Home server: Tailscale + docker
How to set a home server with tailscale and expose docker services.
Theory
With Tailscale installed on a machine running Docker services, those services can be securely accessed from any other device in the same tailnet without opening router ports. Tailscale creates a private, encrypted mesh VPN where each device receives a stable virtual IP or domain, making it appear as if they were on the same local network. By binding Docker containers to localhost and then using tailscale serve or directly the host’s Tailscale IP, you can proxy traffic to those services. This way, from another device connected to the tailnet, you can simply use the provided .ts.net domain or the Tailscale IP to reach the Docker apps as if they were running locally, but over a secure peer-to-peer tunnel.
What is Tailscale
Tailscale is a zero-config VPN built on top of WireGuard that lets you create a secure, private network between your devices in minutes. Instead of dealing with port forwarding, firewalls, or complex VPN servers, Tailscale assigns each device a stable private IP address (or .ts.net domain) and automatically connects them through encrypted peer-to-peer tunnels. All devices you log in with your account join the same tailnet, acting as if they were on the same local network no matter where they are in the world. This makes it ideal for securely accessing home servers, Docker services, or even SSH into machines without exposing them to the public internet.
What is docker
Docker is an open-source platform that makes it easy to build, package, and run applications in lightweight, portable containers. A container is like a mini virtual environment that bundles together an application with all its dependencies (libraries, configurations, runtime, etc.) so it runs the same way on any machine. Unlike traditional virtual machines, containers don’t need a full operating system — they share the host’s kernel — which makes them much faster and more efficient. Developers use Docker to avoid the classic “it works on my machine” problem, because containers ensure consistency across development, testing, and production environments. It’s widely used for microservices, cloud deployments, and modern DevOps workflows.
Hands on!
Setup tailscale
Now we’re going to create a Tailscale account, and then you’ll need to download Tailscale on both machines: one acting as the client and the other as the server. On both devices you’ll log in to Tailscale with the account you just created. In my case, I won’t expose any services to the outside internet. That means a friend of mine couldn’t access my server’s services without having my Tailscale account or explicit access permissions.
Create account on Tailscale

Download Tailscale on both your server and your client, then log in:
Once you’ve logged in, you’ll see your device listed on the right.

On both the client and the server, you’ll need to grant certain security permissions. (These may vary depending on whether you’re on Windows, macOS, or Linux.) Just click Allow and continue.

Once both machines have Tailscale installed, open the admin panel, and you’ll see your devices listed there.

If you ping one machine from the other, you should get a response.
ping 100.xxx.xxx.x -t 4

Install any service
For this example, I’ll be installing AppFlowy. You can follow the tutorial here: How to install appflowy
Expose the service (Option 1)
Run the following command on your server machine:
sudo /Applications/Tailscale.app/Contents/MacOS/Tailscale serve --https=443 http://localhost:443
You should see an output similar to this:

Go to the site, log in, and select HTTPS Certificates.
If you also enable Tailscale Funnel
, anyone on the internet will be able to see your service.
It’s important to understand the difference: it depends on whether you want your service to be publicly accessible like a website, or only available to you and other users in your tailnet. In my case, I’ll be using only HTTPS Certificates.

You should see something like this:

You should also see a Success message in the console.

Now, if you navigate from the client machine to that URL
Example URL: https://linux.pro.tail52jh2,.ts.net/
You should get this popup.
Click on advanced
, then on proceed to URL
and that's all! you should be able to login!

Expose the service (Option 2)
For this example, I’ll be exposing the n8n service.
First, install Tailscale Serve so you can run it directly from the console:
brew install tailscale
Now let’s expose the n8n service that’s running in Docker on port 5678:
tailscale serve --https=5678 http://localhost:5678
You should get an output like this one:

That's all! copy the url, and go to your client machine, you can now access your n8n or any other service from the client machine!

Thanks for reading!
New magic trick unlocked! 🧙
Last updated