Feeling generous? Fund my lavish lifestyle 💅.

🔑 445F 8079 96F7 0586 B715 C7B8 A138 06B1 FA2A 676B / RSS

A Blog by Expatriotic

Tailscale

The path: 1. Foundation → 2. Tailscale → 3. Docker → 4. Immich

Every beginner self-hosting tutorial gets this wrong: they tell you to open ports on your router. You will not be doing that. Your photos will not be exposed to the internet. Instead, every device you own joins a private tailnet — a zero-config VPN — and that's the only way in.

Why this guide sits between the OS and the apps, on purpose. The URL you type into the Immich phone app is the one thing you never want to change later. Tailscale is what makes that URL stable and HTTPS-encrypted whether you're on your couch or in another country. Chicken: you can't administer a headless server without remote access. Egg: Tailscale has nothing to join until the OS exists. So the order is foundation → Tailscale → Docker → Immich.

How it works in one paragraph

Tailscale builds a WireGuard mesh between your devices. Your laptop at a café and your server at home talk like they're on one LAN, encrypted, with no router ports opened. Every machine gets a stable name like immichbox.your-tailnet.ts.net with a valid HTTPS certificate. That name is your apps' forever-home.

1. Your laptop joins first

The server is the second device to join, not the first. Sign up at tailscale.com (free for personal use), install the client on your laptop, log in.

2. Install on the server

On the machine you built in guide one:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh

The --ssh flag is the important part: Tailscale becomes your SSH authentication. No keys to copy, no passwords. It prints a URL — open it, log in, authorize the machine.

(If you followed my Ubuntu 24.04 LTS Server Setup, you already did this once. Same ritual on any new box.)

3. Make the server a real server

Two settings in the admin console, both non-negotiable:

  1. Disable key expiry on the server (machine's ⋯ menu). A server that sits in a closet past its 90-day key expiry locks you out of your own lab. Phones and laptops keep expiry on — that rotation is a feature for devices that leave the house.
  2. Enable MagicDNS and HTTPS certificates (DNS tab). This is what gives every machine its name.ts.net hostname and real certificates.

One-time quality-of-life fix, so you can manage tailscale serve without sudo later:

sudo tailscale set --operator=$USER

4. Test it, then close the old door

From your laptop:

ssh youruser@server-name

The first time, your terminal prints a URL — complete it in the browser and you're in. No password, no key, identity-based. Now edit the config and switch off password login entirely:

sudo nano /etc/ssh/sshd_config
# PasswordAuthentication no
sudo systemctl reload ssh

Worst case now: someone steals your router. Your photos are still unreachable. That's the point. (The LAN side of this story is in my Router Setup Tips.)

5. The HTTPS front door: tailscale serve

This is the trick that makes mobile apps "just work." One command turns a local HTTP port into a proper HTTPS URL — valid certificate included — visible only inside your tailnet:

# example: Immich's port 2283, arriving in guide four
sudo tailscale serve --bg 2283

Now https://server-name.your-tailnet.ts.net proxies to port 2283 on that machine.

Serve ≠ Funnel. Serve keeps it private to your devices. Funnel publishes it to the whole internet. For family photos you want Serve — that's not a limitation, that's the privacy model. Your phone uploads over Tailscale, full stop. iOS also refuses plain-HTTP sync for many apps, so the HTTPS URL saves you a war you didn't need to fight.

Two gotchas I've personally paid for

Next: the app layer — Docker and Dockge.


← Previous: Pick Your Foundation | Next: Docker and Dockge →

#privacy #self-hosting