diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3a88f48 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +# Keep the build context minimal; only the site assets and nginx config +# referenced by the Dockerfile are needed. +.git +.gitea +.github +.idea +.vscode +*.md +renovate.json +.renovaterc* +Dockerfile +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7525657 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +# Lightweight, non-root nginx serving the static site. +# Runs as user "nginx" and listens on 8080, ready to sit behind an +# external reverse proxy that terminates TLS and forwards requests. +FROM nginxinc/nginx-unprivileged:1.27-alpine-slim + +COPY default.conf /etc/nginx/conf.d/default.conf +COPY --chown=nginx:nginx index.html styles.css script.js messages.js /usr/share/nginx/html/ + +EXPOSE 8080 diff --git a/default.conf b/default.conf new file mode 100644 index 0000000..449930a --- /dev/null +++ b/default.conf @@ -0,0 +1,42 @@ +# Static file serving for "Why is the DLR shut today?". +# Intended to run behind an external reverse proxy (e.g. NGINX) which +# handles TLS, host routing and any X-Forwarded-* headers. + +server { + listen 8080; + listen [::]:8080; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_vary on; + gzip_types text/css application/javascript; + + location / { + try_files $uri $uri/ =404; + } + + # HTML should always be revalidated so deploys are picked up promptly. + location = /index.html { + add_header Cache-Control "no-cache"; + } + + # The message list is edited frequently; do not cache it. + location = /messages.js { + add_header Cache-Control "no-cache"; + } + + # Other static assets may be cached for a short period. + location ~* \.(?:css|js)$ { + add_header Cache-Control "public, max-age=3600"; + } + + # Health endpoint for the proxy / orchestrator. + location = /healthz { + access_log off; + default_type text/plain; + return 200 "ok\n"; + } +}