TLS & public exposure¶
The firebox daemon listens HTTP on :8765 and trusts the bearer
token for every call. That's fine on a LAN. For anything publicly
reachable, terminate TLS in front of it.
Topology¶
flowchart LR
Net[Internet] --> RP[Reverse proxy<br/>TLS termination]
RP --plain HTTP--> D[firebox-daemon :8765]
classDef proxy fill:#42a5f5,stroke:#1565c0,color:#fff
class RP proxy
The reverse proxy can be Caddy, Cloudflared, Tailscale Funnel, nginx, or whatever else you already run — the daemon doesn't care, as long as the bearer header makes it through.
Caddy (cleanest from-scratch path)¶
scripts/Caddyfile ships with the repo:
firebox.example.com {
encode zstd gzip
reverse_proxy http://127.0.0.1:8765 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
flush_interval -1 # NDJSON streaming for /sandboxes/{id}/stream
}
@admin path /admin/*
rate_limit @admin 10r/m
}
Install:
sudo apt install caddy
sudo cp /opt/firebox/repo/scripts/Caddyfile /etc/caddy/Caddyfile
sudo $EDITOR /etc/caddy/Caddyfile # swap firebox.example.com
sudo systemctl restart caddy
Caddy auto-issues + renews a Let's Encrypt cert, no other config needed. Point your DNS A/AAAA at the host, wait for cert issuance, done.
Then on the firewall: only port 443 is public; the daemon's own port stays loopback or LAN-only.
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 443/tcp
sudo ufw enable
# 8765 stays internal — Caddy reaches it via 127.0.0.1.
Cloudflared tunnel¶
If you don't want to expose ports at all, Cloudflare Tunnel works
beautifully. Add to /etc/cloudflared/config.yml:
tunnel: <your-tunnel-uuid>
credentials-file: /etc/cloudflared/<uuid>.json
ingress:
- hostname: firebox.example.com
service: http://localhost:8765
- service: http_status:404
Restart cloudflared. Public TLS is provided by Cloudflare; firebox sees only loopback traffic.
Tailscale Funnel¶
For a private-by-default setup that's still reachable from the public internet:
Tailscale terminates TLS via their *.ts.net domain or your custom
hostname.
What changes for clients¶
Once TLS is in front:
# Was:
export FIREBOX_URL=http://192.168.1.50:8765
# Becomes:
export FIREBOX_URL=https://firebox.example.com
Nothing else changes — the bearer header rides through every proxy unmodified.
Hardening checklist¶
- [ ] Bind to loopback if a reverse proxy lives on the same host:
change the
firebox-daemon.serviceunit to--host 127.0.0.1after Caddy / cloudflared is in front. - [ ] Rate-limit
/admin/*at the proxy. The CLI is rare; brute force is suspicious. - [ ] Token rotation policy: admin tokens — long-lived; user
tokens — issue with a
noteand a known expiry, revoke when the relationship ends. - [ ] Backups:
/etc/firebox/,/srv/firebox/templates/,/var/firebox-profiles/are the only state worth restoring to a fresh host. - [ ] Logs:
journalctl -u firebox-daemonis single source of truth. Pipe to your log shipper / SIEM.