Back to home

Seamless Site-to-Site Networking - How I Linked Two Homes Without Installing Tailscale Everywhere

6 min read
Homelab

Moving out of your parents' home is a big milestone, but for a self-hosted enthusiast, it presents a unique challenge: how do you keep your homelab services accessible across two different locations?

In my case, I left my UNRAID server (Server A) at my parents' place so they could keep using Nextcloud and Immich with minimal latency. Meanwhile, at my new apartment, I set up a Raspberry Pi (Server B) running Jellyfin.

I wanted a way for my parents to watch Jellyfin on their smart TV and for me to access my UNRAID files without the headache of installing Tailscale on every single device. Here is how I built a "bridge" between two homes using Tailscale and Caddy.

🚀 The Problem: The "Tailscale on Everything" Fatigue

Tailscale is incredible for secure remote access, as it creates a peer-to-peer mesh network with stable IPs and no port forwarding required. However, it has limitations in a family setting:

  • Smart TVs and Appliances: Many devices don't support the Tailscale app.
  • Maintenance Overhead: I didn’t want to manage Tailscale logins for my parents' phones or tablets.
  • The Goal: I wanted remote services to feel local. If I’m at my new home, I want to hit a local IP and see my parents' UNRAID server.

✅ What You'll Need

  • Server A (Parents' Home - UNRAID): Tailscale IP 100.a.b.c. Running Nextcloud (Port 8001) and Immich (Port 8002).
  • Server B (New Home - Raspberry Pi): Tailscale IP 100.x.y.z. Running Jellyfin (Port 5000).
  • Tailscale: Both servers authenticated on the same Tailnet.
  • Docker & Docker Compose: Installed on both machines.

🛠️ The Architecture: The Tailscale-Caddy Bridge

The secret sauce is using Caddy as a reverse proxy to map remote Tailscale IPs to local ports. This is a clean, modern solution that avoids public exposure.

  1. Tailscale Connects the Servers: The UNRAID and Pi "see" each other via their private Tailscale IPs.
  2. Caddy Maps the Services: A Caddy container on each side takes the remote Tailscale IP and presents it on a local LAN port.
  3. Local Access: Any device on the local network can access the remote services by hitting the local server’s IP and assigned port.

📝 Step-by-Step: Docker Compose and Port Mapping

To make this work, the Docker Compose file must explicitly open the ports that will be used for the "bridged" services. Mapping host directories to the container ensures you retain your settings across restarts.

On Server A (Parents' Home)

This server needs to "host" the Jellyfin service coming from your new home.

  • Port to Open: 5000
services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "5000:5000" # Local entry point for Remote Jellyfin
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
On Server B (New Home)

This server needs to "host" the Nextcloud and Immich services coming from your parents' home.

  • Ports to Open: 8001 and 8002
services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "8001:8001" # Local entry point for Remote Nextcloud
      - "8002:8002" # Local entry point for Remote Immich
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data

📂 Configuring the Caddyfiles

The Caddyfile tells the container exactly where to proxy the traffic once it hits those open ports.

Server A Caddyfile (Parents' Home):

# Map remote Jellyfin (running on Server B) to local port 5000
:5000 {
    reverse_proxy 100.x.y.z:5000
}

Server B Caddyfile (New Home):

# Map remote Nextcloud (running on Server A) to local port 8001
:8001 {
    reverse_proxy 100.a.b.c:8001
}

# Map remote Immich (running on Server A) to local port 8002
:8002 {
    reverse_proxy 100.a.b.c:8002
}

📡 How to Connect to Your Services

Once the stacks are "Up", connecting to your services is as simple as using your local LAN IP.

Service Access From Parents' Home (Server A) Access From New Home (Server B)
Nextcloud http://<Server_A_Local_IP>:8001 http://<Server_B_Local_IP>:8001
Immich http://<Server_A_Local_IP>:8002 http://<Server_B_Local_IP>:8002
Jellyfin http://<Server_A_Local_IP>:5000 http://<Server_B_Local_IP>:5000
  • For your parents: They just point their Smart TV or browser to their own server's IP on port 5000. No Tailscale login required!
  • For you: You access your parents' Nextcloud and Immich by hitting your Raspberry Pi's local IP on ports 8001 and 8002.

🧠 Why This Works So Well

This setup follows a "clean" philosophy:

  • No Client Setup: No need to install Tailscale on every phone, laptop, or TV.
  • Secure & Private: All traffic between homes stays within the Tailscale mesh with end-to-end encryption.
  • Persistent: By mapping volumes, your configuration remains intact after updates.
  • Low Overhead: Caddy is extremely efficient, making it perfect for the Raspberry Pi.

🎉 Final Thoughts

By using one server at each location as a "gateway," you've effectively merged two separate networks into one cohesive homelab. It’s private, secure, and passes the "parent test" for ease of use.