Skip to content

Docs: add a production hardening / secure-deployment section #253

Description

@johnzastrow

Summary

The README/deployment docs would benefit from a "Production hardening" section. Deploying actalog behind a reverse proxy recently surfaced several defaults worth documenting so operators land in a secure-by-default state. All items below are deployment/docs guidance — no code changes required.

Suggested additions

1. Bind to loopback and front with a reverse proxy

The example compose uses network_mode: host, and SERVER_HOST defaults to 0.0.0.0, so actalog binds on all interfaces out of the box. Docs should recommend:

  • Set SERVER_HOST=127.0.0.1 and put a reverse proxy (Caddy/nginx/Traefik) in front for TLS + access control, or
  • Use bridge networking and publish the port as 127.0.0.1:8080:8080 rather than 8080:8080.

Either way the app shouldn't be directly reachable on 0.0.0.0 in a typical single-host deployment.

2. Keep secrets out of docker-compose.yml

The sample compose inlines DB_PASSWORD (and friends) as plaintext in the environment: block. Recommend instead:

  • - DB_PASSWORD=${DB_PASSWORD} with the value supplied from a .env file (Compose interpolates it at up time), or an env_file: reference.
  • This keeps the committed/at-rest compose free of credentials.

3. Document .env file permissions

The .env holds JWT_SECRET, DB_PASSWORD, DB_ROOT_PASSWORD, and SMTP credentials. Docs should note chmod 600 .env (owner-only) — the common default of 664 leaves it readable by any local account/process.

4. Stress replacing the JWT_SECRET placeholder

The sample env ships a placeholder (JWT_SECRET=your-...). Docs should call out generating a strong random value (e.g. openssl rand -hex 32) as a required first step — a weak/default signing secret means forgeable auth tokens.

5. Database exposure

actalog connects to the DB over 127.0.0.1, so docs can recommend binding MariaDB/MySQL to bind-address = 127.0.0.1 rather than 0.0.0.0, keeping the DB off the network entirely on single-host setups.

6. Container capability hardening

A short note that actalog runs fine with a reduced Linux capability set. Suggested compose snippet:

    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true

(add back only the specific caps a given base image needs). This limits post-compromise blast radius.

Why

These are all defense-in-depth / least-privilege defaults. Folding them into the deployment docs (ideally with a copy-pasteable hardened docker-compose.yml example) would help self-hosters avoid the common footguns of all-interface binds, plaintext secrets in compose, and world-readable env files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions