Skip to content

Accessing Atelier over Tailscale

Atelier is designed to run on a server in your home or lab and is accessed by hostname over your local network — typically http://atelier.home.arpa/. That works great when you’re sitting at home, but the moment you leave the LAN you can’t reach it.

Tailscale is a mesh VPN built on WireGuard that gives every device you enrol a stable private IP and a private DNS name. Connections are typically peer-to-peer; Tailscale falls back to its encrypted DERP relays when a direct path can’t be established (e.g. between two double-NAT’d networks), but traffic stays end-to-end encrypted either way. Putting your Atelier cluster on Tailscale gives you remote access from a laptop, phone, or trusted collaborator’s machine without exposing anything to the public internet.

This guide covers the setup we recommend for an Atelier homelab. The shape of it:

  1. Install Tailscale on the cluster node and enrol it.
  2. Pick a DNS strategy so atelier.home.arpa resolves to the cluster’s tailnet IP for clients off the LAN.
  3. Verify access from a remote tailnet device.
  4. (Optional) Share the cluster with another person — partner, co-tester — without giving them your full tailnet.

Tailscale is free for personal use up to three users and 100 devices, which is more than enough for a homelab.


Prerequisites

  • An existing Atelier install reachable on your LAN at a hostname like atelier.home.arpa (or whatever your portal_domain is).
  • Shell access to the cluster node with sudo rights.
  • A Tailscale account (sign up — free for personal use).

1. Install Tailscale on the cluster

The official one-liner detects your distro and adds the Tailscale apt/dnf repo. On the Ubuntu/Debian k3s node Atelier typically runs on:

Terminal window
curl -fsSL https://tailscale.com/install.sh | sudo sh

That installs the tailscale CLI plus the tailscaled daemon. The daemon is enabled and started automatically.

2. Authenticate the node

Terminal window
sudo tailscale up --hostname=atelier-cluster --accept-dns=false

Two flags worth understanding:

  • --hostname=atelier-cluster — what the node will appear as in your Tailscale admin and MagicDNS. Pick anything; atelier-cluster reads cleanly.
  • --accept-dns=false — the cluster node itself doesn’t need to use Tailscale’s DNS resolver (it has its own k3s CoreDNS for in-cluster lookups). Leave Tailscale DNS turned off here so it doesn’t fight with k3s.

The command prints an auth URL like https://login.tailscale.com/a/abc123def. Open it in any browser logged in to your tailnet, approve the new node, and tailscale up returns success.

Verify:

Terminal window
tailscale ip -4 # → 100.x.y.z (your cluster's tailnet IP)
tailscale status # one line per peer; cluster shows itself

Note the tailnet IP — you’ll use it in the next step. The MagicDNS name is <hostname>.<tailnet>.ts.net (e.g. atelier-cluster.tail-12345.ts.net).

3. Quick sanity check

Before configuring DNS, verify Atelier is actually reachable on the tailnet interface from another tailnet device. Easiest test — from your laptop with Tailscale connected:

Terminal window
ssh atelier@<tailnet-ip> # SSH still works the same; just a different IP

Or curl the cluster’s port 80 directly using the tailnet IP and a Host header so Traefik’s routing matches:

Terminal window
curl -H 'Host: atelier.home.arpa' http://<tailnet-ip>/

If that returns the Atelier UI, the network path is clear and we just need to make atelier.home.arpa resolve to the tailnet IP for off-LAN clients.


4. Pick a DNS strategy

Atelier’s Traefik uses host-based routing — every ingress is keyed to a specific hostname:

  • The UI: atelier.<portal_domain> (default atelier.home.arpa).
  • Gitea: gitea.<portal_domain>.
  • Kasten (if installed): kasten.<portal_domain>.
  • Each generated app’s ingress also matches the UI host (path-prefixed).

For a tailnet client to reach Atelier, requests have to arrive at Traefik with the matching Host header, which means tailnet clients need their DNS to resolve each of those hostnames to the cluster’s tailnet IP. The exact hostnames depend on what portal_domain was set to at install time — check yours with:

Terminal window
kubectl get ingress -A

Three approaches, simplest first. Examples below assume the default portal_domain=atelier.home.arpa; substitute yours.

