All apps · 0 apps
Site-Gateway
Docker app from mfwade's Repository
Overview
Readme
View on GitHub
Host. Proxy. Secure.
A friendly, self-hosted gateway for homelabs and small teams — publish static sites, reverse-proxy your apps, forward raw TCP/UDP streams, and manage TLS and access from one calm dashboard.
Why Site Gateway · What you get · Quick start · Configuration · Unraid · ZimaOS · Roadmap Roles
Why Site Gateway
I didn't set out to build a reverse-proxy manager. I just wanted to host one website without hand-editing a Caddyfile or Nginx config every time I needed a domain and a certificate pointed at something. Every option I found was either too raw (edit the config, reload, hope it works) or way more than I needed for one site.
Once that one site was working — and it only took a few clicks — I realized the same thing applied to everything else I was running. Proxying Plex, forwarding a port for a hosted service, redirecting a domain, renewing a certificate — every one of those was its own manual chore in whatever proxy setup I already had. What I actually wanted wasn't a nicer way to host a website. It was a replacement for my whole reverse-proxy setup, with one dashboard that handled all of it the same easy way.
That's Site Gateway now: one container, one dashboard, for static sites, proxy routes, redirects, raw TCP/UDP streams, TLS, and access control — with Caddy doing the actual routing and certificates underneath. I built it so someone who's never touched a Caddyfile can point a domain at an app in a couple clicks, and someone who's run Nginx Proxy Manager or Traefik for years won't feel like anything's missing.
The goal for day-to-day use is three steps. Hosting a site, three steps. Setting up a proxy host, three steps. That's for the stuff you'll do over and over. It doesn't apply to the initial install below — that's honestly closer to five steps, because getting Docker, your .env, and your first admin account right matters more than hitting a number.
It's narrower than a general-purpose proxy manager on purpose. You tell it what you want — a site, a proxy target, a redirect, a port forward — and it writes and reloads the actual gateway config for you. No Caddyfile required.
What you get
| Hosted Sites | Proxy Hosts | Redirect Hosts | Streaming Hosts |
|---|---|---|---|
Upload a ZIP or index.html and publish static files on a domain and/or a direct port |
Point a domain at Plex, Jellyfin, Vaultwarden, or any HTTP app — TLS, HSTS, and headers included | Send one or more domains to a canonical destination with 301/302/307/308 | Forward raw TCP/UDP ports straight to a service — game servers, SSH, anything that isn't HTTP |
- 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, and throughput at a glance, plus a live resource panel (CPU, memory, swap, disk, network, uptime) reading real container-scoped cgroup v2 stats, not host-wide numbers, and auto-refreshing while the page is open.
- 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, 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.
- API access tokens — issue scoped (full-access or read-only), optionally expiring bearer tokens for scripts and integrations, revocable at any time.
- Backups — configuration or complete
.sgbackuparchives, downloadable, importable, schedulable, and optionally AES-256-GCM encrypted. - Certificates page — issuer, expiration, days remaining, and renewal health for every managed and uploaded certificate.
- Performance and logs — per-domain request throughput, response times, and rotating access/activity logs, including a System page (Administration) with the same live resource panel as the Dashboard, environment/integration status, gateway sync, scheduled jobs, storage usage, and version/database/public IP details.
- SQLite-backed persistence — no external database container; everything lives under one
/datavolume.
Hosted uploads remain static-only (HTML, CSS, JS, images, fonts, downloads). Dynamic applications are connected as Proxy Hosts instead — Site Gateway does not execute uploaded PHP, Node, Python, or database code.
Quick start
Requirements: Docker Engine with Docker Compose, and ports 80/443 free on the host (plus 8080 for the dashboard).
Copy
.env.exampleto.envand setADMIN_PASSWORDandSESSION_SECRET.Pull and start the published image:
docker compose -f compose.release.yaml pull docker compose -f compose.release.yaml up -dOpen
http://YOUR-SERVER-IP:8080and sign in withadminand the password you set.Finish first-time setup (you'll be asked to confirm or change the display name, username, and password).
Create your first route from the dashboard — Hosted, Proxy, Redirect, or Streaming.
Prefer to build from source instead of pulling the image? Use compose.yaml and docker compose up -d --build.
The included Compose files publish site ports 9000–9099 for direct-LAN access to Hosted Sites. Docker can't add a host port to an already-running container, so change SITE_PORT_MIN, SITE_PORT_MAX, and the Compose ports range together, before starting the container, if you want a different range. The same applies to Streaming Hosts — publish the TCP/UDP port you plan to use before creating the route in the dashboard.
For domain routing and automatic certificates, point the domain's DNS record at this server and forward public ports 80 and 443 to the container. If another reverse proxy already owns those ports, stop it or use temporary alternate host ports for LAN testing — public ACME issuance won't work until 80/443 traffic actually reaches Site Gateway.
Domains, proxy hosts, and TLS
Use Hosted Sites for uploaded files. A domain is optional; when present, Caddy serves the site on ports 80/443 and automatically obtains and renews a public certificate. Direct site ports remain available for LAN testing.
Use Proxy Hosts to connect a domain to an existing application, such as http://192.168.1.20:3000 or another container's name and port. Caddy supplies the standard forwarded headers and supports WebSocket upgrades automatically.
Use Streaming Hosts for anything that isn't HTTP — game servers, SSH, or other raw TCP/UDP services. These need their port published in Compose up front, since Docker can't add ports to a running container.
Automatic HTTPS requires valid public DNS and inbound access to port 80 or 443. HSTS is optional and should only be enabled after HTTPS is confirmed working.
Configuration
| Variable | Default | Purpose |
|---|---|---|
ADMIN_USERNAME |
admin |
Bootstrap dashboard login name |
ADMIN_PASSWORD |
— | Bootstrap dashboard password; required, always change it |
SESSION_SECRET |
— | Required. Any random string; rotating it signs everyone out |
ADMIN_PORT |
8080 |
Dashboard port inside the container |
SITE_PORT_MIN / SITE_PORT_MAX |
9000 / 9099 |
Direct-LAN port range Hosted Sites can bind to |
DATA_DIR |
/data |
Persistent state location |
DATA_DIR_LIMIT_GB |
empty | Optional display-only allowance for the System tab's Disk stat (e.g. a smaller dedicated share); usage/free space still come from the real volume |
BACKUP_PASSWORD |
empty | Encryption password used only when encrypted scheduled backups are enabled |
PUID / PGID |
1000 / 1000 |
User/group the container writes files as (Unraid: 99/100) |
ACME_EMAIL |
empty | Optional certificate account email |
At startup, the container creates the complete /data hierarchy, applies PUID/PGID ownership, then drops root privileges. Configuration lives in SQLite at /data/database/site-gateway.sqlite; hosted files live under /data/sites; backups under /data/backups; certificates under /data/certificates.
Unraid
- Add the container from Docker → Add Container using the image
ghcr.io/mfwadejr/site-gateway:latest, or search Community Applications once a template is published. - Map ports
80,443(TCP+UDP),8080, and9000-9099as above, plus any Streaming Host ports you plan to use. - Map one path, e.g.
/mnt/user/appdata/site-gateway:/data. - Set
PUID=99andPGID=100so the container writes to/dataas thenobody/usersaccount Unraid expects. - Set
ADMIN_PASSWORDandSESSION_SECRET, then start the container and openhttp://UNRAID-IP:8080.
For automatic image-based upgrades, Unraid's Update Container action pulls the newest latest image; if you use Watchtower, compose.release.yaml includes its opt-in label.
ZimaOS
The simplest path is compose.zimaos.yaml — a ready-to-import file with the x-casaos metadata ZimaOS's app installer and App Store use for the icon, title, and port mapping.
- In ZimaOS, go to Docker → Install a Customized App, and paste or select
compose.zimaos.yaml. - Before starting it, edit
ADMIN_PASSWORDandSESSION_SECRETin the environment fields. - Confirm the data path — it defaults to
/DATA/AppData/site-gateway— and start the app. - Open
http://ZIMAOS-IP:8080.
Prefer a plain Compose file instead? compose.yaml (build from source) and compose.release.yaml (pull the published image) both work the same way:
Copy this folder into ZimaOS storage, e.g.
/DATA/AppData/site-gateway/app.Point the Compose volume at
/DATA/AppData/site-gateway/data:/data.Set
ADMIN_PASSWORDandSESSION_SECRET(andPUID/PGIDif needed — ZimaOS typically uses1000:1000).Import through ZimaOS's custom app / Compose import option, or run it from the terminal:
cd /DATA/AppData/site-gateway/app docker compose up -d --buildOpen
http://ZIMAOS-IP:8080. Use ZimaOS's container update/recreate action whenever a new image is published — the/datamount keeps all sites during replacement.
Backup and update
Open Administration → Backup & restore to create a Configuration or Complete backup. Manual backups download to the browser; scheduled backups are stored under /data/backups and can be AES-256-GCM encrypted when BACKUP_PASSWORD is set. A Complete backup contains a consistent SQLite snapshot, portable JSON recovery data, hosted files, local icons, custom fallback assets, and certificate storage. Because certificate backups contain private keys, encryption is strongly recommended.
Before restoring, Site Gateway checks the archive manifest, creates a complete pre-restore safety backup, then reloads and validates the resulting configuration.
To upgrade:
docker compose -f compose.release.yaml pull
docker compose -f compose.release.yaml up -d
This recreates only the application container — your sites, certificates, and configuration remain in the mounted data directory.
Security notes
- Use a unique bootstrap password during installation, then finish first-time setup to finalize the persistent administrator account.
- Enable two-factor authentication on administrator accounts.
- Keep the dashboard on a trusted LAN or behind a trusted HTTPS reverse proxy/VPN — don't expose the admin dashboard directly to the internet.
- Uploaded static JavaScript runs for visitors; only publish files you trust.
- The container starts as root only to apply
PUID/PGIDownership and grant Caddycap_net_bind_service, then drops both the Node app and Caddy to the unprivilegedPUID:PGIDuser. It does not require access to the Docker socket.
Troubleshooting
- Site shows Error: another process probably owns its port. Check
docker logs site-gateway, then recreate the site on a free published port. - Site cannot be reached: confirm the port is within the published Compose range and allowed through the server firewall.
- Permission denied under
/data: make the host data directory writable by the configuredPUID/PGID. - Upload fails: verify the file is below 250 MB and the extracted root contains
index.html. - Dashboard port is busy: change only the host side, e.g.
8180:8080, then browse to port 8180. - Streaming Host has no traffic: confirm the TCP/UDP port is published in Compose before creating the route — Docker can't add ports to a running container.
Roadmap
See ROADMAP.md for what's shipped and what's next, CHANGELOG.md for the full per-release history, or ROLES.md for the full Administrator/Standard User/Viewer permission matrix.
License
MIT — see LICENSE.
Install Site-Gateway on Unraid in a few clicks.
Find Site-Gateway in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Related apps
Explore more like this
Explore allDetails
ghcr.io/mfwadejr/site-gateway:latestRuntime arguments
- Web UI
http://[IP]:[PORT:8080]- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--restart=unless-stopped
Template configuration
Where Site Gateway stores its SQLite database, hosted files, backups, and certificates (including private keys). This is real, durable data, not a cache — point it at a protected array or pool location rather than an unprotected cache-only share.
- Target
- /data
- Default
- /mnt/user/appdata/site-gateway
- Value
- /mnt/user/appdata/site-gateway
Login name for the first-run admin account. Pre-filled with admin — used the first time you log in to the dashboard; you can create additional users afterward.
- Default
- admin
- Value
- admin
Password for the first-run admin account, used the first time you log in to the dashboard. Pre-filled with changeme as a placeholder — required, and you must replace it with a real password before starting the container.
- Value
- changeme
Required. A random secret (at least 32 characters recommended) used to sign login sessions — it is not a password and is never used to log in. Changing it later signs every logged-in user out.
- Value
- changeme-too
Encryption password used only when encrypted scheduled backups are enabled. Leave blank to disable backup encryption.
Optional, but recommended. Let's Encrypt uses this address to warn you if a certificate renewal is failing — without it you won't be notified until a site actually goes down.
Internal port the admin dashboard listens on. Must match the WebUI port mapping's target below if changed.
- Default
- 8080
- Value
- 8080
Start of the port range Hosted Sites use internally, and are reachable on directly (host-ip:port) for LAN-only access, in addition to through Caddy on 80/443. Must not overlap ADMIN_PORT, 80, 443, or any port you use for Streaming Hosts — the app reserves this whole range and will refuse to reuse a port already claimed elsewhere.
- Default
- 9000
- Value
- 9000
End of the port range Hosted Sites use internally, and are reachable on directly (host-ip:port) for LAN-only access, in addition to through Caddy on 80/443. Must not overlap ADMIN_PORT, 80, 443, or any port you use for Streaming Hosts — the app reserves this whole range and will refuse to reuse a port already claimed elsewhere.
- Default
- 9099
- Value
- 9099
User the container writes /data as. Unraid convention is 99 (nobody).
- Default
- 99
- Value
- 99
Group the container writes /data as. Unraid convention is 100 (users).
- Default
- 100
- Value
- 100
Optional, display-only. Tells the Dashboard/Administration > System resource panel how much space is actually assigned to this app's data (useful if your appdata share doesn't use the whole array/pool), so the Disk percentage shown is meaningful instead of comparing against total array capacity. Leave blank if you don't need that panel to be precise.
Admin dashboard.
- Target
- 8080
- Default
- 8080
- Value
- 8080
Plain HTTP — required for HTTP-01 ACME challenges and HTTP→HTTPS redirects.
- Target
- 80
- Default
- 80
- Value
- 80
HTTPS for every hosted site and proxy host.
- Target
- 443
- Default
- 443
- Value
- 443
Publishes the Hosted Sites port range (see SITE_PORT_MIN/SITE_PORT_MAX above) so hosted sites are reachable directly at host-ip:port on your LAN, in addition to through Caddy on 80/443.
- Target
- 9000-9099
- Default
- 9000-9099
- Value
- 9000-9099
Not required — shown only as an example. Add one line like this per Streaming Host you configure in the dashboard, matching whatever port you enter there (e.g. a game server on 25565). Must be a port outside the Hosted Sites range above and not 80/443/ADMIN_PORT. Delete this example if you're not using Streaming Hosts.
- Target
- 25565
- Default
- 25565
- Value
- 25565
Must be mounted to enable 'Pick from running containers' when configuring Proxy or Streaming host targets — without it, that feature stays unavailable and you'll enter targets by IP/hostname manually instead. Access to the Docker socket is effectively root on the host, so only mount it if you want this feature.
- Target
- /var/run/docker.sock