- base image -> nginxinc/nginx-unprivileged:1.28-alpine, digest-pinned
(BREAKING for the docker path: container port 80 -> 8080; compose
mapping/healthcheck updated in the same change, cap_add dropped)
- nginx add_header inheritance fix: shared snippets file re-included in
every location that sets Cache-Control -- previously ALL security
headers were dropped on real responses (verified live before/after)
- server_tokens off; set_real_ip_from restricted to 127.0.0.1
- expires directives removed (duplicated Cache-Control); gzip_types
text/html redundancy removed (nginx -t warn)
Add Dockerfile (nginx:1.27-alpine), nginx.conf (gzip, cache, CSP and
security headers, no HSTS — left to outer proxy), and docker-compose
service `bchanot-web`. Host port is configurable via PORT env var
(default 8080) and bound to 127.0.0.1 so the container sits behind a
reverse proxy. Container hardened with read_only fs, cap_drop ALL,
no-new-privileges, and tmpfs for nginx runtime dirs. Healthcheck via
wget on /. Also adds .dockerignore and .env.example, and ignores .env.
Usage:
cp .env.example .env
docker compose up -d --build
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>