19 KiB
Site Gateway
Host. Proxy. Secure.
A friendly, self-hosted gateway for websites, applications, domains, and automatic HTTPS.
Quick start · Domains & TLS · Unraid · ZimaOS · v0.9 installation guide · Roadmap
Site Gateway gives a home server one clear control panel for two jobs: publishing uploaded static sites and routing domains to applications already running on your network. Caddy handles the gateway, certificates, renewals, redirects, compression, and WebSocket forwarding behind the scenes.
| Publish | Route | Protect | Operate |
|---|---|---|---|
Upload a ZIP or index.html |
Proxy domains to LAN apps or containers | Automatic HTTPS certificates and renewal | Enable, disable, replace, and delete from one dashboard |
| Assign direct testing ports | Host multiple domains on ports 80/443 | Optional HSTS and HTTPS redirects | Persistent /data storage with PUID/PGID support |
Note
Site Gateway is intentionally simpler than a general-purpose proxy manager. You provide the site or destination; the guided interface writes and safely reloads the gateway configuration.
Alpha features
- Password-protected, responsive dashboard with live gateway health
- Hosted-site, proxy-host, TLS-domain, and attention totals at a glance
- Runtime uptime, memory, persistent-data size, disk space, and installed versions
- Recent configuration activity for the current container session
- Confirmed Caddy, HTTP port 80, and HTTPS port 443 health checks with manual and automatic refresh
- Searchable Dashboard Icons picker with validated local storage under
/data/icons - Consistent two-letter icon fallbacks for hosted sites and proxy hosts
- Create a site from a ZIP archive or a single
index.html - One independently enabled/disabled port per site
- Caddy gateway on ports 80 and 443
- Domain routing and automatic HTTPS for hosted sites
- Reverse proxy hosts for containers, LAN services, and applications
- Redirect Hosts with 301, 302, 307, and 308 responses and optional path preservation
- Reusable Access Lists with LAN/CIDR rules and a themed username/password sign-in page
- Collapsible Proxy Host controls for custom locations, headers, compression, upstream TLS, health expectations, and expert Caddy snippets
- Public, internal, HTTP-only, and uploaded custom-certificate modes
- Automatic certificate renewal and HTTP-to-HTTPS redirects
- Configurable themed welcome, 404, redirect, no-response, and custom-HTML fallback pages
- Integrated, searchable documentation with real-world setup examples
- Administrator workspace for users, gateway defaults, security guidance, and backup/restore
- Downloadable, importable, scheduled, retained, and optionally encrypted
.sgbackuparchives - Replace a site's files without recreating it
- Delete sites and their stored files
- Persistent configuration and uploads under
/data - Built-in transactional SQLite configuration database at
/data/database/site-gateway.sqlite - Unified certificate storage under
/data/certificatesand fixed backup storage under/data/backups - Path traversal protection for ZIP extraction and a 250 MB upload limit
- Clean shutdown and automatic site restart after a container restart
Hosted uploads remain static-only (HTML, CSS, JavaScript, images, fonts, and downloads). Dynamic applications can be connected as proxy hosts. Site Gateway does not execute uploaded PHP, Node, Python, or database code.
Quick start
Requirements: Docker Engine with Docker Compose.
-
Edit
compose.yamland replacechange-this-passwordwith a strong password. -
From this folder, run:
docker compose up -d --build -
Open
http://YOUR-SERVER-IP:8080. -
Sign in with
adminand the password you chose. -
Select New site, provide a name and unused port, then upload either:
- a ZIP with
index.htmlat its root; or - a single
index.htmlfile.
- a ZIP with
-
Open the site from its arrow button or visit
http://YOUR-SERVER-IP:PORT.
The included Compose file publishes site ports 9000–9099. Docker cannot add a host port to an already-running container, so any site port must be included in the published range. Change SITE_PORT_MIN, SITE_PORT_MAX, and the Compose ports range together before starting the container if you want a different range.
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 map Site Gateway to temporary alternate host ports for LAN testing; public ACME issuance will not work until 80/443 traffic 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 name and port. Caddy supplies the normal forwarded headers and supports WebSocket upgrades automatically.
Automatic HTTPS requires valid public DNS and inbound access to port 80 or 443. Caddy renews certificates automatically before expiration. HSTS is optional and should only be enabled after HTTPS works reliably.
Install from the published image
Each push to main automatically publishes ghcr.io/mfwadejr/site-gateway2:latest for both Intel/AMD and ARM64 servers. Copy .env.example to .env, replace the password and session secret, then run:
docker compose -f compose.release.yaml pull
docker compose -f compose.release.yaml up -d
To upgrade later:
docker compose -f compose.release.yaml pull
docker compose -f compose.release.yaml up -d
This recreates only the application container. Uploaded sites remain in the persistent data mount.
ZIP layout
Preferred:
my-site.zip
├── index.html
├── styles.css
├── app.js
└── images/
└── logo.png
A ZIP containing one top-level folder is also accepted; Site Gateway unwraps that folder automatically.
Unraid alpha install
Option A: Compose Manager
- Install Compose Manager from Community Applications if it is not already present.
- Copy this project folder to
/mnt/user/appdata/site-gateway/app. - In
compose.yaml, change the volume to/mnt/user/appdata/site-gateway/data:/data. - Set a strong
ADMIN_PASSWORD. Optionally set a long randomSESSION_SECRET. - Add the stack in Compose Manager and choose Compose Up.
- Open
http://UNRAID-IP:8080.
For automatic image-based upgrades, use compose.release.yaml instead. Unraid's Update Container action can pull the newest latest image. If you already use Watchtower, the release Compose file includes its opt-in label.
Option B: build from the Unraid terminal
cd /mnt/user/appdata/site-gateway/app
docker compose up -d --build
If Unraid reports a port conflict, change the admin port mapping's left side (for example 8180:8080) or choose a different site-port range. Allow the selected site ports through any LAN firewall.
ZimaOS alpha install
-
Copy this folder into ZimaOS storage, for example
/DATA/AppData/site-gateway/app. -
Change the Compose volume to
/DATA/AppData/site-gateway/data:/data. -
Set a strong
ADMIN_PASSWORDand optionallySESSION_SECRET. -
In the ZimaOS app interface, use its custom app / Compose import option and paste or select
compose.yaml. If that option is unavailable in your release, use the terminal:cd /DATA/AppData/site-gateway/app docker compose up -d --build -
Open
http://ZIMAOS-IP:8080.
For simple upgrades, import compose.release.yaml; use ZimaOS's container update/recreate action whenever a new image is published. The /data mount keeps all sites during replacement.
Migrating from Web Server
The product, repository, image, and default container are now named Site Gateway. Existing data does not need to move. Stop and remove the old container, then run the new image while mounting the existing folder:
docker stop web-server
docker rm web-server
docker pull ghcr.io/mfwadejr/site-gateway2:latest
docker run -d --name site-gateway --restart unless-stopped \
-p 8080:8080 -p 80:80 -p 443:443 -p 9000-9099:9000-9099 \
-v /DATA/AppData/web-server:/data \
-e ADMIN_USERNAME=admin \
-e ADMIN_PASSWORD='YOUR_EXISTING_PASSWORD' \
-e SESSION_SECRET='YOUR_EXISTING_SESSION_SECRET' \
-e PUID=1000 -e PGID=1000 \
ghcr.io/mfwadejr/site-gateway2:latest
After confirming the sites appear, you may keep the legacy host folder or rename it to /DATA/AppData/site-gateway while the container is stopped and update the mount accordingly. Unraid users should retain /mnt/user/appdata/web-server as the template's Data path for the first upgraded launch.
Configuration
| Variable | Default | Purpose |
|---|---|---|
ADMIN_USERNAME |
admin |
Dashboard login name |
ADMIN_PASSWORD |
change-this-password |
Dashboard password; always change it |
SESSION_SECRET |
derived | Optional stable signing secret for login sessions |
ADMIN_PORT |
8080 |
Dashboard port inside the container |
SITE_PORT_MIN |
9000 |
Lowest allowed site port |
SITE_PORT_MAX |
9099 |
Highest allowed site port |
DATA_DIR |
/data |
Persistent state location |
BACKUP_PASSWORD |
empty | Encryption password used only when encrypted scheduled backups are enabled |
PUID |
1000 |
UID that owns and runs against persistent files |
PGID |
1000 |
GID that owns and runs against persistent files |
ACME_EMAIL |
empty | Optional certificate account email |
At startup, the container creates the complete /data hierarchy, applies PUID/PGID ownership, and then drops root privileges. Configuration is stored in SQLite, hosted files remain in /data/sites, backups use /data/backups, uploaded certificates use /data/certificates/custom, and Caddy owns /data/certificates/managed. With the ZimaOS bind mount, these appear under /DATA/AppData/site-gateway on the host. Unraid commonly uses PUID=99 and PGID=100; ZimaOS typically uses 1000:1000.
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, retained according to the interface setting, and can use AES-256-GCM encryption when BACKUP_PASSWORD is configured. A Complete backup contains a consistent SQLite snapshot, portable JSON recovery data, hosted files, local icons, custom fallback assets, and both custom and Caddy-managed certificate storage; logs are optional. Because certificate backups contain private keys, encryption is strongly recommended.
Before restoring, Site Gateway checks the archive manifest and creates a complete pre-restore safety backup. It then reloads persisted state and validates the resulting Caddy configuration. Store important backups on a separate disk or NAS share—copies in the same appdata volume do not protect against disk failure.
To rebuild after pulling a new version:
docker compose up -d --build
Your sites remain intact because they live in the mounted data directory.
Publishing updates
The GitHub Actions workflow builds and publishes a fresh multi-architecture container whenever code is pushed to main. Alpha release tags publish an exact version and the moving alpha channel. For example, v0.9.0-alpha.1 publishes ghcr.io/mfwadejr/site-gateway2:0.9.0-alpha.1 and ghcr.io/mfwadejr/site-gateway2:alpha. The package starts private if the GitHub account's package defaults require it; make the site-gateway2 package public in GitHub package settings so Unraid and ZimaOS can pull without credentials.
Monitoring in v0.5.0-alpha.1
- Certificate inventory shows issuer, expiration date, days remaining, provisioning state, and the last certificate-file update reported by Caddy.
- Dashboard alerts call out certificates within 30 days of expiration and unreachable proxy upstreams.
- Enabled proxy targets are checked every 60 seconds with a four-second timeout; status, HTTP response, latency, and recent in-memory history are available to the dashboard.
- Caddy access logs are stored as rotating JSON files under
/data/logsand displayed without request headers. Gateway activity and errors are also appended to/data/logs/activity.jsonl.
v0.5.0-alpha.2 clarifies that a missing stored certificate is not detected, rather than claiming issuance is actively provisioning, and includes a consistency pass for dashboard indicators, cards, and log controls.
Users and roles in v0.6.0-alpha.1
- The environment-defined administrator becomes the initial persistent Administrator on first startup after upgrading.
- Administrators can create users, assign Administrator or Standard User roles, reset passwords, disable accounts, and archive or restore accounts.
- Standard Users have read-only access to dashboard health, hosted sites, proxy hosts, certificates, and logs. Per-host ownership and granular permissions are planned for a later release.
- Passwords are stored as salted scrypt hashes in the SQLite database; plaintext passwords are never written to disk.
- Site Gateway prevents removal of the final active Administrator and blocks users from disabling or archiving their own active session.
Gateway management in v0.7.0-alpha.1
- Administration and Documentation appear directly above the installed-version divider; Administration is role-restricted.
- Proxy Hosts support multiple custom locations using
path | destination | strip-or-preserve, request/response headers, upstream TLS controls, custom certificates, Access Lists, compression, and configurable health checks. - Access List credentials are stored as salted password hashes and presented through a Site Gateway-themed login form. Network rules accept exact IP addresses, CIDR ranges, or Caddy's
private_rangestoken. - Redirect Hosts and the configurable Default Site compile to native Caddy routes and are validated before reload.
- Expert Caddy snippets are administrator-only, size-limited, screened against global directives, and validated as part of the complete generated configuration.
Storage foundation in v0.8.0-alpha.1
- SQLite is built into the container and stores configuration at
/data/database/site-gateway.sqlite; no external database container or port is required. - A seeded Local Gateway instance scopes every stored entity in preparation for future multi-instance management.
- Existing JSON installations are imported once into SQLite after a complete migration backup is written to
/data/backups; original JSON snapshots remain under/data/migrations. - Failed first-time imports remove the incomplete database so the migration safely retries after the source problem is corrected.
- Caddy-managed certificates and internal CA data live under
/data/certificates/managed; uploaded certificates live under/data/certificates/custom; public exports are reserved under/data/certificates/exports. - Backups contain a consistent SQLite snapshot, portable JSON recovery records, checksums, and optional complete filesystem content.
First login in v0.8.0-alpha.2
- Fresh installations explain that the administrator credentials supplied to Docker are bootstrap credentials.
- After the first successful sign-in, the administrator must confirm or change the display name, username, and password before opening the dashboard.
- Completing setup rotates the account session identity and requires one final sign-in with the finalized credentials.
- Existing installations are treated as already configured and are not interrupted by the new workflow.
Trust and visibility in v0.9.0-alpha.1
- Certificate details include source, covered domains, issuer, validity, serial number, fingerprint, expiration, and the last detected file update.
- Configurable warning thresholds, 30-day and 7-day totals, uploaded-certificate mismatch detection, and linked dashboard alerts make certificate state actionable.
- On-demand diagnostics distinguish DNS, HTTP/HTTPS listener, TLS, and upstream failures for each configured domain.
- Administrators can download a redacted support report that excludes credentials, private keys, cookies, secrets, and expert configuration.
- Password minimums are eight characters throughout, and authentication forms are cleared after use.
Security notes
- Use unique bootstrap credentials during installation, then finalize the persistent administrator account during first-time setup.
- Keep the dashboard on a trusted LAN or behind a trusted HTTPS reverse proxy/VPN. The alpha dashboard itself serves plain HTTP.
- Do not 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 Caddy thecap_net_bind_servicecapability, then drops both the Node app and Caddy to the unprivilegedPUID:PGIDuser (default1000:1000) viasu-exec. 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 UID/GID 1000, or adjust ownership to match your environment. - 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, such as
8180:8080, then browse to port 8180.
Alpha roadmap
Good next additions are per-site access logs, certificate status reporting, drag-and-drop folder upload, rollback/history, health checks, access lists, and guided DNS diagnostics.
License
MIT — see LICENSE.