From fa3d50393e0db14728c12f3435faabc55ae96ed7 Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 22 Feb 2026 14:51:33 +0100 Subject: [PATCH] Add Dockerfile with nginx for static serving - Multi-stage build: node:22-alpine builds, nginx:stable-alpine serves - RFC1918 set_real_ip_from for 10/8, 172.16/12, 192.168/16 - X-Forwarded-For real_ip_header with recursive resolution - Access log to stdout, error log to stderr (Docker best practice) - Immutable cache headers for hashed static assets - SPA fallback via try_files --- .dockerignore | 5 +++++ Dockerfile | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..01b8e10 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +dist +.git +.DS_Store +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..55c66a5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +FROM node:22-alpine AS build +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile +COPY . . +RUN yarn build + +FROM nginx:stable-alpine +# Remove default config +RUN rm /etc/nginx/conf.d/default.conf +# Custom nginx config: real_ip from RFC1918, access_log to stdout +COPY <<'EOF' /etc/nginx/conf.d/netwatch.conf +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Trust RFC1918 reverse proxies for X-Forwarded-For + set_real_ip_from 10.0.0.0/8; + set_real_ip_from 172.16.0.0/12; + set_real_ip_from 192.168.0.0/16; + real_ip_header X-Forwarded-For; + real_ip_recursive on; + + # Access log to stdout (Docker best practice) + access_log /dev/stdout combined; + error_log /dev/stderr warn; + + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets aggressively + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} +EOF + +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80