Changelog - 2026-10-25
The preset image compresses, answers /health and sends security headers
New Feature Enhancement Behavior Change SecurityIn one line. The image of an app made from the ARDOR preset now gzips text, answers /health from nginx alone, sends safe security headers on every response, and leaves out the /api proxy when API_UPSTREAM is empty, for an app served behind a gateway. Available in 0.4.2.
What changed
- Compression. nginx gzips plain text, JavaScript, CSS, JSON, XML, web manifests and SVG. Images and fonts are left alone.
/health.GET /healthanswers200 okfrom nginx, never cached, without calling the backend. Point a load balancer or an orchestrator probe at it.- Security headers. Every response, errors included, carries
X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-originandX-Frame-Options: SAMEORIGIN. AContent-Security-Policyis a commented example only: the right one depends on what your app loads.SAMEORIGINlets the app frame itself; to allow another site, remove the header and setframe-ancestorsin your Content-Security-Policy. /apionly when asked for. The proxy is written at container start, and only whenAPI_UPSTREAMis set and not empty. The default is stillhttp://api:3000, so nothing changes until you empty it (ENV API_UPSTREAM=in the Dockerfile, or-e API_UPSTREAM=). A value that is not an address, such as one with a space, a;or a quote, stops the container and the message never prints the value.- The cache rules are unchanged.
config.jsisno-store,/assets/isimmutablefor a year, every other route isno-cachewith theindex.htmlfallback.
Who is affected
- A new app. Nothing to do: the files are generated.
- An app already generated from the preset. No action is needed to keep running as it is. To get the new behavior, copy the files below.
- An app served behind a gateway. Empty
API_UPSTREAMafter copying, and the image has no/api; a request to/api/...then reaches the app'sindex.html, not a backend.
Copy the new files into an existing app
The preset is published inside @venizia/ardor at dist/presets/app/files/.configs/builders/. In the files you copy, replace the tokens and (the app name and its folder) the way the existing Dockerfile has them.
Replace
nginx.conf.templatewith the new one.Add the folder
nginx-snippets/(security-headers.confandapi-proxy.conf).Add
docker-entrypoint.d/45-api-proxy.sh, next to40-runtime-config.sh.In the Dockerfile, add these lines in the
productionstage, beside the existingCOPYlines:dockerfileCOPY --from=builder /home/bun/app/<appPath>/.configs/builders/nginx-snippets /etc/nginx/snippets COPY --from=builder --chmod=0755 /home/bun/app/<appPath>/.configs/builders/docker-entrypoint.d/45-api-proxy.sh /docker-entrypoint.d/45-api-proxy.shRebuild the image.
WARNING
Copy all of it. The new template includes /etc/nginx/snippets/security-headers.conf, so a template copied without step 2 and the Dockerfile lines makes nginx refuse to start. The 0755 matters: the base image skips a script that is not executable, and then /api is never written.
If you changed your template, keep your changes and add four things to it: the gzip lines, location = /health, the line include /etc/nginx/snippets/security-headers.conf; in the server and again in every location that sets add_header (nginx passes add_header down from the server only into a location that sets none of its own), and include /etc/nginx/conf.d/*.locations; in place of your location /api/ block (which now lives in nginx-snippets/api-proxy.conf).