mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-09-03 07:24:52 +08:00
Moves demo.nginxui.com off a VPS and onto a Worker-fronted container
that sleeps when idle.
The Worker never awaits the boot. It checks container state and, when
not ready, starts it in the background and immediately returns a
self-contained loading page at the requested URL — 200, no redirect, so
deep links survive and no redirect loop is possible. API and WebSocket
requests get 503 with Retry-After instead of HTML they cannot parse. The
page is fully inline because nothing under /assets is reachable while
the container that serves it is still starting.
Disk is ephemeral, so a scheduled stop IS the restore; a daily cron
handles the case where nobody idled it out. SIGTERM rather than a kill,
because nginx-ui holds an open SQLite handle.
The image needed rebuilding around four platform constraints, each found
by reproducing them locally rather than reading docs:
1. s6-overlay cannot run. Its preinit chowns /run and its suexec calls
setgid; neither CAP_CHOWN nor CAP_SETGID is granted, and s6 exits
111 before anything starts. Replaced with a plain entrypoint.
2. A `USER` directive prevents scheduling entirely — the instance sits
'inactive' and never gets a location. Runs as root instead.
3. Root is not all-powerful there. With capabilities dropped there is
no CAP_DAC_OVERRIDE, so root obeys file permissions; chowning paths
to `nginx` locked root out of its own filesystem.
4. /run is a fresh tmpfs at runtime, so directories created at build
time are gone and nginx-ui cannot bind its handover socket. The
entrypoint creates them on start.
Cluster peers run as extra nginx-ui processes in the same container on
loopback rather than as separate containers. Node traffic then never
crosses the Worker boundary, never counts as an in-flight request
holding the container awake, and needs no outbound interception.
Also drops NGINX_UI_OFFICIAL_DOCKER: it enabled a Docker socket
self-check that can only fail here, logged OTA cleanup errors on every
boot, and defaulted RestartCmd to `nginx -s stop` — which assumes the s6
supervisor this image no longer has, so restarting nginx from the UI
would have killed the container. The entrypoint supervises nginx
instead.
/__demo/bootlog keeps nginx serving the startup log even when nginx-ui
is down; it is how constraint 4 was found, and without container stdout
it is the only window in. /__demo/recycle forces a fresh container after
a config change that only applies at start.
Image: 509 MB -> 425 MB (105 MB compressed, which is what Cloudflare
distributes), mostly from building with -trimpath -ldflags "-s -w",
which the release workflow already did and this path did not.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
50 lines
1.3 KiB
JSON
50 lines
1.3 KiB
JSON
{
|
|
// Local-only override: builds the container from this working tree instead
|
|
// of pulling the published image, so `wrangler dev` exercises unreleased
|
|
// changes. Not used by `wrangler deploy`.
|
|
//
|
|
// demo.Dockerfile expects a prebuilt linux/amd64 binary at
|
|
// nginx-ui-linux-amd64/nginx-ui in the build context; produce it with:
|
|
//
|
|
// docker run --rm --platform linux/amd64 -v "$PWD":/src -w /src \
|
|
// -e GOWORK=off -e CGO_ENABLED=1 -e GOOS=linux -e GOARCH=amd64 \
|
|
// golang:1.26-trixie go build -o /src/nginx-ui-linux-amd64/nginx-ui main.go
|
|
//
|
|
// bunx wrangler dev -c wrangler.dev.jsonc
|
|
"$schema": "./node_modules/wrangler/config-schema.json",
|
|
"name": "nginx-ui-demo-dev",
|
|
"main": "src/index.ts",
|
|
"compatibility_date": "2026-07-01",
|
|
"compatibility_flags": ["nodejs_compat"],
|
|
|
|
"containers": [
|
|
{
|
|
"class_name": "NginxUiDemo",
|
|
"image": "../demo.Dockerfile",
|
|
"image_build_context": "..",
|
|
"image_vars": {
|
|
"TARGETOS": "linux",
|
|
"TARGETARCH": "amd64"
|
|
},
|
|
"instance_type": "basic",
|
|
"max_instances": 1
|
|
}
|
|
],
|
|
|
|
"durable_objects": {
|
|
"bindings": [
|
|
{
|
|
"name": "NGINX_UI_DEMO",
|
|
"class_name": "NginxUiDemo"
|
|
}
|
|
]
|
|
},
|
|
|
|
"migrations": [
|
|
{
|
|
"tag": "v1",
|
|
"new_sqlite_classes": ["NginxUiDemo"]
|
|
}
|
|
]
|
|
}
|