docker-single-port-multi-instance
Skill1 starsChanged 44 days agoMITView on GitHub
Consolidate multiple Docker Compose app instances (production / test / demo) behind ONE host port using an nginx reverse proxy that routes by URL path prefix (e.g. /demo). Use when a user wants 'one port, several apps/banks' or a demo reachable simultaneously from the main landing page with its own database.
- Reads credentials
In this repository125 other files it gives its agents.
- AGENTS.mdAGENTS.md
- skill-authoringSkill
- apple-notesSkill
- apple-remindersSkill
- findmySkill
- imessageSkill
- agy-customizationsSkill
- antigravity-guideSkill
- awesome-skills-masterSkill
- claude-codeSkill
- codexSkill
- computer-useSkill
- context-modeSkill
- dogfoodSkill
- hermes-agentSkill
- opencodeSkill
- rag-local-lancedbSkill
- skills-sh-registrySkill
- watermarks-removerSkill
- yuanbaoSkill
- libretranslate-markdown-i18nSkill
- mt-markup-preserving-translationSkill
- architecture-diagramSkill
- ascii-artSkill
- ascii-videoSkill
- baoyu-infographicSkill
- claude-designSkill
- comfyuiSkill
- design-mdSkill
- excalidrawSkill
- humanizerSkill
- manim-videoSkill
- p5jsSkill
- popular-web-designsSkill
- portfolio-github-pagesSkill
- pretextSkill
- sketchSkill
- songwriting-and-ai-musicSkill
- touchdesigner-mcpSkill
- jupyter-live-kernelSkill
- suap-iff-apiSkill
- desktop-themingSkill
- hermes-desktop-pluginsSkill
- hybrid-desktop-server-opsSkill
- himalayaSkill
- codebase-inspectionSkill
- git-conventional-commitsSkill
- github-authSkill
- github-code-reviewSkill
- github-issue-pr-attribsSkill
- github-issuesSkill
- github-profile-readmeSkill
- github-pr-workflowSkill
- github-repo-managementSkill
- github-starred-kbSkill
- hermes-installed-catalogSkill
- readme-templateSkill
- cv-latex-multilingualSkill
- latex-cv-maintenanceSkill
- gif-searchSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 3 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 18
When the ONLY goal is routing separate instances, do NOT refactor the app to hold two DB connections (e.g.
- Distinctive: line 23
Keep each instance as its own container (own DB, own env).
- Distinctive: line 24
Put ONE nginx container on the public port.
- Very specific: line 34
If the demo is served under /demo/* but its client JS calls /api/...
- Very specific: line 74
Verify with curl -s -D - -o /dev/null URL/demo | grep -i location — it must show Location: /demo/app (NO :5000), never …
- Very specific: line 76
If you see :5000, the config did not take: rebuild the nginx image and docker compose up -d --force-recreate nginx (a plain up may not …
- Very specific: line 82
Only nginx publishes the host port.
- Very specific: line 88
After you docker compose build app app-demo (or up -d app app-demo) to push a code change, the demo can suddenly break even though the app …
- Very specific: line 109
If restart alone doesn't take, rebuild + recreate the image: docker compose build nginx && docker compose up -d --force-recreate nginx.
- Very specific: line 111
Do NOT reach for docker compose down -v — that wipes named volumes (e.g.
- Very specific: line 123
Call the demo API WITH that cookie: curl -o /dev/null -w '%{http_code}' --cookie "$CK" URL/demo/api/dashboard → expect 200.
- Very specific: line 127
If a /demo/* PAGE returns 302 /login, run the stale-routing diagnostic above BEFORE suspecting app code — 9 times out of 10 it's the nginx …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
One port, many instances: nginx reverse proxy by path prefix
When this applies
- You have an app that runs as several instances: production, test, and a public demo — each with its OWN database.
- The user asks for a single published port (e.g. 4460) where the demo is reached by clicking a button on the landing page, and the demo's data lives in its own DB, isolated from prod/test.
- Key constraint: the demo must be reachable SIMULTANEOUSLY with the main app.
Prefer nginx-by-prefix over in-app multi-tenancy
When the ONLY goal is routing separate instances, do NOT refactor the app to hold two DB connections (e.g. a second mongoose connection) just to serve /demo/* from the same process. That touches ~30 files (every model + service + controller) and risks regressing the normal routes. Instead:
- Keep each instance as its own container (own DB, own env).
- Put ONE nginx container on the public port; it routes:
/demo/*→app-demo(strip prefix:proxy_pass http://app-demo:5000/;)/(rest) →app(the principal: test or prod chosen via .env)
- The demo container keeps its existing autologin; the button on the landing
just points to
/demo/app.
This delivers "one port, demo with own DB, simultaneous" with near-zero risk to the main app's logic.
The non-obvious gotcha: APIs must also be prefixed
If the demo is served under /demo/* but its client JS calls /api/...
(absolute), the proxy sends those calls to the PRINCIPAL instance, not the
demo → tokens fail (401 "Token invalido"). You must route the demo's APIs to
the demo instance too:
- Mount the demo's API router under
/demo/apiin the app (only when a DEMO_AUTOLOGIN-style flag is set), in addition to the normal/api. - Make the frontend prefix API calls with
/demowhen running in the demo. Inject the prefix WITHOUT an inline script (CSP will block it — see the express-csp-runtime-config skill): usedata-api-prefix="/demo"on<html>and read it withgetAttributeinside the shared fetch wrapper.
nginx location block:
location = /demo { return 302 /demo/app; }
location /demo/ { proxy_pass http://app-demo:5000/; }
location / { proxy_pass http://app:5000; }CRITICAL: make the /demo redirect relative (absolute_redirect off)
The snippet above is subtly broken in production. When nginx listens on the
INTERNAL port (e.g. 5000, mapped to 4460 on the host) and you return 302
/demo/app, nginx builds an ABSOLUTE Location: http://host:5000/demo/app
using the listen port — not the port the browser used (4460). The user's
browser is then thrown at a port that does not exist outside the host, and
/demo appears dead even though /demo/app works directly.
Fix: disable absolute redirects in the server block so the Location
stays relative (/demo/app) and the browser resolves it against the real
port:
server {
listen 5000;
absolute_redirect off; # keep Location relative -> /demo/app
port_in_redirect off; # belt-and-suspenders, drop the port entirely
location = /demo { return 302 /demo/app; }
location /demo/ { proxy_pass http://app-demo:5000/; }
location / { proxy_pass http://app:5000; }
}Verify with curl -s -D - -o /dev/null URL/demo | grep -i location — it must
show Location: /demo/app (NO :5000), never http://host:5000/demo/app.
If you see :5000, the config did not take: rebuild the nginx image and
docker compose up -d --force-recreate nginx (a plain up may not replace it).
docker-compose shape
- One file, project name preserved (so named volumes survive, e.g.
fa_mongo_data). - Services:
app,app-demo,mongo,mongo-demo(tmpfs for demo),nginx. - Only
nginxpublishes the host port.appandapp-demohave NO host port (internal network only). - Demo DB on tmpfs so it resets on restart; seed manually via
docker compose exec app-demo node scripts/seed-demo.js.
Pitfall: nginx serves STALE routing after a sibling container rebuild
After you docker compose build app app-demo (or up -d app app-demo) to push
a code change, the demo can suddenly break even though the app code is correct:
/demo/veiculos (and any /demo/* page) returns 302 -> /login, and the demo
API /demo/api/* returns 401. The container app-demo is healthy and answers
200 when hit DIRECTLY on its internal IP:port, but via the published port it
fails. Root cause: the nginx container never re-read its default.conf — it
kept the in-memory routing from before the rebuild and is sending /demo/* to
the PRINCIPAL instance (which has no demo autologin → 302 /login).
Tell-tale sign (this is the key diagnostic): hit /demo/veiculos through the
published port, then check BOTH app logs. If neither app nor app-demo
logged the request but nginx returned a 302 with the app's CSP headers, the
request never reached an app — nginx generated the redirect itself from a stale
location/return. (Add a one-line console.log('[mw]', req.path) at the top
of the demo autologin middleware to confirm whether the demo instance even saw
the request; remove it after.)
Fix (cheapest first):
docker compose restart nginx— forces nginx to re-readdefault.conf. Re-test/demo/veiculos→ should now be200and the autologin middleware should logpath= / host= <published-host>.- If restart alone doesn't take, rebuild + recreate the image:
docker compose build nginx && docker compose up -d --force-recreate nginx. Do NOT reach fordocker compose down -v— that wipes named volumes (e.g.fa_mongo_data); the HANDOFF explicitly forbids it.
Why this happens: up -d app app-demo recreates those services but leaves the
long-running nginx container untouched, and nginx does not hot-reload its config
on a sibling's restart. A plain restart re-reads the (already-correct, baked-into
the-image) conf.
Verify server-side (don't trust a caching browser)
The inspection browser may keep stale HTML/JS across navigations and report phantom 401s even after a correct rebuild. Validate at the HTTP layer instead:
- Capture the autologin Set-Cookie:
CK=$(curl -s -i URL/demo/app | grep -i set-cookie | ...). - Call the demo API WITH that cookie:
curl -o /dev/null -w '%{http_code}' --cookie "$CK" URL/demo/api/dashboard→ expect 200. The same cookie against/api/dashboard(no prefix) → 401 (hits principal). That pair proves routing + auth are correct. - If a
/demo/*PAGE returns 302 /login, run the stale-routing diagnostic above BEFORE suspecting app code — 9 times out of 10 it's the nginx conf not being reloaded.
Reference
See references/nginx-demo-example.md for a concrete financas-app docker-compose.yml + nginx/default.conf + app.js mount snippet.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

