Reverse Proxy Setup
For production deployments, place Gatwy behind a reverse proxy to use a trusted TLS certificate. Gatwy listens on port 7443 by default.
Nginx
server {
listen 443 ssl http2;
server_name gatwy.example.com;
ssl_certificate /etc/letsencrypt/live/gatwy.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gatwy.example.com/privkey.pem;
location / {
proxy_pass https://localhost:7443;
proxy_ssl_verify off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Web support — required for all remote sessions
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Caddy
gatwy.example.com {
reverse_proxy localhost:7443 {
transport http {
tls_insecure_skip_verify
}
}
}
Caddy automatically provisions and renews Let's Encrypt certificates.
Traefik
The reliable approach is TCP passthrough: Traefik routes the raw TLS stream directly to Gatwy based on the SNI hostname, without terminating it. Gatwy handles its own TLS end-to-end.
TCP passthrough operates at the connection level (SNI), not the path level. Traefik does not inspect HTTP paths in passthrough mode — the entire hostname is forwarded as raw TCP.
TCP Passthrough (Recommended)
Traefik reads the SNI hostname from the TLS handshake and forwards the raw stream to Gatwy. Gatwy terminates TLS itself. Let's Encrypt via Traefik is not used in this mode — you must provide your own certificate to Gatwy (or use its auto-generated self-signed cert).
Step 1 — Create the project folder
mkdir gatwy && cd gatwy
mkdir -p data certs letsencrypt
Step 2 — Obtain a TLS certificate
You need a certificate for your domain. Two options:
Option A — Certbot (DNS or standalone challenge)
# Standalone (port 80 must be free)
certbot certonly --standalone -d gatwy.example.com
# Copy to your project certs folder
cp /etc/letsencrypt/live/gatwy.example.com/fullchain.pem ./certs/cert.pem
cp /etc/letsencrypt/live/gatwy.example.com/privkey.pem ./certs/key.pem
Option B — Use Gatwy's self-signed cert (dev / home-lab only)
Skip this step entirely. Browsers will show a certificate warning — accept it once and proceed.
Step 3 — Create docker-compose.yml
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
# Single entrypoint on port 443 — TCP passthrough works at this level
- "--entrypoints.websecure.address=:443"
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
gatwy:
image: ghcr.io/kotoxie/gatwy:latest
container_name: gatwy
restart: unless-stopped
volumes:
- ./data:/app/data
- ./certs:/app/certs:ro # omit if using Gatwy's self-signed cert
environment:
- GATWY_ENCRYPTION_KEY=your-64-char-hex-key # openssl rand -hex 32
- TLS_CERT_PATH=/app/certs/cert.pem # omit if using self-signed
- TLS_KEY_PATH=/app/certs/key.pem # omit if using self-signed
labels:
- "traefik.enable=true"
# TCP router — Traefik matches on SNI and forwards raw TLS to Gatwy
- "traefik.tcp.routers.gatwy.rule=HostSNI(`gatwy.example.com`)"
- "traefik.tcp.routers.gatwy.entrypoints=websecure"
- "traefik.tcp.routers.gatwy.tls.passthrough=true"
- "traefik.tcp.services.gatwy.loadbalancer.server.port=7443"
Replace
gatwy.example.comwith your actual domain in both the label and your DNS.
Step 4 — Generate your encryption key
echo "GATWY_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
Then reference it in docker-compose.yml:
environment:
- GATWY_ENCRYPTION_KEY=${GATWY_ENCRYPTION_KEY}
Step 5 — Start the stack
docker compose up -d
Open https://gatwy.example.com — you'll be prompted to create the admin account on first launch.
Step 6 — Add Traefik to trusted proxies
After logging in, you'll see a toast notification that Gatwy detected an untrusted proxy IP. Click Add to trusted proxies in the toast, or go to Settings → Security → Trusted Proxies and add Traefik's container IP (or 172.16.0.0/12 to cover all Docker bridge networks).
Key Configuration Points
| Label / Option | Why it's needed |
|---|---|
tls.passthrough=true | Traefik forwards raw TLS — Gatwy handles the cert and protocol upgrade natively |
HostSNI(...) | TCP routing matches on the TLS SNI hostname, not the HTTP path |
server.port=7443 | Gatwy's default HTTPS port |
No --serversTransport.insecureSkipVerify | Not needed — Traefik never inspects the backend TLS in passthrough mode |
Generate a cert with Certbot (standalone mode or DNS challenge), mount it into the container, and point TLS_CERT_PATH / TLS_KEY_PATH at it. Gatwy will pick it up on next restart.
HTTP Reverse Proxy (Alternative)
If you need Traefik to manage Let's Encrypt certificates, use the HTTP reverse proxy mode. Set --serversTransport.insecureSkipVerify=true so Traefik can connect to Gatwy's self-signed backend cert.
services:
traefik:
image: traefik:v3.0
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--serversTransport.insecureSkipVerify=true"
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
gatwy:
image: ghcr.io/kotoxie/gatwy:latest
container_name: gatwy
restart: unless-stopped
volumes:
- ./data:/app/data
environment:
- GATWY_ENCRYPTION_KEY=your-64-char-hex-key
labels:
- "traefik.enable=true"
- "traefik.http.routers.gatwy.rule=Host(`gatwy.example.com`)"
- "traefik.http.routers.gatwy.entrypoints=websecure"
- "traefik.http.routers.gatwy.tls.certresolver=letsencrypt"
- "traefik.http.services.gatwy.loadbalancer.server.scheme=https"
- "traefik.http.services.gatwy.loadbalancer.server.port=7443"
Trusted Proxies
When Gatwy is behind a reverse proxy, all requests arrive from the proxy's IP. Gatwy's proxy detection feature (enabled by default) notices when X-Forwarded-For comes from an IP that isn't on the trusted proxies list and shows an admin warning toast.
Add your proxy IP after first login:
- Open Settings → Security → Trusted Proxies
- Add the proxy's IP address or CIDR range (e.g.
192.168.1.10or10.0.0.0/8)
Alternatively, click Add to trusted proxies directly from the warning toast that appears at first login — no navigation required.
You can also disable the proxy detection warning entirely under Settings → Security → Proxy Detection if it isn't needed in your environment.
Using Your Own Certificate Directly
If you prefer not to use a reverse proxy, mount your certificate directly into Gatwy:
environment:
- TLS_CERT_PATH=/app/certs/cert.pem
- TLS_KEY_PATH=/app/certs/key.pem
volumes:
- ./certs:/app/certs:ro