fix(deploy): lock down postgres — no public port + password via .env

Yesterday's prod incident exposed postgres on 0.0.0.0:5432 with the
default 'postgres:postgres' credentials. A scanner ransomware bot
brute-forced it and dropped the database (left a readme_to_recover
note). We restored from a pre-incident dump and the user data is back,
but the underlying weakness was in this docker-compose.yml.

Changes:
- Remove `ports: "5432:5432"` from the postgres service entirely.
  Postgres is reachable only via the internal docker network. For
  ad-hoc admin access, use an SSH tunnel:
  `ssh -L 5432:localhost:5432 deploy@<host>`
- POSTGRES_PASSWORD now reads from `${POSTGRES_PASSWORD:-postgres}`
  via env interpolation. Prod `.env` (not in repo) provides the real
  value; local dev gets the `postgres` fallback so `docker compose up`
  still works without setup.
- Remove the no-longer-needed DATABASE_URL override in the app service
  `environment:` — `env_file: .env` already supplies it.

After this lands, the deploy pipeline will rsync the new compose.yml,
recreate containers with no exposed pg port, and substitute the strong
password from .env at container start. Volumes persist, data intact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
emil
2026-05-16 02:56:53 +03:00
co-authored by Claude Opus 4.7
parent cce582df6c
commit 79e1dc4144
+3 -4
View File
@@ -9,7 +9,6 @@ services:
- NODE_ENV=production
- HOST=0.0.0.0
- PORT=4321
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/randify
depends_on:
postgres:
condition: service_healthy
@@ -23,11 +22,11 @@ services:
postgres:
image: postgres:16-alpine
ports:
- "5432:5432"
# No public port mapping: Postgres is reachable only via the internal
# docker network. Use an SSH tunnel for ad-hoc admin access.
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=randify
volumes:
- postgres_data:/var/lib/postgresql/data