Switch static server from nginx to static-web-server

Replace nginx:alpine-slim with the scratch-based static-web-server
image, reducing the final image size ~32MB -> ~23MB (28% smaller).

- Dockerfile: serve from static-web-server:2, copy site to /public
- sws.toml: mirror previous nginx behavior (compression, cache-control,
  SPA index fallback) plus security headers and /health endpoint
- Remove now-unused nginx.conf
This commit is contained in:
2026-07-25 01:04:17 +01:00
parent 0d425c0ed1
commit 898e3003a2
3 changed files with 48 additions and 74 deletions
+5 -4
View File
@@ -3,8 +3,9 @@ WORKDIR /tmp/hugo
COPY . . COPY . .
RUN hugo --gc --minify RUN hugo --gc --minify
FROM nginx:alpine-slim FROM ghcr.io/static-web-server/static-web-server:2
WORKDIR /usr/share/nginx/html COPY sws.toml /etc/sws.toml
COPY nginx.conf /etc/nginx/nginx.conf COPY --from=build /tmp/hugo/public /public
COPY --from=build /tmp/hugo/public . ENV SERVER_CONFIG_FILE=/etc/sws.toml
EXPOSE 80/tcp EXPOSE 80/tcp
CMD ["--config-file", "/etc/sws.toml"]
-70
View File
@@ -1,70 +0,0 @@
# auto detects a good number of processes to run
worker_processes auto;
#Provides the configuration file context in which the directives that affect connection processing are specified.
events {
# Sets the maximum number of simultaneous connections that can be opened by a worker process.
worker_connections 1024;
# Tells the worker to accept multiple connections at a time
multi_accept on;
}
http {
# what times to include
include /etc/nginx/mime.types;
# what is the default one
default_type application/octet-stream;
# Sets the path, format, and configuration for a buffered log write
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $upstream_addr '
'"$http_referer" "$http_user_agent"';
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 9;
gzip_buffers 10 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css text/xml text/javascript image/webp image/svg+xml image/x-icon application/javascript application/x-javascript application/json application/xml application/xml+rss;
server {
# listen on port 80
listen 80;
# save logs here
access_log /var/log/nginx/access.log compression;
# where's the root dir
root /usr/share/nginx/html;
# what file to serve as index
index index.html index.htm;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to redirecting to index.html
try_files $uri $uri/ /index.html;
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|webp)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# Javascript and CSS files
location ~* \.(?:css|js)$ {
try_files $uri =404;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# Any route containing a file extension (e.g. /devicesfile.js)
location ~ ^.+\..+$ {
try_files $uri =404;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
[general]
#### Server
# Listen on all interfaces, port 80 (matches previous nginx setup)
host = "0.0.0.0"
port = 80
# Root directory of the static site (Hugo `public/` output)
root = "/public"
# Number of worker threads (0 = auto-detect based on CPU cores)
threads-multiplier = 1
# Log level
log-level = "info"
#### Performance / caching
# On-the-fly gzip, brotli and zstd compression (replaces nginx `gzip on`)
compression = true
# Serve pre-compressed .gz/.br/.zst files from disk when present
compression-static = true
# Emit Cache-Control + ETag headers with sensible per-content-type defaults.
# SWS applies long-lived caching to static assets (images, css, js, fonts)
# and short/no-cache to HTML, replacing the manual nginx `expires 1y` blocks.
cache-control-headers = true
#### Routing
# SPA-style fallback: serve index.html when a path is not found on disk,
# mirroring the previous nginx `try_files $uri $uri/ /index.html`.
page-fallback = "/public/index.html"
#### Security
# Opinionated security headers (safe defaults for a static site)
security-headers = true
# Health endpoint at /health for container/K8s liveness probes
health = true