Self-hosted log retention and access
Set retention and reader permissions for each self-hosted log class, audit receiver, device log and host-administration session record.
Your organization owns log storage, retention and readers. CodeHerder states each log class and the control it offers. Where CodeHerder has no control, you set it in the system that holds the log. For log formats and shipping, see Self-hosted logs.
Log classes
| Log class | What it holds | Data class | Who should read it | Retention control |
|---|---|---|---|---|
Server journald (codeherder.service) |
Application logs. Errors can quote repo URLs and branch names. | customer_code |
Security team and platform operators | None in CodeHerder. Set it in journald and in your log store. |
| API request line (in server journald) | One line for each request: method, path, route, status, duration and request ID. The path can hold workspace and task slugs. It holds no client address. | confidential |
Security team and platform operators | None in CodeHerder. Set it in journald and in your log store. |
| Reverse proxy (Caddy) | One line for each proxied request, plus certificate and error logs. It holds the client address. | personal_data |
Security team and platform operators | None in CodeHerder. Set it in journald and in your log store. |
| Host sign-in and kernel audit | sshd, sudo, PAM and kernel audit records. They hold user names and addresses. |
personal_data |
Security team only | None in CodeHerder. Set it in journald and in your log store. |
| Database logs (PostgreSQL or RDS) | Server, connection and slow-query logs. A slow statement logs its bind values, so the log can hold any column, secrets included. The hosted parameter group logs statements slower than one second. | secret_material |
Database administrators and security team | None in CodeHerder. Set it in PostgreSQL or in your RDS parameter group and CloudWatch log group. |
Instance audit (admin_audit_log, plane = 'instance') |
Operator actions on the instance plane, with the operator’s email and address. | personal_data |
Security team only | None in CodeHerder. A self-hosted server never prunes this table. Set a delete or archive job in PostgreSQL. |
Sign-in audit (auth_audit_log) |
Rejected and accepted credentials, counted for each minute, with the client address. | personal_data |
Security team only | None in CodeHerder. A self-hosted server never prunes this table. Set a delete or archive job in PostgreSQL. |
Workspace events (events) |
The activity record of each workspace. | confidential |
Workspace admins, for their own workspace | CH_EVENTS_MAX_AGE_DAYS. Default 180. 0 disables the prune. CH_EVENTS_METRICS_RETENTION_DAYS covers device metrics events. Default 7. |
Cost events (cost_events) |
AI spend records. | internal |
Workspace admins and finance | CH_COST_EVENTS_MAX_AGE_DAYS. Default 90. 0 disables the prune. CH_COST_RAW_RETENTION_DAYS prunes raw rows after the rollup reconciles. Default 90. 0 disables it. |
| Audit trace export | Trace spans and webhook records sent to your receivers. The exported records hold identifiers only. The local span buffer also holds span attributes and events. | confidential |
Security team | None in CodeHerder. Set it at each receiver. See the audit receivers section of the self-hosted log retention guide. The local span buffer (audit_span_open) keeps spans for CH_OTEL_SPAN_MAX_AGE. Default 48 hours. |
| Webhook delivery records | One row for each outbound and inbound webhook delivery. | confidential |
Workspace admins, for their own workspace | CodeHerder prunes both tables nightly after 30 days (runWebhookDeliveriesRetentionSweeper, runInboundWebhookDeliveriesRetentionSweeper). |
The data class is the strictest data the log may hold. Treat the log with the handling rule of that class. A slow PostgreSQL statement logs its bind values, so the database log can hold secrets. Restrict it the most.
The infrastructure classes have no application control. These are the server journald, API request line, reverse proxy, host sign-in, database logs and audit receivers. The two audit tables have none either.
Recommended rules
This is template rule text. Every value is a proposal. Your organization sets the final values.
- The security team reads infrastructure logs and instance audit records. No other group reads them.
- Workspace admins read the events and cost records of their own workspaces.
- Keep security logs off the host for at least one year. Use storage that the host role cannot delete.
- Keep the workspace events and cost events settings at their defaults, unless a policy needs more.
- Give each log store a named owner. Review the reader list every quarter.
- Delete a log at the end of its retention period. Record the deletion.
Audit receivers
You may run two kinds of audit receiver.
- An OTLP collector. Set
CH_OTEL_TRACES_ENDPOINTto send trace spans. The trace ID is the task UUID. - A webhook receiver. See Webhooks.
The exported records hold identifiers only: UUIDs, event type, timestamps, and workspace (tenant) IDs. They hold no titles, prompts or session text. A webhook in the default metadata_only mode sends the event ID, type, workspace ID, subject type and ID, the acting member ID, and the time. Its payload is null.
You own each receiver. Do these things at each one:
- Set a retention period.
- Restrict readers to the security team.
- Keep
metadata_onlyon every audit webhook. Thefullmode adds event details. If you choose it, apply the same controls to those details. - Separate tenants if your policy needs it. The records carry workspace IDs, so you can filter or route by workspace.
- Alert when a receiver stops accepting records.
Device logs
The people who run a device are responsible for its logs. CodeHerder does not collect them centrally.
A device holds these logs:
~/.codeherder/logs/device-server.log. CodeHerder copies it to one.1file and truncates it when it passesCH_LOCAL_LOG_BUDGET_MB. Default 8.~/.codeherder/launches/<launchID>/. CodeHerder removes this folder after the run ends.- Service-manager copies: the systemd user journal (
journalctl --user -u codeherder-device-server), the launchd file/tmp/codeherder-device-server.log, and Docker container logs. See Running the device server.
CodeHerder caps the size of these logs. It sets no age limit. No central secret scrubber runs on them.
The device operator must do these things:
- Restrict the folder to the device user. For example, run
chmod 700 ~/.codeherder. - Set an age limit. Use journald
MaxRetentionSec, logrotate, or a scheduled delete for the launchd file. For Docker, use--log-opt max-sizeandmax-file. - Do not ship device logs to a shared store without your own scrubber.
- Delete the logs when you retire the device.
Accepted residual risk
A secret that a tool prints can reach a device log in clear text. Access and age settings limit who sees it and for how long. They cannot stop the write. Your organization accepts this risk under the decision that device operators own device logs.
Host administration sessions
Log and retain every host-administration session off the host. Use this rule for whichever channel you pick: SSM, an SSH bastion, or a serial console.
The record must show who connected, when, and what they ran. Send it to storage that the host’s own role cannot delete. Review it on a schedule.
Example: AWS Systems Manager
Set these Session Manager preferences in the SSM-SessionManagerRunShell document:
cloudWatchLogGroupName: a log group with a retention period.cloudWatchEncryptionEnabled:true.cloudWatchStreamingEnabled:true, to stream the session as it runs.s3BucketNameands3EncryptionEnabled:true. Use a bucket in a separate account, with Object Lock or a deny-delete policy.kmsKeyId: a key that encrypts the session data.runAsEnabled: as your policy needs, so sessions run as a named OS user.
CloudTrail records StartSession and SendCommand. Send Run Command output to S3 or CloudWatch. Use OutputS3BucketName and CloudWatchOutputConfig.
Port-forwarding and SSH-over-SSM sessions log no keystrokes. Log the SSH server on the host as well.
Your emergency host access path needs the same logging.
Related guides
- Self-hosted logs — log formats and how to ship them off the host
- Self-hosted deployment — download, verify, run and upgrade the server
- Webhooks — receive a signed JSON payload for chosen events
- Running the device server — run the device server as a service
- Replacing a compromised self-hosted server — isolate a suspect host and plan emergency host access
Last updated