Easily Access Your Self-Hosted Apps Remotely Using Tailscale
Video
Transcript
Hello, this is the channel Easy Self Host.
In this video, we're going to set up remote access to our self-hosted apps using Tailscale VPN.
Our main goal is to use the same domain names both when you're at home and when you're accessing your network remotely through VPN.
So you won’t even notice when you arrive at or leave your home .
Tailscale is one of the most popular VPN solutions out there right now, and it's really easy to use.
It’s built on WireGuard, which keeps your connections secure, and it leverages identity providers to authenticate your devices, making the whole setup process a breeze.
But before we jump into setting up Tailscale and our home server, I want to give you a quick overview of what VPNs are.
I'll explain how they allow us to access our home servers.
This way, we won't have to expose our home router or gateway to the public internet.
Our home network is like a secure bubble, protected by our router's built-in defenses that keep outsiders from accessing our devices directly.
By default, we can't reach our home servers and devices from outside because they're hidden from the public internet for safety.
One way to access them is through port forwarding, which opens a specific door in our router to the internet.
But this method poses significant security risks since it can allow anyone to attempt entry into our network.
That's where a Virtual Private Network, or VPN, comes into play.
As the name suggests, a VPN creates a private network over the public internet, inaccessible to outsiders.
It is software-based, so it isn't limited by physical hardware like routers.
In practice, we set up a VPN that includes both our home servers and the devices we use remotely.
This way, even when we're away from home, we can access our servers as if we were on the same local network.
All of this is made possible through an encrypted connection tunnel, which securely links our devices over the internet.
Typically, when setting up a basic VPN, we need to configure each participating device with encryption keys, and we also need a server with a public IP address to manage the connections.
Tailscale simplifies all of this by handling those details for you.
It uses modern authentication solutions to identify devices and establish connections seamlessly.
Of course, you do need to trust Tailscale's commitment to not storing any of your keys and maintaining strong security measures.
Tailscale offers a free tier for personal use, which is perfect for accessing your home network.
Alternatively, there's an open-source, self-hostable project called Headscale that implements the Tailscale server functionality.
We'll be covering Headscale in the next video.
Now let’s get started to set up our Tailscale network.
First, let’s go to the Tailscale.com website and create an account.
Here we can choose the identity provider we like for authentication.
We could use our self-hosted Authentik server if it’s publicly accessible.
But mine is not so I’ll go with other options.
After signing in there are the onboarding steps to help us set up our devices.
We can skip the onboarding and set up devices on our own.
The first device I'm going to enroll is my phone, which is the primary device I use when I'm away from home.
So, let's open the Tailscale app on our phone.
We'll need to agree to add the VPN profile so our phone can use Tailscale as the VPN.
Then, sign in with the same account we used earlier.
After signing in, let's connect this device to the Tailscale VPN.
Now, if we go back to the Tailscale admin panel, we'll see that there's one machine connected.
Next, we can start adding our home server to the Tailscale VPN.
Since all our self-hosted apps are running in Docker, we can integrate Docker with Tailscale as well.
According to their documentation, the Tailscale container can be attached to our proxy container, allowing us to access all the apps through the proxy server.
For this example, I'm going to duplicate my Caddy proxy configuration and Docker Compose files to separate them from the non-Tailscale version.
I'll shut down the old Caddy Docker Compose setup and use this new version going forward.
The Docker Compose file is the same as the normal Caddy version, except that we've added a Tailscale service.
Starting off, we declare the proxy-net Docker network, which connects the proxy to our self-hosted apps.
We also declare volumes to persist data for both the Caddy and Tailscale containers.
There's a configuration file for Caddy located in the same directory.
For the Caddy service, I'm using my own custom-compiled version of Caddy that includes plugins that support popular DNS providers like Cloudflare for automatically obtaining certificates.
We connect this service to the proxy-net Docker network.
And publish ports 80 and 443 for HTTP and HTTPS.
We then link the configuration defined in our local directory to the config path inside the container.
For volumes, we use the caddy volume to persist Caddy data like certificates.
In the environment section, we include the DNS_PROVIDER_TOKEN that's defined in the .env file.
In my case, I'm using a Cloudflare API token for Caddy's automatic HTTPS feature.
Now, let's move on to the new Tailscale service.
This service uses the official Tailscale image.
In the environment variables, we first need an Auth key for signing in to Tailscale.
We'll generate this key in the admin portal and fill it into the .env file.
The next environment specifies where the container should persist data.
The TS_USERSPACE environment configures whether to use user-space networking instead of kernel networking—here, we set it to false.
The network_mode configuration is very important.
We must set it to “service:caddy-tailscale”, which means this container will share the network stack with the Caddy container.
This is because Tailscale works best when everything we want to access is on the localhost of the VPN node.
In the volumes section, we first map the tailscale volume to the path where we persist Tailscale data.
The second volume maps the host's tunnel network device to the container so it can use the host system's tunneling capabilities.
Finally, we need to add NET_ADMIN and SYS_MODULE capabilities to this container so it can establish the VPN connection.
Now, let's go to the Tailscale admin panel to generate an Auth key.
We'll navigate to Settings, then find Keys under Personal Settings.
Click on Generate Auth Key...
By default, the key is valid for a single use, which means you'll need a new key to sign in again if you sign out of the Tailscale Docker container—for example, when you run docker compose down.
The key is valid for 90 days, but remember, this key is for signing in, not for keeping the VPN node active.
Once you've signed in, your Tailscale node will remain active even after those 90 days.
So, let's go ahead and generate the key.
Copy the key and paste it into your .env file for the TS_AUTH_KEY variable.
Now, we can start our Docker Compose setup to connect our home server to Tailscale.
First, I'll bring down my old Docker Compose configuration.
Then, in the new directory that contains the Docker Compose files for both Caddy and Tailscale, we'll run: docker compose up -d.
After it starts, we can head back to the Tailscale admin portal, and we'll see there's a new machine listed.
The machine name is auto-generated and might not be very readable.
We can rename it to something more user-friendly in the detailed view.
Next, I want to make sure that the VPN setup doesn't interfere with access from my home network.
So, from my laptop—which isn't connected to the VPN—I'll try to access one of my self-hosted apps.
And it works as expected!
Now, I want to check if the VPN is working, and let’s start with something simple.
I'll add a simple "Hello World" endpoint in my Caddy configuration, using the domain name assigned by Tailscale.
We can find this domain name in the machine detailed page.
If the VPN is set up correctly, my phone should be able to access this simple site.
To refresh the Caddy configuration, we'll need to restart the Docker Compose.
We have to restart the entire Docker Compose stack instead of just the Caddy container because Tailscale is bound to the same network stack.
After that's done, let's try accessing the Tailscale endpoint from the browser on my phone.
And there it is—the "Hello World" page appears, which means our Tailscale VPN is set up correctly!
At this point, we still can't access our self-hosted apps through their usual domain names.
That's because our home server has different IP addresses on the home network and on the Tailscale network.
In my case, the home network IP is 192.168.1.101, and the Tailscale network IP is 100.98.112.126.
In my existing setup, I use public DNS to resolve all the home.easyselfhost.com domains to the home network IP.
So, we need another DNS server to resolve our domains to the Tailscale IP address when we're connected to VPN.
Tailscale supports assigning a custom DNS server for the VPN, but we still need to host that DNS server ourselves.
If you've watched my previous videos, you'll know that we can use AdGuard Home or Pi-hole as DNS servers.