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.
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, andSERVER_HOSTdefaults to0.0.0.0, so actalog binds on all interfaces out of the box. Docs should recommend:SERVER_HOST=127.0.0.1and put a reverse proxy (Caddy/nginx/Traefik) in front for TLS + access control, or127.0.0.1:8080:8080rather than8080:8080.Either way the app shouldn't be directly reachable on
0.0.0.0in a typical single-host deployment.2. Keep secrets out of
docker-compose.ymlThe sample compose inlines
DB_PASSWORD(and friends) as plaintext in theenvironment:block. Recommend instead:- DB_PASSWORD=${DB_PASSWORD}with the value supplied from a.envfile (Compose interpolates it atuptime), or anenv_file:reference.3. Document
.envfile permissionsThe
.envholdsJWT_SECRET,DB_PASSWORD,DB_ROOT_PASSWORD, and SMTP credentials. Docs should notechmod 600 .env(owner-only) — the common default of664leaves it readable by any local account/process.4. Stress replacing the
JWT_SECRETplaceholderThe 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 tobind-address = 127.0.0.1rather than0.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:
(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.ymlexample) would help self-hosters avoid the common footguns of all-interface binds, plaintext secrets in compose, and world-readable env files.