On every device you want to use Atelier from over Tailscale, add one line:

100.x.y.z atelier.home.arpa gitea.atelier.home.arpa kasten.atelier.home.arpa

(Replace 100.x.y.z with the cluster’s tailnet IP from step 2, and substitute your own portal_domain if it isn’t atelier.home.arpa.)

OSPath
macOS / Linux/etc/hosts (needs sudo)
WindowsC:\Windows\System32\drivers\etc\hosts (run editor as Administrator)
iOS / Androidnot editable directly — use Option B or C

After that, http://atelier.home.arpa/ works the same off-LAN as on. Pros: zero infrastructure, five minutes per device. Cons: per-device, doesn’t help iOS/Android, breaks if you reinstall the OS.

Option B — dnsmasq + Tailscale Split DNS (zero per-client config)

Run a tiny dnsmasq on the cluster node, bound only to the tailnet interface, with one A record per Atelier hostname. Then add a Split DNS rule in the Tailscale admin console pointing at it. All tailnet clients — including iOS/Android — automatically resolve Atelier hostnames without any per-device config.

On the cluster:

Terminal window
sudo apt-get install -y dnsmasq

Drop in a single config file (/etc/dnsmasq.d/atelier-tailnet.conf):

# Atelier tailnet split-DNS resolver.
# Bound only to the Tailscale interface so it stays out of the way of
# systemd-resolved on loopback and never serves LAN clients.
interface=tailscale0
bind-interfaces
# Ignore the host resolv.conf and /etc/hosts — we only answer for the
# Atelier zones below, otherwise NXDOMAIN.
no-resolv
no-hosts
# Atelier hostnames -> cluster tailnet IP. Replace 100.x.y.z with your
# cluster's tailnet IP, and substitute your own portal_domain if it
# isn't atelier.home.arpa. Add entries here for any extra ingress hosts
# (e.g. one per generated app if you use per-app subdomains).
address=/atelier.home.arpa/100.x.y.z
address=/gitea.atelier.home.arpa/100.x.y.z
address=/kasten.atelier.home.arpa/100.x.y.z
# Lower default TTL so changes here propagate within a minute rather
# than the dnsmasq default of 1 hour.
local-ttl=60

Restart and verify:

Terminal window
sudo systemctl restart dnsmasq
sudo systemctl status dnsmasq # should be active (running)
ss -tlnup | grep ':53' # confirm dnsmasq is bound to 100.x.y.z:53
dig +short @100.x.y.z atelier.home.arpa # → 100.x.y.z

In the Tailscale admin console (login.tailscale.com/admin/dns):

  1. Nameservers+ Add nameserverCustom…
  2. Nameserver IP: 100.x.y.z (the cluster’s tailnet IP)
  3. Toggle Restrict to search domain on, enter your portal_domain (e.g. atelier.home.arpa). This sends only Atelier-related queries to dnsmasq; all other DNS still flows normally. The single search domain covers atelier.<portal>, gitea.atelier.<portal>, and kasten.atelier.<portal> because dnsmasq’s Split DNS matches by suffix.
  4. Save.

If your install used a non-default portal_domain for some components (e.g. legacy installs that put Kasten on kasten.atelier.local), add a second Custom nameserver entry with the corresponding search domain.

Tailscale clients pick up DNS config changes within ~30 seconds — no client restart needed.

Pros: zero per-client config, works on iOS/Android automatically. Cons: about 15 minutes to set up, one more service running on the cluster.

Option C — your existing home DNS

If you already run Pi-hole / dnsmasq / Unbound elsewhere and it’s reachable on your tailnet (e.g. on a homelab box that’s also Tailscale-enrolled), just add the override there and add a Split DNS entry pointing Tailscale at that resolver. Same effect as Option B, just reusing what you already run.


5. Verify from a remote device

The cleanest test is from a tailnet device that’s off your home network — phone hotspot is the easiest way to force the traffic over the tailnet. With Tailscale connected:

Terminal window
# DNS resolution should return the tailnet IP
dig +short atelier.home.arpa # → 100.x.y.z
# And the actual app
curl -I http://atelier.home.arpa/ # → HTTP/1.1 200 OK

