Docs/ Operations

Security and production

Before using it officially, go through this page from start to finish. Most incidents come from two things: keys not backed up, or services exposed to the public network.

Two keys §

GPT-Load uses two keys for completely different purposes:

Key Function What happens if lost
AUTH_KEY Log into the management UI Just change one key, data is unaffected
ENCRYPTION_KEY Upstream credentials stored encrypted Credentials that have been encrypted are permanently irrecoverable

Set both keys explicitly in .env, or let the first startup generate auth.key and encryption.key in the data directory.

Does not support master key rotation

This release does not provide a way to replace ENCRYPTION_KEY. If the key is changed or lost, stored channel credentials cannot be decrypted and must be re-entered. In other words, this key should be treated like the database.

Backup §

Back up the database together with its encryption key. Auto-generated auth.key and encryption.key are stored in the data directory; explicitly configured AUTH_KEY and ENCRYPTION_KEY must be backed up separately from their original environment variables or secrets manager.

Stop Compose before backing up

SQLite uses WAL, so do not archive the data volume while the service is running. The actual Compose volume name also changes with the project name and must not be hard-coded as gpt-load-data. Follow the complete procedure in Database and backup.

The backup file itself contains decryptable credentials. Treat it as sensitive data: store it encrypted, and do not put it in a public cloud drive or repository.

See Database and backup before changing database drivers or moving servers.

Network boundary §

The service listens only on 127.0.0.1, so only the local machine can reach it. This is intentional: if the management UI is exposed publicly, anyone with AUTH_KEY can reveal every upstream credential.

Do not open directly for convenience

Changing HOST to 0.0.0.0 and publishing the port directly on a public IP is common and dangerous. The correct approach is via a reverse proxy, with TLS and access control added.

For remote access, choose from lowest to highest risk:

  1. SSH Port Forwarding — Safest; no service configuration changes are required:
Map the remote service to the local machine
ssh -L 3001:127.0.0.1:3001 user@your-server
 # Then open http://127.0.0.1:3001 in the local browser 
  1. Intranet / VPN — Expose the service only inside a controlled network.
  2. Reverse proxy + TLS + access control — Use this only when public access is required; see the next section.

Reverse proxy §

Put Nginx, Caddy, or another reverse proxy in front and do at least three things: Enable HTTPS, restrict sources, do not expose management UI and data plane together.

Nginx Example: restrict origin for management interface
server {
    listen 443 ssl;
    server_name gateway.example.com;

     # Certificate configuration omitted 

     # Management side: only allow trusted sources 
    location /api/ {
        allow 203.0.113.0/24;
        deny all;
        proxy_pass http://127.0.0.1:3001;
    }

     # Data side: open as needed, note that streaming responses should disable buffering 
    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_buffering off;
        proxy_read_timeout 600s;
    }
}

proxy_buffering off and a sufficiently long read timeout are required. If the proxy buffers a streaming response, the client receives no incremental output.

File Permissions §

The managed data directory is restricted to owner-only access automatically at startup:

  • Data directory: 0700 (owner read/write/execute only).
  • Database file and both keys: 0600 (owner read/write only).
  • Using the Current User's Exclusive ACL on Windows

If directory ownership or link type cannot be verified, the program will refuse to start instead of weakening its checks. This prevents credentials from being written to a location with unknown permissions.

Secrets to protect §

  • Two keys — Never commit them, paste them into an issue, or post them in a chat group.
  • Backup files — They contain credentials that can be decrypted.
  • Screenshot — Management UI captures may include account emails and key suffixes; redact them before sharing.
  • AccessKey — It can be revoked, but usage incurred during a leak still costs money.

Report security issues privately through SECURITY.md and do not open public issues.

Production checklist §

Verify every item before sending production traffic:

  • Key — Set AUTH_KEY and ENCRYPTION_KEY explicitly, or verify that their generated values are backed up.
  • Backup — Back up the database with encryption.key and verify that it can be restored.
  • Network — Do not bind the service directly to 0.0.0.0 on the public internet. Use SSH forwarding, a private network, or a TLS reverse proxy.
  • Management UI — Restrict access to /api by source; do not expose it publicly.
  • AccessKey — Issue one per application with appropriate rate and cost limits.
  • Monitoring — Know where to inspect health and request logs; see Monitoring and troubleshooting.
  • Boundary awareness — Understand that cost is estimated and 2.0 targets single-instance deployments.
a single-instance deployment

2.0 guarantees correctness only for a single application instance and does not share state across instances. Do not place a load balancer across replicas: scheduling, cooldown, and rate limiting would be calculated independently. For more scale, create separate deployments by workload.

Security and production - GPT-Load