${escapeHtml(user.displayName)}${isSelf ? ' You' : ""}
${escapeHtml(user.username)}
From 5417d5eeedeeaf2634d3926b4a49497cd356a0d2 Mon Sep 17 00:00:00 2001
From: marvin
-
+
Why Site Gateway · @@ -42,7 +42,7 @@ It's intentionally narrower than a general-purpose proxy manager. You describe * - **Automatic HTTPS** — Caddy issues and renews public certificates; internal, HTTP-only, and uploaded custom-certificate modes are also supported. - **Live dashboard** — gateway/HTTP/HTTPS/storage health, hosted and proxy counts, certificate status, throughput, uptime, memory, disk, and version info at a glance. - **Access Lists** — reusable login/network policies combining accounts, groups, and IP/CIDR rules across any host. -- **Two-factor authentication** — TOTP-based MFA for administrator and user accounts, with recovery codes. +- **Two-factor authentication** — TOTP-based MFA for administrator and user accounts, with recovery codes, plus an administrator-side override to disable a locked-out user's 2FA when they've lost their authenticator and used up their recovery codes. - **Users, groups, and roles** — Administrator and Standard User roles, with account lifecycle controls. - **Backups** — configuration or complete `.sgbackup` archives, downloadable, importable, schedulable, and optionally AES-256-GCM encrypted. - **Certificates page** — issuer, expiration, days remaining, and renewal health for every managed and uploaded certificate. diff --git a/ROADMAP.md b/ROADMAP.md index b758ed5..3ab84ad 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ ## Current release status -`v0.11.112` is a stable, day-to-day release. The product has moved well past the original alpha creation flow described in earlier versions of this document — Hosted Sites, Proxy Hosts, Redirect Hosts, and Streaming Hosts are all implemented, along with authentication, access control, certificates, backups, and full dashboard reporting. This document reflects what's actually shipped and what's genuinely still ahead. +`v0.11.118` is a stable, day-to-day release. The product has moved well past the original alpha creation flow described in earlier versions of this document — Hosted Sites, Proxy Hosts, Redirect Hosts, and Streaming Hosts are all implemented, along with authentication, access control, certificates, backups, and full dashboard reporting. This document reflects what's actually shipped and what's genuinely still ahead. ## Product direction @@ -23,7 +23,7 @@ Site Gateway stays simpler than a general-purpose proxy manager: one dashboard, - Local users with Administrator and Standard User roles, account lifecycle controls (disable/archive/restore). - Groups, used to grant Access List membership without managing users one by one. - Access Lists combining accounts, groups, and IP/CIDR network rules behind a themed sign-in page. -- Optional two-factor authentication (TOTP) with a self-service My Account view for enrolling and managing it. +- Optional two-factor authentication (TOTP) with a self-service My Account view for enrolling and managing it, plus an administrator-side override (Administration → Users → “•••” → Disable 2FA) for a user who's locked out with no recovery codes left. Logged to the Audit log. - First-time setup flow that finalizes the persistent administrator account from bootstrap credentials. ### Certificates and TLS @@ -36,7 +36,7 @@ Site Gateway stays simpler than a general-purpose proxy manager: one dashboard, - Live dashboard health for the gateway, HTTP, HTTPS, and storage, plus hosted/proxy/certificate counts and throughput. - System panel: uptime, memory, persistent-data size, disk space, installed app/Caddy versions, public IP. -- Performance view with request throughput, response times, and per-route breakdowns. +- Performance view with request throughput, response times, and per-route breakdowns — the host filter applies to the throughput table as well as the trend chart, average response times display in seconds once they pass 1000ms, and per-domain error counts open a themed breakdown by status code. - Rotating access and activity logs. - Update-available banner when a newer image is deployed. - A redacted support-report export exists (version, config health, certificate readiness, upstream checks, recent events) but its UI entry point is currently hidden pending a readability rewrite of the report's output format. @@ -51,7 +51,8 @@ Site Gateway stays simpler than a general-purpose proxy manager: one dashboard, - Current icon and wordmark (v0.11.99) used consistently across the login screen, sidebar, themed default pages, and this README. - A sitewide design-token system (colors, spacing, radius, and type scale defined once and reused everywhere) underpins the interface, so new UI stays visually consistent by default. -- Integrated, searchable in-app documentation covering every configurable field, including 2FA and the update-notification banner. +- Integrated, searchable in-app documentation covering every configurable field, including 2FA (self-service and the administrator override) and the update-notification banner. +- Toast notifications are color-coded — error toasts render distinctly from success/neutral ones, using the same token-driven theming as the rest of the interface. - Companion marketing site with an installation guide covering Docker Compose, plain `docker run`, and Unraid. ## What's next diff --git a/package.json b/package.json index dffb4fd..dcffb4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "site-gateway", - "version": "0.11.117", + "version": "0.11.118", "private": true, "description": "Site Gateway: simple self-hosted website publishing, reverse proxying, and automatic HTTPS.", "type": "module", diff --git a/src/public/app.js b/src/public/app.js index 5819c73..f8f09a1 100644 --- a/src/public/app.js +++ b/src/public/app.js @@ -359,7 +359,7 @@ function renderUsers() { const roleLabel = user.role === "administrator" ? "Administrator" : user.role === "viewer" ? "Viewer" : "Standard User"; const lifecycle = user.status === "archived" ? `` : ``; const statusToggle = user.status === "archived" ? "" : ``; - const menu = `
${escapeHtml(user.username)}
No users found.
'; document.querySelectorAll("#user-list .user-card").forEach(card => { card.style.position = "relative"; card.style.minHeight = "250px"; card.style.paddingBottom = "64px"; const head = card.querySelector(".user-card-head"), status = head?.querySelector(".status-pill"), footer = card.querySelector(".card-footer"); if (!head || !footer) return; if (status) footer.prepend(status); }); @@ -656,6 +656,13 @@ $("#user-list").addEventListener("click", async event => { closeMenus(); state.passwordTarget = user.id; $("#password-form").reset(); $("#password-error").textContent = ""; $("#password-title").textContent = `Reset ${user.username} password`; $("#password-dialog").showModal(); return; } + if (button.dataset.userAction === "mfa-disable") { + closeMenus(); + if (!await themedUserConfirm(`Disable two-factor authentication for “${user.username}”? They’ll be able to sign in with just their password until they set it up again.`, "Disable 2FA")) return; + button.disabled = true; + try { await api(`/api/users/${user.id}/mfa/disable`, { method: "POST" }); await loadFeatureView(); toast("Two-factor authentication disabled."); } catch (error) { toast(error.message, "error"); } finally { button.disabled = false; } + return; + } if (button.dataset.userAction === "delete") { closeMenus(); if (!await themedUserConfirm(`Permanently delete user “${user.username}”? This cannot be undone.`, "Delete user")) return; diff --git a/src/public/index.html b/src/public/index.html index 005b14c..fe2325b 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -306,7 +306,7 @@Site Gateway manual
A complete reference for the Dashboard, Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, Certificates, Access Lists, My Account & two-factor authentication, Administration, Performance monitoring, and every advanced control between them. Start with an area’s overview, then use its field reference when you need to know what one specific setting does.
Introduction
Reverse proxies often expose powerful settings without explaining what they change. Site Gateway provides a visual, Caddy-powered control plane for static sites, proxy routes, redirects, raw TCP/UDP streams, HTTPS, health checks, access control, and recovery — covering everything from a single ZIP upload to a full homelab of proxied applications.
Each area below has an overview article (what it’s for and how to configure the common case) followed by a field reference article covering every advanced control, one at a time. Use the sidebar to jump straight to a section, or search for any field name, error message, or setting — search matches headings, body text, and field names together.
Create one route, test it locally, then add a domain and TLS. Keep defaults until you have a reason to change them.
Configuration is stored in SQLite under /data and every generated Caddy configuration is validated before reload — if validation fails, the previous working configuration stays active and the failure is explained in Gateway Events.
Getting started
Install the container with persistent /data storage, open the management port (8080 by default), and complete the administrator setup screen shown on first launch. Before publishing public domains, confirm DNS already points to this server and that ports 80 and 443 are free for Site Gateway to use.
index.html) and want Site Gateway to serve them directly.Publish a ZIP on a direct port first so you can confirm it works over LAN, then add www.example.com once DNS and port forwarding are ready and Automatic HTTPS can issue a certificate.
Dashboard
The Dashboard is a glance-and-go summary — every number and status on it links back to a full section elsewhere, so you never have to act on the Dashboard itself.
Counts of Hosted Sites, Proxy Hosts, and Certificates needing attention, plus a Throughput chip showing live requests in the last minute across every configured domain — click it to open the full Performance tab.
Container and version facts, plus a Public IP tile showing your gateway's current public address, rechecked automatically every 60 minutes — prep work for future Dynamic DNS support. This is a status fact, not a job you configure.
Background jobs shown as status tiles — proxy health checks, backups, log pruning, certificate/domain readiness checks, and the Public IP check — each showing its schedule and last result.
Lists anything that needs a decision (a failing health check, an expiring certificate). Clicking an item jumps straight to it. When nothing needs attention, the panel collapses to a single all-clear banner instead of an empty list.
The last several configuration and operational events, with relative timestamps (“4 hours ago”). This is a shortcut, not a separate log — the same events are searchable in full under Logs → Gateway Events.
Hosted Sites
A Hosted Site serves files you upload directly — no separate application or container required. Use it for a static site, a single-page app build, documentation, or anything that’s just HTML/CSS/JS.
9000–9099) and not already be used by another site.index.html (a single top-level folder inside the ZIP is automatically flattened), or upload a bare index.html file directly. Up to 250 MB.Use Replace files from the card’s menu to upload a new ZIP or HTML file without recreating the site or losing its domain/TLS/health settings. Use Domain & TLS to change the domain, TLS mode, or any advanced setting below.
Files are served immediately on the chosen port and, once configured, through the domain as well.
Hosted Sites
Expand Advanced options on the create or edit form for these controls:
Name: value pair per line, up to 30 each. Request headers are added before Caddy processes the request; response headers are added to what visitors receive.includeSubDomains to the HSTS header; only takes effect when HSTS itself is on and TLS isn’t HTTP only.import/persist_config directives are rejected outright, since those could affect every other route on the gateway.Hosted Sites can be health-checked the same way Proxy Hosts are: a Health-check path (default /), method (GET or HEAD), expected status (a code, list, or range such as 200, 200,204, or 200-499), a timeout in seconds (1–60, default 4), up to 3 retries, and a Monitor this site toggle. Turning monitoring off shows the card as “Monitoring paused” instead of running a periodic check.
Proxy Hosts
A Proxy Host puts a domain and HTTPS in front of something already running elsewhere — another container, a LAN device, or a remote service.
http://192.168.1.20:8123. Use the container name, LAN address, or application URL — no path or query string beyond a trailing slash.http(s):// targets, one per line, up to 10. When present, Caddy distributes requests across every healthy target instead of using the single Forward-to address alone, and the Advanced options’ Load balancing setting controls how.For Jellyfin at 192.168.1.20:8096, use domain jellyfin.example.com and forward target http://192.168.1.20:8096. Site Gateway checks the upstream continuously and Caddy manages an eligible public HTTPS certificate automatically.
Proxy Hosts
Most applications only need a domain, Forward-to target, and TLS choice. These controls are for applications with unusual paths, authentication needs, response codes, headers, or performance requirements.
/; GET or HEAD).200, 200,204, or 200-399.../ or ..\); direct requests for /etc/passwd; WordPress probing (/wp-login.php, /wp-admin/, /xmlrpc.php); exposed config/VCS paths (/.env, /.git/, /.aws/); exposed PHPUnit test endpoints (/vendor/phpunit, /phpunit/); the literal strings eval( and base64_decode(; a SQL UNION SELECT sequence; and <script. Matching is case-insensitive. Important: this only inspects the URL path — it does not inspect the query string, request body, cookies, or headers, so a SQL-injection or XSS payload sent as a query parameter (e.g. ?id=1 UNION SELECT...) is not caught by this toggle. This is a small, fixed, path-only ruleset, not a full web application firewall — it will not catch every attack, cannot currently be extended with custom patterns, and should not replace keeping the upstream application itself patched./api/* | http://192.168.1.20:3001 | strip or preserve — strip removes the matched prefix before forwarding, preserve keeps it. Up to 20 entries.Name: value-per-line format as Hosted Sites.https:// — the field is disabled otherwise.http(s):// targets, one per line, up to 10 — the same field described in the Overview, now editable here too on an existing Proxy Host, not just when first creating it. Once Upstream pool has any entries, Caddy uses only those targets — the single Forward-to address above is not automatically added to the pool alongside them, so include it as one of the pool lines too if it should keep receiving traffic.Save one setting at a time, watch the card’s upstream status line, check Access Logs, and compare against a direct request to the application. If Caddy rejects a custom configuration, Site Gateway keeps the last known-good configuration active and shows the rejection reason.
Proxy Hosts
Choosing Custom uploaded certificate as the TLS mode reveals two file fields: Certificate PEM and Private key PEM. Both are required together — Site Gateway verifies the private key’s public key actually matches the certificate before accepting the pair, and confirms the certificate’s Subject Alternative Names cover every domain configured on that Proxy Host. A certificate that doesn’t cover every alias is rejected rather than silently applied to only some of them.
Accepted files are stored under /data/certificates/custom and included in complete backups. Replacing a custom certificate later works the same way — upload both files again through the same field.
Redirect Hosts
A Redirect Host sends visitors from one domain straight to another, with no files hosted and no application behind it.
http:// or https:// URL to send visitors to.302 Temporary (default), 301 Permanent, 307 Temporary — preserve method, 308 Permanent — preserve method.old.example.com/library?id=2 becomes new.example.com/library?id=2 instead of always landing on the destination’s root.Use 301 or 308 only when the move is meant to be permanent — browsers and search engines cache these aggressively. Use 302 or 307 while you’re still testing the new destination.
Streaming Hosts
A Streaming Host forwards a raw TCP or UDP port straight to another host and port — there’s no domain, no HTTPS, and no HTTP layer involved at all, unlike every other route type in Site Gateway. Use it for services that speak their own protocol directly over a port: SSH, a Minecraft or other game server, a VPN endpoint, or any similar TCP/UDP service.
Streaming Hosts listen for connections from inside the Site Gateway container itself — they are not routed through Caddy the way domains are. That means the incoming port must already be published on the container (added to your docker-compose.yaml or Unraid port mappings, with the container recreated) before you create the matching Streaming Host in the UI, or nothing outside the container will ever reach it.
To forward SSH (22) and a Minecraft server (25565):
ports:
- "22:22/tcp"
- "25565:25565/tcp"
host:port address, e.g. 192.168.1.20:25565. No http:// — this is a raw socket forward, not a web address.Streaming Hosts
TCP is a full one-to-one relay: every inbound connection gets its own fresh outbound connection to the forward target, and the two are piped together in both directions. Closing or erroring either side tears down the other.
UDP is connectionless, so Site Gateway multiplexes many remote clients over one listening port by tracking a short-lived “session” per unique client address, each with its own outbound socket to the forward target. An idle session is cleaned up automatically after about a minute of inactivity.
The monitor always performs a plain TCP reachability check against the forward address, with a 4-second timeout — this confirms the target host and port are reachable, not that the specific game or service protocol is fully healthy. Disabling monitoring shows the card as “Monitoring paused” rather than unreachable.
2222, forward to 192.168.1.30:22, TCP only.25565, forward to 192.168.1.20:25565, TCP (and UDP if the specific server/mod needs it — vanilla Minecraft is TCP-only).Changing the port, target, or protocol checkboxes restarts the listener immediately to apply the change; toggling Enable/Disable does the same.
Certificates
For Automatic HTTPS to succeed, a domain must resolve to your public address, inbound ports 80 and 443 must reach Site Gateway, and no other service (including another reverse proxy) can already own those ports on this host.
Forces an immediate re-check of every certificate, domain readiness result, and health probe instead of waiting for the periodic background check.
Confirm DNS, forward ports 80 and 443, stop any competing proxy, then run Check now. Don’t troubleshoot an upstream application until the domain and HTTPS checks themselves are healthy.
See Certificates → Field reference for what Renewing-soon warning, Critical warning, and Stale health data actually control.
Certificates
Expanding a certificate’s details shows: status, valid-from date, issuer, every domain it covers, serial number, SHA-256 fingerprint, and when it was last detected — deliberately excluding private key material.
Set from Administration → Security & Health:
A status of mismatch means a custom certificate was uploaded for that route but its coverage doesn’t include every configured domain — upload a replacement covering all of them.
Access Lists
An Access List restricts who can reach a Hosted Site, Proxy Host, or Redirect Host, by network address, by login, or both. Assign a saved list from that route’s Advanced options.
private_ranges per line. When set, every network not listed is denied — this is an allow-list, not a suggestion.At least one rule — a network rule, a denied-network rule, or a login — is required before the list can be saved.
Use a route’s Advanced options to assign an Access List to it, or use the Access List’s own View assigned hosts menu action to see everywhere it’s currently in use. An Access List can’t be deleted while anything still references it — unassign it from every host first.
Users & Groups
Every account has a role:
._-, must be unique.An administrator can change a user’s role from the card’s role dropdown, reset their password, archive them (a reversible soft-disable distinct from deleting), or delete them outright. Delete and Change icon live under the card’s “•••” menu, matching Hosted Sites and Proxy Hosts; role, password reset, and archive stay as visible buttons. You cannot disable, archive, delete, or change the role of your own account — another administrator has to do that — and Site Gateway always keeps at least one active Administrator, refusing any action that would leave zero. Resetting a user’s password here does not disable their two-factor authentication if they have it enabled — see My Account for how 2FA works. There is currently no administrator-side way to turn off another user’s 2FA; only that user can, from their own My Account page.
A Group is simply a named set of users. Its only purpose is authentication: assign a Group to an Access List so its members can log in with their own Site Gateway credentials instead of a separate Access-List-only login.
Every Group has its own enable/disable toggle, separate from deleting it. Disabling a Group immediately stops it from granting access through any Access List it’s assigned to — the assignment itself is untouched and still shows as assigned, but its members can no longer authenticate through it until the Group is re-enabled. This is a common surprise: disabling a Group is not the same as archiving it for later cleanup, it has an immediate access-control effect. If the Group is currently assigned to at least one enabled Access List, disabling it now asks for confirmation first, naming exactly which Access List(s) will stop authenticating that Group’s members — the same pattern already used when disabling an Access List that protects active hosts.
Administration includes an Audit log — a searchable, filterable, immutable record of who did what, filterable by outcome (success/failed) and free-text search across the user, action, and target. Audit entries can’t be edited or deleted.
My Account
My Account is available to every role — Administrator, Standard User, and Viewer alike — and only ever affects your own account. It sits in the sidebar next to Administration and Documentation.
Shows your display name, username, and role. These are read-only here; an administrator changes them from Administration → Users.
Enter your current password once, then your new password twice. This works for every role — previously, only an administrator could change a user’s password (Administration → Users → Reset password), which meant every routine password change had to go through an admin. My Account closes that gap for everyone’s own account.
Optional and off by default for every account. When enabled, signing in requires your password plus a 6-digit code from an authenticator app (or a recovery code), using the standard TOTP algorithm (RFC 6238) — any authenticator app works, not a Site Gateway-specific one.
After your username and password are accepted, you’re prompted for a code. Enter the current 6-digit code from your authenticator app, or one of your unused recovery codes if you don’t have the app available. A wrong code shows an inline error without sending you back to the username/password screen.
Both require re-entering your current password as confirmation. Regenerating recovery codes immediately invalidates the previous set.
An administrator resetting your password does not disable your 2FA — you’ll still need your authenticator app or a recovery code at your next sign-in. Only you can turn off your own 2FA, from My Account.
Administration
Controls what happens when a visitor reaches Site Gateway on HTTP using a hostname that isn’t configured. (Unknown HTTPS hostnames are always rejected outright, regardless of this setting, since serving anything else would need a certificate Site Gateway doesn’t have — and issuing a misleading one would be worse.)
The themed page’s heading and explanation text are also editable here, independent of which mode is active. It displays the Site Gateway icon and wordmark, matching the branding used throughout the rest of the app.
A preview pane updates as you type, showing the page a visitor would actually see — the same rendering the gateway serves, not an approximation. It only shows something for the modes that actually serve a page (Themed route-not-found page, Gateway ready page, and Custom HTML); for No response and Redirect elsewhere, the pane explains why there’s nothing to preview — those modes close the connection or send the visitor elsewhere before any page is ever shown. Scripts do not execute in the preview even when Custom HTML contains them, since the preview runs in a sandboxed frame — this only affects the preview, not what a real visitor’s browser does with your saved Custom HTML.
Administration
A Configuration only backup contains a consistent SQLite snapshot of every route, user, group, Access List, and setting, plus a portable JSON export of the same data. A Complete backup adds uploaded Hosted Site files, icons, the default-site page, and certificates (both managed and custom).
BACKUP_PASSWORD environment value — enable this only after that value is actually configured, or scheduled runs will fail.The optional backup password field on this page is used only for manually created backups and for restoring an encrypted archive — it is never stored by Site Gateway. A manually created backup is saved to /data/backups and appears in the list below; it does not download automatically — use that entry’s Download button when you want a local copy.
.sgbackup archive (importing just stages the file — restoring is a separate, explicit action).Site Gateway verifies every file’s checksum and automatically creates a safety backup of the current state before restoring anything. If the restored configuration turns out to be invalid, it automatically rolls back to that safety backup rather than leaving the gateway in a broken state.
Site Gateway validates every generated Caddy configuration before reload and keeps the previous working configuration active if validation fails. Container updates are installed by pulling a new pinned image — create a backup first.
Administration
Set how many days of Access, Activity, Audit, Certificate, and Security records to keep (7–3650 days each) and whether automatic pruning is enabled. Prune Now shows exactly how many records in each category are eligible before you confirm, and Download Logs exports them.
Administration
Two separate, deliberately distinct destructive actions — kept apart so a routine preference correction is never confused with a full rebuild. Both require re-entering your own administrator username and password, typing an exact confirmation phrase, and then confirming a second themed dialog by typing YES.
Confirmation phrase: RESTORE DEFAULT. Resets Gateway Defaults, backup schedule settings, and certificate-health thresholds back to their starting values. It does not remove any hosts, uploaded files, users, groups, Access Lists, certificates, logs, or backups.
Confirmation phrase: FACTORY RESET. Deletes everything under /data — every host of every kind, uploaded files, certificates (managed and custom), logs, backups, icons, users, and settings. Docker-mounted files outside /data are untouched. The container returns to the initial setup screen without needing a manual restart. Because backups themselves live under /data/backups, they’re deleted too — recovery is only possible from a backup taken beforehand and stored elsewhere (downloaded, or on separately mounted storage).
If you want to undo a recent change while keeping the rest of the installation intact, restore a backup — Factory Reset is not a rollback tool.
Logs
Every request Caddy handles, with domain, path, response status, latency, and upstream outcome. Filter by host or by status-code range (2xx/3xx/4xx/5xx). Sensitive query-string values — tokens, secrets, passwords, session identifiers, API keys, credentials — are redacted before they’re ever stored, regardless of filter settings.
Configuration and operational changes, filterable by severity (Normal/Warnings/Errors) and by category (certificate, health, authentication, backup, configuration, or system).
Filter Access Logs for a 502, then compare the target address against a direct LAN request to the same upstream to isolate whether the problem is the gateway or the application itself.
Performance
Built entirely from the same request data already collected for Access Logs — no new logging or extra overhead, just a different view of it.
Domain narrows the Trend chart to one host (default: all domains combined). Range sets the Trend window — Last hour, 3, 6 (default), 12, or 24 hours, or 3 or 7 days.
Request volume over the selected range, bucketed into 15-minute (up to 24h) or hourly (3–7 days) points.
One row per domain that has received traffic, sorted by 24-hour volume:
Common Interface Controls
The same card language is used throughout Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, Access Lists, Groups, and Users, so learning one area transfers directly to the next.
Contains actions that change or inspect a card: Edit opens the full form, kind-specific extras appear where relevant (Replace files on Hosted Sites, View assigned hosts on Access Lists), and Delete removes the record after a confirmation.
A slide switch, separate from the menu, turns a route or account on or off without deleting its saved configuration — useful during maintenance or testing when you expect to reuse the exact same settings shortly after.
Administrators can manage everything. Standard Users can manage Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, and Access Lists, but not Users, Groups, Settings, or Backups. Viewers can inspect information but cannot create, edit, disable, assign, or delete anything — their menus and toggles are hidden entirely. This is enforced on the server independently of what the interface shows, so hiding a button is a convenience, not the actual security boundary.
While signed in, Site Gateway checks every 60 seconds whether a newer version has been deployed. If so, a small banner appears with Refresh and Dismiss — Refresh reloads the page to pick up the new version; Dismiss hides the banner, but it reappears on the next check if you’re still on the old version. This only matters for a tab left open across a deploy; closing and reopening the tab, or signing in fresh, always loads the current version automatically.
Icons
Every Hosted Site, Proxy Host, Redirect Host, Streaming Host, Access List, Group, and User can have its own icon. Open the picker from a card’s icon tile or its “Change icon” menu action.
Jellyfin, Plex) to search a large built-in icon catalog and pick a match./data/icons. Uploaded SVGs are checked for embedded scripts or external references before being accepted.https:// image link instead of uploading a file.If a custom icon URL ever stops loading, the card automatically falls back to showing initials instead of a broken image.
Troubleshooting
Confirm public DNS actually points to this server, that router/firewall forwarding reaches ports 80 and 443, and that NGINX Proxy Manager or another reverse proxy isn’t still holding those ports. Then check Certificates and Logs → Gateway Events for the specific rejection reason. Site Gateway cannot request a public certificate while another gateway is receiving the ACME challenge on its behalf.
Check the error shown on save — it names the specific problem (duplicate address, invalid upstream, malformed custom configuration, certificate/TLS issue) rather than a generic failure, and the previous working configuration stays active while you fix it.
This is almost always the port not being published on the container yet — see Streaming Hosts → Overview for the docker-compose/Unraid port mapping requirement.
If they still have an unused recovery code, they can sign in with it in place of the 6-digit code. If not, there is currently no administrator-side way to disable another user’s 2FA — only the affected user can turn it off, from My Account, which itself requires signing in first. Keep this in mind before encouraging 2FA adoption broadly.
No guide matched that search.
Site Gateway manual
A complete reference for the Dashboard, Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, Certificates, Access Lists, My Account & two-factor authentication, Administration, Performance monitoring, and every advanced control between them. Start with an area’s overview, then use its field reference when you need to know what one specific setting does.
Introduction
Reverse proxies often expose powerful settings without explaining what they change. Site Gateway provides a visual, Caddy-powered control plane for static sites, proxy routes, redirects, raw TCP/UDP streams, HTTPS, health checks, access control, and recovery — covering everything from a single ZIP upload to a full homelab of proxied applications.
Each area below has an overview article (what it’s for and how to configure the common case) followed by a field reference article covering every advanced control, one at a time. Use the sidebar to jump straight to a section, or search for any field name, error message, or setting — search matches headings, body text, and field names together.
Create one route, test it locally, then add a domain and TLS. Keep defaults until you have a reason to change them.
Configuration is stored in SQLite under /data and every generated Caddy configuration is validated before reload — if validation fails, the previous working configuration stays active and the failure is explained in Gateway Events.
Getting started
Install the container with persistent /data storage, open the management port (8080 by default), and complete the administrator setup screen shown on first launch. Before publishing public domains, confirm DNS already points to this server and that ports 80 and 443 are free for Site Gateway to use.
index.html) and want Site Gateway to serve them directly.Publish a ZIP on a direct port first so you can confirm it works over LAN, then add www.example.com once DNS and port forwarding are ready and Automatic HTTPS can issue a certificate.
Dashboard
The Dashboard is a glance-and-go summary — every number and status on it links back to a full section elsewhere, so you never have to act on the Dashboard itself.
Counts of Hosted Sites, Proxy Hosts, and Certificates needing attention, plus a Throughput chip showing live requests in the last minute across every configured domain — click it to open the full Performance tab.
Container and version facts, plus a Public IP tile showing your gateway's current public address, rechecked automatically every 60 minutes — prep work for future Dynamic DNS support. This is a status fact, not a job you configure.
Background jobs shown as status tiles — proxy health checks, backups, log pruning, certificate/domain readiness checks, and the Public IP check — each showing its schedule and last result.
Lists anything that needs a decision (a failing health check, an expiring certificate). Clicking an item jumps straight to it. When nothing needs attention, the panel collapses to a single all-clear banner instead of an empty list.
The last several configuration and operational events, with relative timestamps (“4 hours ago”). This is a shortcut, not a separate log — the same events are searchable in full under Logs → Gateway Events.
Hosted Sites
A Hosted Site serves files you upload directly — no separate application or container required. Use it for a static site, a single-page app build, documentation, or anything that’s just HTML/CSS/JS.
9000–9099) and not already be used by another site.index.html (a single top-level folder inside the ZIP is automatically flattened), or upload a bare index.html file directly. Up to 250 MB.Use Replace files from the card’s menu to upload a new ZIP or HTML file without recreating the site or losing its domain/TLS/health settings. Use Domain & TLS to change the domain, TLS mode, or any advanced setting below.
Files are served immediately on the chosen port and, once configured, through the domain as well.
Hosted Sites
Expand Advanced options on the create or edit form for these controls:
Name: value pair per line, up to 30 each. Request headers are added before Caddy processes the request; response headers are added to what visitors receive.includeSubDomains to the HSTS header; only takes effect when HSTS itself is on and TLS isn’t HTTP only.import/persist_config directives are rejected outright, since those could affect every other route on the gateway.Hosted Sites can be health-checked the same way Proxy Hosts are: a Health-check path (default /), method (GET or HEAD), expected status (a code, list, or range such as 200, 200,204, or 200-499), a timeout in seconds (1–60, default 4), up to 3 retries, and a Monitor this site toggle. Turning monitoring off shows the card as “Monitoring paused” instead of running a periodic check.
Proxy Hosts
A Proxy Host puts a domain and HTTPS in front of something already running elsewhere — another container, a LAN device, or a remote service.
http://192.168.1.20:8123. Use the container name, LAN address, or application URL — no path or query string beyond a trailing slash.http(s):// targets, one per line, up to 10. When present, Caddy distributes requests across every healthy target instead of using the single Forward-to address alone, and the Advanced options’ Load balancing setting controls how.For Jellyfin at 192.168.1.20:8096, use domain jellyfin.example.com and forward target http://192.168.1.20:8096. Site Gateway checks the upstream continuously and Caddy manages an eligible public HTTPS certificate automatically.
Proxy Hosts
Most applications only need a domain, Forward-to target, and TLS choice. These controls are for applications with unusual paths, authentication needs, response codes, headers, or performance requirements.
/; GET or HEAD).200, 200,204, or 200-399.../ or ..\); direct requests for /etc/passwd; WordPress probing (/wp-login.php, /wp-admin/, /xmlrpc.php); exposed config/VCS paths (/.env, /.git/, /.aws/); exposed PHPUnit test endpoints (/vendor/phpunit, /phpunit/); the literal strings eval( and base64_decode(; a SQL UNION SELECT sequence; and <script. Matching is case-insensitive. Important: this only inspects the URL path — it does not inspect the query string, request body, cookies, or headers, so a SQL-injection or XSS payload sent as a query parameter (e.g. ?id=1 UNION SELECT...) is not caught by this toggle. This is a small, fixed, path-only ruleset, not a full web application firewall — it will not catch every attack, cannot currently be extended with custom patterns, and should not replace keeping the upstream application itself patched./api/* | http://192.168.1.20:3001 | strip or preserve — strip removes the matched prefix before forwarding, preserve keeps it. Up to 20 entries.Name: value-per-line format as Hosted Sites.https:// — the field is disabled otherwise.http(s):// targets, one per line, up to 10 — the same field described in the Overview, now editable here too on an existing Proxy Host, not just when first creating it. Once Upstream pool has any entries, Caddy uses only those targets — the single Forward-to address above is not automatically added to the pool alongside them, so include it as one of the pool lines too if it should keep receiving traffic.Save one setting at a time, watch the card’s upstream status line, check Access Logs, and compare against a direct request to the application. If Caddy rejects a custom configuration, Site Gateway keeps the last known-good configuration active and shows the rejection reason.
Proxy Hosts
Choosing Custom uploaded certificate as the TLS mode reveals two file fields: Certificate PEM and Private key PEM. Both are required together — Site Gateway verifies the private key’s public key actually matches the certificate before accepting the pair, and confirms the certificate’s Subject Alternative Names cover every domain configured on that Proxy Host. A certificate that doesn’t cover every alias is rejected rather than silently applied to only some of them.
Accepted files are stored under /data/certificates/custom and included in complete backups. Replacing a custom certificate later works the same way — upload both files again through the same field.
Redirect Hosts
A Redirect Host sends visitors from one domain straight to another, with no files hosted and no application behind it.
http:// or https:// URL to send visitors to.302 Temporary (default), 301 Permanent, 307 Temporary — preserve method, 308 Permanent — preserve method.old.example.com/library?id=2 becomes new.example.com/library?id=2 instead of always landing on the destination’s root.Use 301 or 308 only when the move is meant to be permanent — browsers and search engines cache these aggressively. Use 302 or 307 while you’re still testing the new destination.
Streaming Hosts
A Streaming Host forwards a raw TCP or UDP port straight to another host and port — there’s no domain, no HTTPS, and no HTTP layer involved at all, unlike every other route type in Site Gateway. Use it for services that speak their own protocol directly over a port: SSH, a Minecraft or other game server, a VPN endpoint, or any similar TCP/UDP service.
Streaming Hosts listen for connections from inside the Site Gateway container itself — they are not routed through Caddy the way domains are. That means the incoming port must already be published on the container (added to your docker-compose.yaml or Unraid port mappings, with the container recreated) before you create the matching Streaming Host in the UI, or nothing outside the container will ever reach it.
To forward SSH (22) and a Minecraft server (25565):
ports:
- "22:22/tcp"
- "25565:25565/tcp"
host:port address, e.g. 192.168.1.20:25565. No http:// — this is a raw socket forward, not a web address.Streaming Hosts
TCP is a full one-to-one relay: every inbound connection gets its own fresh outbound connection to the forward target, and the two are piped together in both directions. Closing or erroring either side tears down the other.
UDP is connectionless, so Site Gateway multiplexes many remote clients over one listening port by tracking a short-lived “session” per unique client address, each with its own outbound socket to the forward target. An idle session is cleaned up automatically after about a minute of inactivity.
The monitor always performs a plain TCP reachability check against the forward address, with a 4-second timeout — this confirms the target host and port are reachable, not that the specific game or service protocol is fully healthy. Disabling monitoring shows the card as “Monitoring paused” rather than unreachable.
2222, forward to 192.168.1.30:22, TCP only.25565, forward to 192.168.1.20:25565, TCP (and UDP if the specific server/mod needs it — vanilla Minecraft is TCP-only).Changing the port, target, or protocol checkboxes restarts the listener immediately to apply the change; toggling Enable/Disable does the same.
Certificates
For Automatic HTTPS to succeed, a domain must resolve to your public address, inbound ports 80 and 443 must reach Site Gateway, and no other service (including another reverse proxy) can already own those ports on this host.
Forces an immediate re-check of every certificate, domain readiness result, and health probe instead of waiting for the periodic background check.
Confirm DNS, forward ports 80 and 443, stop any competing proxy, then run Check now. Don’t troubleshoot an upstream application until the domain and HTTPS checks themselves are healthy.
See Certificates → Field reference for what Renewing-soon warning, Critical warning, and Stale health data actually control.
Certificates
Expanding a certificate’s details shows: status, valid-from date, issuer, every domain it covers, serial number, SHA-256 fingerprint, and when it was last detected — deliberately excluding private key material.
Set from Administration → Security & Health:
A status of mismatch means a custom certificate was uploaded for that route but its coverage doesn’t include every configured domain — upload a replacement covering all of them.
Access Lists
An Access List restricts who can reach a Hosted Site, Proxy Host, or Redirect Host, by network address, by login, or both. Assign a saved list from that route’s Advanced options.
private_ranges per line. When set, every network not listed is denied — this is an allow-list, not a suggestion.At least one rule — a network rule, a denied-network rule, or a login — is required before the list can be saved.
Use a route’s Advanced options to assign an Access List to it, or use the Access List’s own View assigned hosts menu action to see everywhere it’s currently in use. An Access List can’t be deleted while anything still references it — unassign it from every host first.
Users & Groups
Every account has a role:
._-, must be unique.An administrator can change a user’s role from the card’s role dropdown, reset their password, archive them (a reversible soft-disable distinct from deleting), or delete them outright. Delete and Change icon live under the card’s “•••” menu, matching Hosted Sites and Proxy Hosts; role, password reset, and archive stay as visible buttons. You cannot disable, archive, delete, or change the role of your own account — another administrator has to do that — and Site Gateway always keeps at least one active Administrator, refusing any action that would leave zero. Resetting a user’s password here does not disable their two-factor authentication if they have it enabled — see My Account for how 2FA works. If a user is locked out of their own 2FA (lost authenticator, no recovery codes left), an administrator can disable it for them from the card’s “•••” menu — Disable 2FA appears there only when that user currently has 2FA enabled. This clears their authenticator, secret, and any unused recovery codes; they can set 2FA up again afterward if they choose to. The action is logged to the Audit log, since it removes a security control from someone else’s account.
A Group is simply a named set of users. Its only purpose is authentication: assign a Group to an Access List so its members can log in with their own Site Gateway credentials instead of a separate Access-List-only login.
Every Group has its own enable/disable toggle, separate from deleting it. Disabling a Group immediately stops it from granting access through any Access List it’s assigned to — the assignment itself is untouched and still shows as assigned, but its members can no longer authenticate through it until the Group is re-enabled. This is a common surprise: disabling a Group is not the same as archiving it for later cleanup, it has an immediate access-control effect. If the Group is currently assigned to at least one enabled Access List, disabling it now asks for confirmation first, naming exactly which Access List(s) will stop authenticating that Group’s members — the same pattern already used when disabling an Access List that protects active hosts.
Administration includes an Audit log — a searchable, filterable, immutable record of who did what, filterable by outcome (success/failed) and free-text search across the user, action, and target. Audit entries can’t be edited or deleted.
My Account
My Account is available to every role — Administrator, Standard User, and Viewer alike — and only ever affects your own account. It sits in the sidebar next to Administration and Documentation.
Shows your display name, username, and role. These are read-only here; an administrator changes them from Administration → Users.
Enter your current password once, then your new password twice. This works for every role — previously, only an administrator could change a user’s password (Administration → Users → Reset password), which meant every routine password change had to go through an admin. My Account closes that gap for everyone’s own account.
Optional and off by default for every account. When enabled, signing in requires your password plus a 6-digit code from an authenticator app (or a recovery code), using the standard TOTP algorithm (RFC 6238) — any authenticator app works, not a Site Gateway-specific one.
After your username and password are accepted, you’re prompted for a code. Enter the current 6-digit code from your authenticator app, or one of your unused recovery codes if you don’t have the app available. A wrong code shows an inline error without sending you back to the username/password screen.
Both require re-entering your current password as confirmation. Regenerating recovery codes immediately invalidates the previous set.
An administrator resetting your password does not disable your 2FA — you’ll still need your authenticator app or a recovery code at your next sign-in. Only you can turn off your own 2FA, from My Account.
Administration
Controls what happens when a visitor reaches Site Gateway on HTTP using a hostname that isn’t configured. (Unknown HTTPS hostnames are always rejected outright, regardless of this setting, since serving anything else would need a certificate Site Gateway doesn’t have — and issuing a misleading one would be worse.)
The themed page’s heading and explanation text are also editable here, independent of which mode is active. It displays the Site Gateway icon and wordmark, matching the branding used throughout the rest of the app.
A preview pane updates as you type, showing the page a visitor would actually see — the same rendering the gateway serves, not an approximation. It only shows something for the modes that actually serve a page (Themed route-not-found page, Gateway ready page, and Custom HTML); for No response and Redirect elsewhere, the pane explains why there’s nothing to preview — those modes close the connection or send the visitor elsewhere before any page is ever shown. Scripts do not execute in the preview even when Custom HTML contains them, since the preview runs in a sandboxed frame — this only affects the preview, not what a real visitor’s browser does with your saved Custom HTML.
Administration
A Configuration only backup contains a consistent SQLite snapshot of every route, user, group, Access List, and setting, plus a portable JSON export of the same data. A Complete backup adds uploaded Hosted Site files, icons, the default-site page, and certificates (both managed and custom).
BACKUP_PASSWORD environment value — enable this only after that value is actually configured, or scheduled runs will fail.The optional backup password field on this page is used only for manually created backups and for restoring an encrypted archive — it is never stored by Site Gateway. A manually created backup is saved to /data/backups and appears in the list below; it does not download automatically — use that entry’s Download button when you want a local copy.
.sgbackup archive (importing just stages the file — restoring is a separate, explicit action).Site Gateway verifies every file’s checksum and automatically creates a safety backup of the current state before restoring anything. If the restored configuration turns out to be invalid, it automatically rolls back to that safety backup rather than leaving the gateway in a broken state.
Site Gateway validates every generated Caddy configuration before reload and keeps the previous working configuration active if validation fails. Container updates are installed by pulling a new pinned image — create a backup first.
Administration
Set how many days of Access, Activity, Audit, Certificate, and Security records to keep (7–3650 days each) and whether automatic pruning is enabled. Prune Now shows exactly how many records in each category are eligible before you confirm, and Download Logs exports them.
Administration
Two separate, deliberately distinct destructive actions — kept apart so a routine preference correction is never confused with a full rebuild. Both require re-entering your own administrator username and password, typing an exact confirmation phrase, and then confirming a second themed dialog by typing YES.
Confirmation phrase: RESTORE DEFAULT. Resets Gateway Defaults, backup schedule settings, and certificate-health thresholds back to their starting values. It does not remove any hosts, uploaded files, users, groups, Access Lists, certificates, logs, or backups.
Confirmation phrase: FACTORY RESET. Deletes everything under /data — every host of every kind, uploaded files, certificates (managed and custom), logs, backups, icons, users, and settings. Docker-mounted files outside /data are untouched. The container returns to the initial setup screen without needing a manual restart. Because backups themselves live under /data/backups, they’re deleted too — recovery is only possible from a backup taken beforehand and stored elsewhere (downloaded, or on separately mounted storage).
If you want to undo a recent change while keeping the rest of the installation intact, restore a backup — Factory Reset is not a rollback tool.
Logs
Every request Caddy handles, with domain, path, response status, latency, and upstream outcome. Filter by host or by status-code range (2xx/3xx/4xx/5xx). Sensitive query-string values — tokens, secrets, passwords, session identifiers, API keys, credentials — are redacted before they’re ever stored, regardless of filter settings.
Configuration and operational changes, filterable by severity (Normal/Warnings/Errors) and by category (certificate, health, authentication, backup, configuration, or system).
Filter Access Logs for a 502, then compare the target address against a direct LAN request to the same upstream to isolate whether the problem is the gateway or the application itself.
Performance
Built entirely from the same request data already collected for Access Logs — no new logging or extra overhead, just a different view of it.
Domain narrows the Trend chart to one host (default: all domains combined). Range sets the Trend window — Last hour, 3, 6 (default), 12, or 24 hours, or 3 or 7 days.
Request volume over the selected range, bucketed into 15-minute (up to 24h) or hourly (3–7 days) points.
One row per domain that has received traffic, sorted by 24-hour volume:
Common Interface Controls
The same card language is used throughout Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, Access Lists, Groups, and Users, so learning one area transfers directly to the next.
Contains actions that change or inspect a card: Edit opens the full form, kind-specific extras appear where relevant (Replace files on Hosted Sites, View assigned hosts on Access Lists), and Delete removes the record after a confirmation.
A slide switch, separate from the menu, turns a route or account on or off without deleting its saved configuration — useful during maintenance or testing when you expect to reuse the exact same settings shortly after.
Administrators can manage everything. Standard Users can manage Hosted Sites, Proxy Hosts, Redirect Hosts, Streaming Hosts, and Access Lists, but not Users, Groups, Settings, or Backups. Viewers can inspect information but cannot create, edit, disable, assign, or delete anything — their menus and toggles are hidden entirely. This is enforced on the server independently of what the interface shows, so hiding a button is a convenience, not the actual security boundary.
While signed in, Site Gateway checks every 60 seconds whether a newer version has been deployed. If so, a small banner appears with Refresh and Dismiss — Refresh reloads the page to pick up the new version; Dismiss hides the banner, but it reappears on the next check if you’re still on the old version. This only matters for a tab left open across a deploy; closing and reopening the tab, or signing in fresh, always loads the current version automatically.
Icons
Every Hosted Site, Proxy Host, Redirect Host, Streaming Host, Access List, Group, and User can have its own icon. Open the picker from a card’s icon tile or its “Change icon” menu action.
Jellyfin, Plex) to search a large built-in icon catalog and pick a match./data/icons. Uploaded SVGs are checked for embedded scripts or external references before being accepted.https:// image link instead of uploading a file.If a custom icon URL ever stops loading, the card automatically falls back to showing initials instead of a broken image.
Troubleshooting
Confirm public DNS actually points to this server, that router/firewall forwarding reaches ports 80 and 443, and that NGINX Proxy Manager or another reverse proxy isn’t still holding those ports. Then check Certificates and Logs → Gateway Events for the specific rejection reason. Site Gateway cannot request a public certificate while another gateway is receiving the ACME challenge on its behalf.
Check the error shown on save — it names the specific problem (duplicate address, invalid upstream, malformed custom configuration, certificate/TLS issue) rather than a generic failure, and the previous working configuration stays active while you fix it.
This is almost always the port not being published on the container yet — see Streaming Hosts → Overview for the docker-compose/Unraid port mapping requirement.
If they still have an unused recovery code, they can sign in with it in place of the 6-digit code. If not, an administrator can disable that user’s 2FA from Administration → Users — open the locked-out user’s “•••” menu and choose Disable 2FA. The user can sign in with just their password afterward and set 2FA up again whenever they’re ready.
No guide matched that search.