Exposing the Dashboard Publicly (Safely)
The Local Dashboard is designed for use on your LAN or over a private VPN like Tailscale or ZeroTier. If you want to expose it to the public internet — to view your dashboard from anywhere without a VPN, or to share it with friends — Night Summary provides a Read-Only Mirror that runs alongside the main dashboard on a second port and refuses every write action at the server level.
This page covers four ways to put that read-only mirror behind a public HTTPS hostname.
Safety Rules
Never point a public-exposure tool at your main dashboard port (default 8181).
The main dashboard has write surfaces — regenerate reports, edit Project Stats overrides, reset projects. Anyone with the public URL could trigger them.
Always point your reverse proxy or tunnel at the Read-Only Mirror port (default 8281). It’s the same dashboard UI but rejects every POST/PUT/DELETE with HTTP 403 and hides destructive buttons via CSS.
The read-only mirror is enforced server-side at a single chokepoint, so any new write endpoint added later is auto-blocked without needing to be added to an allowlist.
Enabling the Read-Only Mirror
- Open Options > Night Summary Settings and scroll to the Local Dashboard section
- Make sure Enable Local Dashboard is checked (the main dashboard must be running for the mirror to work)
- Check Read-Only Mirror
- Set the mirror port (default: 8281) — must be different from your main dashboard port
- Restart NINA — the mirror only binds at plugin startup
After restart, the read-only mirror runs on http://localhost:8281/ (or whatever port you chose). Visiting it directly shows the same dashboard with a small “Read-Only” pill in the header. Write buttons are gone.
You can verify the mode by checking the X-Read-Only: true HTTP response header on any request.
Option 1: Tailscale Funnel
Tailscale Funnel exposes a port on your tailnet device to the public internet over HTTPS. Free tier includes Funnel with soft bandwidth caps.
Prerequisites:
- Tailscale installed and logged in on the NINA machine
- HTTPS enabled for your tailnet (Admin Console → DNS → HTTPS Certificates)
- Funnel allowed for the device in your tailnet ACL (
nodeAttrs: [{ target: ["your-machine"], attr: ["funnel"] }])
Enable:
tailscale funnel 8281
Public URL:
https://your-machine-name.tailXXXXX.ts.net/
Disable:
tailscale funnel off
Option 2: Cloudflare Tunnel
Cloudflare Tunnel (cloudflared) gives you a public hostname without opening any ports or running a reverse proxy. Free tier covers personal use.
Setup:
- Sign up for Cloudflare and add a domain (free DNS plan is fine)
- Install
cloudflaredon the NINA machine - Run
cloudflared tunnel loginand create a tunnel - Configure the tunnel to point at the read-only mirror port:
%USERPROFILE%\.cloudflared\config.yml:
tunnel: <your-tunnel-id>
credentials-file: C:\Users\You\.cloudflared\<your-tunnel-id>.json
ingress:
- hostname: nightsummary.example.com
service: http://localhost:8281
- service: http_status:404
- Add a CNAME record
nightsummary→<your-tunnel-id>.cfargotunnel.com - Run as a service:
cloudflared service install
Cloudflare handles TLS automatically. Optional: enable Cloudflare Access for an extra auth layer.
Option 3: Caddy Reverse Proxy
Caddy is a single-binary reverse proxy with automatic Let’s Encrypt TLS. You’ll need:
- A domain pointed at your home IP (or use a dynamic-DNS service)
- Ports 80 and 443 forwarded to the NINA machine
Caddyfile:
nightsummary.example.com {
reverse_proxy localhost:8281
}
Run caddy run (or install as a Windows service via caddy-service.exe). Caddy fetches a TLS cert on first request and auto-renews.
Option 4: nginx Reverse Proxy
Classic option. Same prerequisites as Caddy (domain + open ports).
nginx site config (/etc/nginx/sites-available/nightsummary on Linux, or equivalent on Windows):
server {
listen 443 ssl;
server_name nightsummary.example.com;
ssl_certificate /etc/letsencrypt/live/nightsummary.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nightsummary.example.com/privkey.pem;
location / {
proxy_pass http://localhost:8281;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Use certbot --nginx for TLS.
Verifying It Works
- Hit the public URL in a browser → you should see the dashboard with a Read-Only pill in the header.
- Inspect the response headers (browser devtools → Network tab) → look for
X-Read-Only: true. - Try to POST to a mutation endpoint:
curl -X POST https://nightsummary.example.com/api/regenerate-allYou should get
HTTP 403 — Read-only mode — write actions disabled.
If you see writes succeed, the proxy is pointing at the wrong port — re-check it’s pointing at the read-only mirror port, not the main dashboard.
Revoking Public Access
| Method | Revoke |
|---|---|
| Tailscale Funnel | tailscale funnel off |
| Cloudflare Tunnel | Stop the cloudflared service or delete the DNS record |
| Caddy / nginx | Stop the proxy service or remove the site config |
| All | Uncheck Read-Only Mirror in Options + restart NINA — the mirror port stops listening entirely |
The fastest universal kill switch is unchecking Read-Only Mirror in Options and restarting NINA. The port closes; no public-exposer can reach a dashboard that isn’t running.
Troubleshooting
Port conflict on startup. If the read-only mirror port is already in use, the plugin logs a warning and skips starting the mirror — the main dashboard keeps running. Pick a different port in Options.
Tailscale: “Funnel is not allowed for this node.” Add funnel to the device’s nodeAttrs in your tailnet ACL.
Cloudflare Tunnel: 502 Bad Gateway. cloudflared is running but the read-only mirror isn’t. Check NINA is open, Local Dashboard + Read-Only Mirror both enabled, NINA was restarted after enabling.
Certificate renewal failed (Caddy/nginx). Standard Let’s Encrypt / certbot debugging — Caddy and certbot logs explain. Both auto-renew when working.
The dashboard loads but write buttons are still visible. The proxy is pointing at the main dashboard port (8181). Re-point at the mirror port (8281 default).