If both work, you’re done. Open http://atelier.home.arpa/ in a browser on the same device — same Atelier UI you’d see on the LAN.


6. (Optional) Sharing with another person

You don’t have to add a collaborator (partner, co-tester) to your full tailnet — Tailscale Node Sharing lets you share just the cluster:

  1. admin.tailscale.com/machines → click atelier-clusterShare… → enter their email.
  2. They get an invite, sign up for a free Tailscale account on their own personal tailnet, and accept the share. Your cluster node shows up in their Tailscale client.
  3. They install Tailscale on their device(s), sign in, connect.
  4. DNS caveat: the Split DNS rule from Option B lives in your tailnet, not theirs. Their device needs its own DNS configuration:
    • Easy: a hosts-file entry on their device (Option A).
    • Slightly fiddly: in their Tailscale admin console, add a Custom nameserver pointing at the cluster’s tailnet IP for atelier.home.arpa — same recipe as your Option B Tailscale step, just on their tailnet.

Sharing is preferable to adding them as a full tailnet user when you don’t want to expose other devices on your tailnet to them.


Troubleshooting

Port 80 times out from a remote tailnet device, but SSH (port 22) works

You’re on a Tailscale path with constrained MTU (common on phone-tethering hops, double-NAT carrier networks, some hotel WiFi). SSH packets are small enough to slip through; HTTP responses with body fragments often aren’t.

Confirm by lowering Tailscale’s MTU on the client device:

Terminal window
# macOS / Linux client
sudo tailscale set --mtu=1280

Tailscale’s default is already 1280; some networks need lower (e.g. 1200). If lowering helps, fine; if not, this isn’t the issue.

Other diagnostics:

Terminal window
tailscale ping atelier-cluster # ICMP-equivalent; fails if path is broken
nc -vz <tailnet-ip> 80 # TCP-only test

tailscale up succeeded but the cluster doesn’t show up on other tailnet devices

Check the admin console machines list. If the device is listed but greyed out or marked “Disabled”, click into it and re-authorise. Some tailnets require admin approval for new devices.

dnsmasq fails to start with port 53 already in use

You probably have systemd-resolved listening on 127.0.0.53:53. The config in this guide binds dnsmasq only to the tailscale0 interface (interface=tailscale0 + bind-interfaces), which avoids the loopback conflict. If systemctl status dnsmasq still shows a bind error, double-check the drop-in file is correct and run:

Terminal window
sudo dnsmasq --test # validates config syntax
sudo ss -tlnup | grep ':53\b' # who's bound to port 53?

Generated apps’ subdomains aren’t reachable

If Atelier is configured to give each generated app its own subdomain (<app>.atelier.home.arpa) rather than a path-prefix under atelier.home.arpa, you’ll need a wildcard A record in dnsmasq:

# Wildcard for any *.atelier.home.arpa
address=/atelier.home.arpa/100.x.y.z

(The /atelier.home.arpa/ form already covers any subdomain since dnsmasq’s address= directive matches by suffix.)

Removing Tailscale

Terminal window
sudo tailscale down
sudo apt-get remove --purge tailscale
sudo rm -f /etc/dnsmasq.d/atelier-tailnet.conf
sudo apt-get remove --purge dnsmasq # optional, only if you set up Option B

Also remove the cluster node from the Tailscale admin console, and delete any Split DNS rules that pointed at it.


What this doesn’t give you

  • HTTPS at atelier.home.arpa. This setup leaves Atelier on plain HTTP. Browser features that require a “secure context” (camera, microphone, screen capture, service workers, etc.) won’t work over the tailnet path the same way they don’t over LAN HTTP. Self-signed or Let’s Encrypt certs are a separate setup tracked under issue #333.
  • Public access. This is private-only — only enrolled tailnet members can reach the cluster. If you want public access (sharing an Atelier app with someone outside your tailnet), look at Tailscale Funnel or a more traditional reverse-proxy + DNS + TLS setup. Funnel has limitations with Traefik’s host-based routing — it’s not a drop-in for Atelier today.
  • Per-app ACLs. All tailnet members reaching the cluster can reach everything Atelier exposes. Fine-grained control would need the Tailscale Kubernetes operator per-Service annotations, which is out of scope for this guide.