Repository navigation
Remote Access with Tailscale
Obelo can join your tailnet as a node of its own and serve the same API and
web app there, reached at a stable name like obelo.tail1a2b.ts.net from any
device that is also on the tailnet.
There is no port to forward, no DNS record to keep current, no domain to buy, and nothing exposed to the open internet.
Every client device must also join the tailnet — Tailscale installed and signed in on the iPhone, the iPad, the Apple TV, and any laptop whose browser you use.
That is a worse first run than typing an address, and a better everything after. It is also why this does not replace HTTPS: a household that wants to hand a URL to someone who will not install a VPN client still needs the port forward. Both paths are supported and neither replaces the other.
No port forward is involved at any point. If a step below has you opening the router's admin page, you are on the wrong page.
The plain-HTTP listener on OBELO_LISTEN_ADDR keeps serving the LAN exactly as
before, mDNS discovery goes on working, and any HTTPS you configured is
untouched. This is a third listener, never a replacement. A session created
on one works on the others.
The embedded node is compiled in only under -tags tailscale, which keeps
roughly 550 dependencies out of a development build.
curl -s http://192.168.1.50:8080/api/v1/server | grep -o '"tailscale":[a-z]*'"tailscale":true means the feature is present. false — or nothing — means
you are running a build without it. The Docker image and make build-release
carry it; a plain make build does not.
A build without it answers the remote-access endpoints with an error that names
the build, rather than a confusing 404.
Nothing about the container changes to support this: no extra capabilities, no
/dev/net/tun, no NET_ADMIN, and it still runs as the unprivileged obelo
user, because the node runs in userspace inside the server process.
Sign up at tailscale.com if you have not — the free tier is ample for a household. The account is the tailnet; there is nothing else to create.
Note the tailnet's name in the admin console. It looks like tail1a2b.ts.net
and it forms half of your server's future address.
In the Obelo web UI: Settings → Remote access → Connect.
A login link appears within a few seconds. Open it, approve the machine in your Tailscale account, and the panel switches to connected and shows the address:
http://obelo.tail1a2b.ts.net
http, not https, and that is correct at this point — the tailnet is
already encrypted end to end by WireGuard, and the certificate that gets you the
padlock is step 5.
That address is now permanent. It does not change when your ISP changes your IP, when the router reboots, or when the server's DHCP lease moves.
Skip the click by minting an auth key in the Tailscale console (Settings → Keys) and passing it in the environment:
environment:
OBELO_TAILSCALE_ENABLED: "true"
OBELO_TAILSCALE_AUTHKEY: "tskey-auth-..." # consumed at join, never storedThese variables seed the settings on first boot only. Afterwards the web UI is authoritative and editing them changes nothing. Connect and disconnect take effect immediately, with no restart. See Configuration.
Tailscale expires a machine's membership after 180 days by default. When it lapses, remote access stops. Nothing local breaks, nothing logs an error on the client, and it happens roughly six months after the last time you thought about any of this.
In the Tailscale admin console: Machines → your Obelo server → ⋯ → Disable key expiry.
Obelo warns in the settings panel and in the boot log as the date approaches (loudly under 14 days), and shows a fresh login link if it lapses — but the fix lives in the console, not in Obelo. Nothing here can extend it.
Install the Tailscale app on every device that will reach the server, and sign each one into the same account. iOS, iPadOS, tvOS, macOS, Windows, Android and Linux are all covered.
There is no per-device configuration beyond signing in. A device on the tailnet
reaches obelo.tail1a2b.ts.net; a device not on it does not, which is the
point.
Do this. It is not cosmetics.
The tailnet is already encrypted end to end, so this is not about confidentiality. Three other things hang off it:
- HTTP/2, which is a real speed difference. HTTP/2 is negotiated during the TLS handshake, so plain HTTP can never have it. With HTTPS on, the tailnet multiplexes many small requests over one connection; without it they queue against the browser's per-origin connection limit. A poster grid or an HLS playlist is dozens of small fetches, and the remote path is where latency is highest — so this is precisely where it hurts most.
-
Apple apps cannot use the plain-HTTP address at all. App Transport
Security refuses cleartext to a globally-resolvable name like a
.ts.netone; the request never leaves the app. Safari is exempt, which is why the web app can work while the Obelo app cannot. - No browser warning, and no exception to click.
The address Obelo publishes to clients follows what actually bound. Leave this
off and every client gets the http:// address and stays on HTTP/1.1
permanently, with nothing telling you what you left behind.
It requires two things in the Tailscale admin console, both outside Obelo:
- DNS → MagicDNS: enabled.
- DNS → HTTPS Certificates: enabled.
Then in Obelo: Settings → Remote access → Enable HTTPS.
Two things to know before you do:
- Your server's name is published in public Certificate Transparency logs the
moment a certificate is issued. That reveals that
obelo.tail1a2b.ts.netexists. It reveals nothing about what is on it and grants no access — but it is public and permanent, so decide deliberately. - If certificate provisioning fails, plain HTTP on the tailnet keeps
working, and the address shown to you stays
http://rather than promising anhttps://that would refuse connections. The reason appears on the settings page and in the log, in the same words. It is not an outage, and it retries on its own once you fix the console settings — no restart.
Skipping this step leaves everything working; you simply keep the slower transport and the Obelo app cannot use the tailnet address. It is reversible either way: untick it and the listener goes.
Use the address from step 2 as the server address in each Obelo client. On the LAN you may keep using the local address; both work, and the tailnet address works in both places — which is the argument for just using it everywhere.
In a browser you will be asked to sign in again the first time you use the
tailnet address. That is not a bug: https://obelo.tail1a2b.ts.net and
http://192.168.1.50:8080 are different origins as far as any browser is
concerned, and sessions do not cross origins. Native clients carry their own
token and are unaffected.
The tailnet is also the easiest way to let a friend's Obelo reach yours, so they can browse and play libraries you lend them — with no port forward on either side, and nothing exposed to the internet.
You do it by sharing the machine, not the tailnet: in the Tailscale console, Machines → your Obelo server → ⋯ → Share…, to the other operator's Tailscale account. Their server then dials yours directly over WireGuard. No client device joins anything — their phones and televisions still only talk to their own server.
Both servers need steps 1–3 above done first, and the shared machine needs key expiry disabled for the same reason yours does — except that when it lapses, the only symptom is a link showing unreachable on a machine in someone else's house.
The rest of it — the linked-server user, the ceilings, the invite string — is on Linked Servers.
If you would rather not depend on Tailscale's coordination server at all, point Obelo at your own:
Settings → Remote access → Control URL, or OBELO_TAILSCALE_CONTROL_URL on
first boot. Empty — the default — means Tailscale's.
Everything else works the same way; the console steps happen in your Headscale instead. The knob exists so that nothing about Obelo obliges you to depend on somebody else's service.
Never put 100.64.0.0/10 (or any tailnet range) in OBELO_TRUSTED_PROXIES.
A tailnet peer is a client, not a proxy. Listing the range would let any device
on the tailnet assert whatever client address it likes — and the login-failure
limiter and the device-code quota are keyed on that address, so a device that can
name its own has no limit at all.
Do not turn off the plain-HTTP listener. LAN clients and mDNS discovery use
it, and no certificate can cover a .local name or a raw LAN address.
The login link never appears. The server cannot reach the coordination server. Check the server's own internet access; the log line names what it tried.
Connected, but a client cannot reach it. Confirm the client device is signed into the same tailnet — this is the overwhelmingly common cause. Check the machine list in the console: both should be there and both online.
It worked for months and then stopped. Step 3. Check the machine list for an expired node and re-authorize with the link in Obelo's settings panel.
Playback stutters remotely but the LAN is fine. Your two devices could not connect directly and fell back to a DERP relay, which is throttled and shared. Tailscale's console shows the connection type per machine. Direct connections usually establish given a moment; a network that blocks UDP outright will never get one, and this path will stay slow.
HTTPS says no certificate. Both console toggles in step 5, then read the reason on the Remote access settings page — it names which prerequisite is missing. Plain HTTP on the tailnet is unaffected meanwhile.
I disconnected and the machine is still in the console. Expected. Disconnect stops the node and keeps its identity so reconnecting is instant. Forget wipes the identity here, but the row in the Tailscale console is yours to delete — nothing Obelo does can remove it.
I want to move the server to a different tailnet. Forget, then Connect, then sign in to the other account. Delete the stale machine row in the old console.
Getting started
Reference
Going further
Plugins
Sharing with another household
Reaching it from away
When it breaks