Reaching Noct from outside the house
Noct speaks plain HTTP and is meant to be put behind something that adds HTTPS when it leaves your own network: anyone who can see the traffic can read a password or a token. Sign-in is needed for everything (see security), so a server that’s reachable isn’t open.
Both configurations below were run, in front of a real server, with a browser’s
requests made by curl: signing up and signing in with the cookie, adding and
scanning a folder, a ranged read of a video (a 206 with its Content-Range),
a media URL with a token, an HLS playlist and segment, and signing out. They
passed through each.
What the proxy has to do
Section titled “What the proxy has to do”- Pass
Hostthrough unchanged, or say what it was inX-Forwarded-Host. Noct refuses a signed-in browser’s request to change something when the page’sOriginisn’t the host that was asked for, so that a page on another site can’t act as you. If the web app signs in but then everything it changes answers403 that request came from another site, this is why. - Say
X-Forwarded-Proto: httpswhen the browser used HTTPS. Noct then marks its sign-in cookieSecure, so it is never sent over plain HTTP. Without it the cookie works, and isn’tSecure. - Not hold video back. Turn buffering off for it, or a long film is read into
the proxy before it’s played. Noct answers ranges (
Range), which is how a player seeks, and serves HLS (/api/hls/…), and neither needs anything beyond that. - Allow bodies of 20 MB or more, for uploading a poster.
Caddy does all of that without being told, and gets the certificate itself:
noct.example.com { reverse_proxy 127.0.0.1:7356}server { listen 443 ssl; server_name noct.example.com; # ssl_certificate and ssl_certificate_key: yours, or certbot's. client_max_body_size 25m;
location / { proxy_pass http://127.0.0.1:7356; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Video is sent as it's read, not kept first. proxy_buffering off; proxy_request_buffering off; proxy_read_timeout 1h; }}Host has to be one of those proxy_set_header lines: nginx’s own default is
the address of Noct, not the one the browser asked for.
Tailscale
Section titled “Tailscale”On a tailnet there’s nothing to open: reach Noct at the machine’s tailnet name or address from any device on it. The traffic between tailnet devices is encrypted, so plain HTTP is no weaker there.
To get HTTPS and a name like https://nas.your-tailnet.ts.net, use
Tailscale Serve:
tailscale serve --bg 7356I haven’t run this one. If the web app signs in and then refuses changes with
that request came from another site, Serve isn’t passing the original host
on, as above.
Don’t use Tailscale Funnel, which makes the server public to the whole internet, unless that is what you want: Noct has no limit on requests, only on guesses at a password.
If it doesn’t work
Section titled “If it doesn’t work”| What you see | Why |
|---|---|
Signing in works, changes answer 403 … another site |
The proxy isn’t passing Host or X-Forwarded-Host |
| Signs in, and is asked to sign in again at once, over plain HTTP | The proxy says X-Forwarded-Proto: https for a browser that used HTTP, so the cookie is Secure and the browser never sends it back |
| Video stalls, or starts only after a long wait | The proxy is buffering the response |
413 uploading a picture |
The proxy’s body limit is under 20 MB |