diff --git a/packages/overview/11-hostnames.md b/packages/overview/11-hostnames.md index a300a0a..1824254 100644 --- a/packages/overview/11-hostnames.md +++ b/packages/overview/11-hostnames.md @@ -23,7 +23,7 @@ Loopback on that box is `127.0.0.1`. Do **not** publish NATS `:4222`. ## Service → hostname (NS1 all-in-one) -Suggested public names are under `zapier.georgelambert.org`. They are **not** in Caddy yet except the docs site. Until they are, use `NS1.GEORGELAMBERT.ORG:` (or SSH tunnel for loopback). +HTTPS names under `*.zapier.georgelambert.org` are live in Caddy on NS1 (wildcard DNS already pointed here). Loopback services stay off the public internet. | Service | Port | Bind now | Machine hostname | Suggested service hostname | Public? | |---------|------|----------|------------------|----------------------------|---------| diff --git a/packages/verae-access-staff/src/iam-gate.js b/packages/verae-access-staff/src/iam-gate.js index e443b55..f9ea401 100644 --- a/packages/verae-access-staff/src/iam-gate.js +++ b/packages/verae-access-staff/src/iam-gate.js @@ -26,7 +26,9 @@ export async function denyOrRedirect(req, res, json, { permission, html }) { if (out.ok) return out; const login = iamBase() || (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3028').replace(/\/$/, ''); if (html) { - res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); + const proto = String(req.headers['x-forwarded-proto'] || 'http').split(',')[0].trim(); + const host = String(req.headers['x-forwarded-host'] || req.headers.host || '127.0.0.1').split(',')[0].trim(); + res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent(`${proto}://${host}/`)}` }); res.end(); return false; } diff --git a/packages/verae-bootstrap/types/ns1-all-in-one/start.sh b/packages/verae-bootstrap/types/ns1-all-in-one/start.sh index 4b6c738..75d7e8b 100755 --- a/packages/verae-bootstrap/types/ns1-all-in-one/start.sh +++ b/packages/verae-bootstrap/types/ns1-all-in-one/start.sh @@ -4,7 +4,8 @@ set -euo pipefail STACK="${VERAE_STACK:-$HOME/verae-stack}" FLEET="$STACK/packages/verae-fleet" EDGE_PORT="${EDGE_PORT:-13000}" -export STAFF_IAM_URL="${STAFF_IAM_URL:-http://127.0.0.1:3028}" +export STAFF_IAM_URL="${STAFF_IAM_URL:-https://iam.zapier.georgelambert.org}" +export STAFF_COOKIE_DOMAIN="${STAFF_COOKIE_DOMAIN:-.zapier.georgelambert.org}" export NATS_URL="${NATS_URL:-nats://127.0.0.1:4222}" export FLEET_ENABLE_LAN134="${FLEET_ENABLE_LAN134:-}" test -d "$FLEET" || { echo "missing $FLEET" >&2; exit 1; } @@ -45,17 +46,21 @@ for name in ( "accounting-export", "access-staff", "access-web", + "staff-iam", + "staff-session", + "zappier-edge", ): p = root / "services" / f"{name}.json" if not p.exists(): continue spec = json.loads(p.read_text()) env = spec.setdefault("env", {}) - if "ZAPPIER_ADMIN_URL" in env or name != "access-web": + if "ZAPPIER_ADMIN_URL" in env: env["ZAPPIER_ADMIN_URL"] = admin if name == "access-web": env["ZAPPIER_EDGE_URL"] = admin - env["STAFF_IAM_URL"] = "http://127.0.0.1:3028" + env["STAFF_IAM_URL"] = "https://iam.zapier.georgelambert.org" + env["STAFF_COOKIE_DOMAIN"] = ".zapier.georgelambert.org" env["STAFF_AUTH"] = "1" p.write_text(json.dumps(spec, indent=2) + "\n") print("overlay applied edge", edge_port) @@ -66,7 +71,7 @@ if curl -sf http://127.0.0.1:3850/health >/dev/null; then echo "fleet already up" exit 0 fi -nohup env STAFF_IAM_URL="$STAFF_IAM_URL" NATS_URL="$NATS_URL" node src/cli.js serve \ +nohup env STAFF_IAM_URL="$STAFF_IAM_URL" STAFF_COOKIE_DOMAIN="$STAFF_COOKIE_DOMAIN" NATS_URL="$NATS_URL" node src/cli.js serve \ >/tmp/verae-fleet-serve.out 2>&1 & echo "fleet pid $!" for i in $(seq 1 40); do diff --git a/packages/verae-fleet/src/iam-gate.js b/packages/verae-fleet/src/iam-gate.js index e443b55..f9ea401 100644 --- a/packages/verae-fleet/src/iam-gate.js +++ b/packages/verae-fleet/src/iam-gate.js @@ -26,7 +26,9 @@ export async function denyOrRedirect(req, res, json, { permission, html }) { if (out.ok) return out; const login = iamBase() || (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3028').replace(/\/$/, ''); if (html) { - res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); + const proto = String(req.headers['x-forwarded-proto'] || 'http').split(',')[0].trim(); + const host = String(req.headers['x-forwarded-host'] || req.headers.host || '127.0.0.1').split(',')[0].trim(); + res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent(`${proto}://${host}/`)}` }); res.end(); return false; } diff --git a/packages/verae-ops/05-dedicated-hardware.md b/packages/verae-ops/05-dedicated-hardware.md index 322ce1a..88489fc 100644 --- a/packages/verae-ops/05-dedicated-hardware.md +++ b/packages/verae-ops/05-dedicated-hardware.md @@ -8,7 +8,7 @@ NS1-style: a box that already runs NATS on **127.0.0.1:4222** (never a public bi 2. `nats-server -js` listening **127.0.0.1:4222** only (cluster later on a private NIC). 3. Clone `zappier-edge`, `verae-middleware`, `verae-fleet`. 4. systemd units (below) or `verae-fleet serve` which keepFloor-spawns workers. -5. Caddy/nginx for public HTTPS to **access-web `:3021/portal/`** and **access-zapier `:3024`**. zappier-edge stays loopback (`:3000`, or `:13000` on NS1 if `:3000` is already taken). +5. Caddy file `caddy/zapier-services.georgelambert.org.caddy` on NS1: `portal`/`zap`/`api`/staff/fleet hostnames → local ports. zappier-edge stays loopback (`:3000`, or `:13000` on NS1 if `:3000` is already taken). 6. Operator console: `0.0.0.0:3850`. `verae-keep` (`:3860`) + `watch` (`:3861`) + `guard.sh` keep workers up unless you paused/stopped them in the console. 7. Clone/install: [verae-bootstrap](https://git.georgelambert.org/marchon/verae-bootstrap) type `ns1-all-in-one`. diff --git a/packages/verae-ops/caddy/zapier-services.georgelambert.org.caddy b/packages/verae-ops/caddy/zapier-services.georgelambert.org.caddy new file mode 100644 index 0000000..778f8fa --- /dev/null +++ b/packages/verae-ops/caddy/zapier-services.georgelambert.org.caddy @@ -0,0 +1,87 @@ +# Verae Time × Zapier HTTP doors on NS1. +# DNS: wildcard *.zapier.georgelambert.org → 70.88.205.138 +# Do not proxy NATS :4222, keep, archive workers, or loopback edge :13000. + +(zapier_headers) { + header { + X-Content-Type-Options nosniff + Referrer-Policy strict-origin-when-cross-origin + } + encode gzip zstd +} + +http://portal.zapier.georgelambert.org, +http://api.zapier.georgelambert.org, +http://leaf.zapier.georgelambert.org, +http://zap.zapier.georgelambert.org, +http://staff.zapier.georgelambert.org, +http://iam.zapier.georgelambert.org, +http://login.zapier.georgelambert.org, +http://cs.zapier.georgelambert.org, +http://sales.zapier.georgelambert.org, +http://acct.zapier.georgelambert.org, +http://mw.zapier.georgelambert.org, +http://fleet.zapier.georgelambert.org { + redir https://{host}{uri} permanent +} + +portal.zapier.georgelambert.org { + import zapier_headers + redir / /portal/ 302 + reverse_proxy 127.0.0.1:3021 +} + +api.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3022 +} + +leaf.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3023 +} + +zap.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3024 +} + +staff.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3025 +} + +iam.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3028 +} + +login.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3027 +} + +cs.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3011 +} + +sales.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3012 +} + +acct.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3013 +} + +mw.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3100 +} + +fleet.zapier.georgelambert.org { + import zapier_headers + reverse_proxy 127.0.0.1:3850 +} diff --git a/packages/zapier-decisions/LOG.md b/packages/zapier-decisions/LOG.md index f652134..a7385e9 100644 --- a/packages/zapier-decisions/LOG.md +++ b/packages/zapier-decisions/LOG.md @@ -32,6 +32,11 @@ - Disable lan-134 unless `FLEET_ENABLE_LAN134=1`. - SSH spawn timeout 8s; failed hosts skipped. +## 2026-09-11 — Caddy host names live + +- Installed `/etc/caddy/sites/zapier-services.georgelambert.org.caddy` on NS1. HTTPS: portal, api, leaf, zap, staff, iam, login, cs, sales, acct, mw, fleet. +- Not proxied: NATS, keep, workers, loopback edge. + ## 2026-09-11 — host names - Mapped every running service to **NS1.GEORGELAMBERT.ORG** (`70.88.205.138`). diff --git a/packages/zappier-accounting-export/src/iam-gate.js b/packages/zappier-accounting-export/src/iam-gate.js index e443b55..f9ea401 100644 --- a/packages/zappier-accounting-export/src/iam-gate.js +++ b/packages/zappier-accounting-export/src/iam-gate.js @@ -26,7 +26,9 @@ export async function denyOrRedirect(req, res, json, { permission, html }) { if (out.ok) return out; const login = iamBase() || (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3028').replace(/\/$/, ''); if (html) { - res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); + const proto = String(req.headers['x-forwarded-proto'] || 'http').split(',')[0].trim(); + const host = String(req.headers['x-forwarded-host'] || req.headers.host || '127.0.0.1').split(',')[0].trim(); + res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent(`${proto}://${host}/`)}` }); res.end(); return false; } diff --git a/packages/zappier-customer-service/src/iam-gate.js b/packages/zappier-customer-service/src/iam-gate.js index e443b55..f9ea401 100644 --- a/packages/zappier-customer-service/src/iam-gate.js +++ b/packages/zappier-customer-service/src/iam-gate.js @@ -26,7 +26,9 @@ export async function denyOrRedirect(req, res, json, { permission, html }) { if (out.ok) return out; const login = iamBase() || (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3028').replace(/\/$/, ''); if (html) { - res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); + const proto = String(req.headers['x-forwarded-proto'] || 'http').split(',')[0].trim(); + const host = String(req.headers['x-forwarded-host'] || req.headers.host || '127.0.0.1').split(',')[0].trim(); + res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent(`${proto}://${host}/`)}` }); res.end(); return false; } diff --git a/packages/zappier-sales-pricing/src/iam-gate.js b/packages/zappier-sales-pricing/src/iam-gate.js index e443b55..f9ea401 100644 --- a/packages/zappier-sales-pricing/src/iam-gate.js +++ b/packages/zappier-sales-pricing/src/iam-gate.js @@ -26,7 +26,9 @@ export async function denyOrRedirect(req, res, json, { permission, html }) { if (out.ok) return out; const login = iamBase() || (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3028').replace(/\/$/, ''); if (html) { - res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); + const proto = String(req.headers['x-forwarded-proto'] || 'http').split(',')[0].trim(); + const host = String(req.headers['x-forwarded-host'] || req.headers.host || '127.0.0.1').split(',')[0].trim(); + res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent(`${proto}://${host}/`)}` }); res.end(); return false; }