๐ Exposing a Dockerized Python App on a Raspberry Pi Using Tailscale Funnel
As a developer hosting lightweight services on a Raspberry Pi, exposing them securely to the public internet can be tricky. Tools like ngrok or port forwarding either expire quickly, require fiddly router setup, or open up security holes.
Thatโs where Tailscale comes in. Recently, I stumbled across it while looking for a simple, secure way to expose a Python app running in Docker on my Raspberry Pi and I was seriously impressed.
In this guide, Iโll walk you through how I used Tailscale Funnel to host a Dockerized Python app at https://mypiapp.example.com.
Table of contents
๐ง Why Tailscale?
Tailscale creates a peer-to-peer mesh VPN using WireGuard under the hood. But it doesnโt stop at private networking. With the release of Tailscale Funnel, you can securely expose services to the public internet without any port forwarding or dynamic DNS.
Benefits:
-
๐ End-to-end encryption
-
๐ No port forwarding needed
-
๐ Free tier supports Funnel
-
๐ ๏ธ Custom domain support
๐๏ธ Our Setup
Weโll expose a Flask-based Python app running inside a Docker container on a Raspberry Pi.
Requirements:
-
Raspberry Pi (or any Linux device) with Docker installed
-
Tailscale account (Free works fine)
-
A custom domain (e.g. example.com)
-
Access to DNS settings (e.g., Cloudflare, Namecheap)
-
Python Flask app (or similar)
๐ณ Step 1: Dockerize the Python App
Letโs start with a simple Flask app.
app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello from Raspberry Pi!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY app.py .
RUN pip install flask
CMD ["python", "app.py"]
docker-compose.yml
(Optional)
version: '3'
services:
piapp:
build: .
ports:
- '5000:5000'
restart: always
Then build and run:
docker compose up -d --build
Visit http://
To verify Tailscale is running, you can check the status:
tailscale status --json
To get your Tailscale IP address, run:
tailscale ip -4
๐ Step 2: Install & Authenticate Tailscale
Install Tailscale on the Pi:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Open the URL printed in the terminal and authenticate your device.
๐ Step 3: Enable Tailscale Funnel
Enable Funnel (public internet access) for this node:
sudo tailscale funnel enable
Then route public traffic to port 5000:
sudo tailscale serve tcp 443 http://localhost:5000
Boom! Your app is now live on:
https://<your-tailscale-username>.ts.net/
Test it from your phone or another device. It should show your Flask app.
๐ Step 4: Connect a Custom Domain (mypiapp.example.com)
Now the fun part using your own domain.
- Add a CNAME DNS Record Go to your domain registrar and add a CNAME:
Type: CNAME
Host: mypiapp
Value: <your-tailscale-username>.ts.net
TTL: Auto or 5 min
If your DNS provider doesnโt support CNAME
at the root domain, you can use a subdomain like mypiapp.example.com
.
- Configure HTTPS Tailscale will automatically provision a Letโs Encrypt certificate for your .ts.net domain, but your custom domain still points there via CNAME so youโre covered.
To verify:
curl -v https://mypiapp.example.com
๐ Optional: Make Tailscale Serve Permanent
By default, tailscale serve is ephemeral. To persist it:
Create a tailscale serve config file using [tailscale up --advertise-exit-node
+ ACLs], or
Use [tailscale serve --bg
] with systemd or a startup script.
A simple systemd
service might look like:
[Unit]
Description=Tailscale Funnel for Pi App
After=network.target
[Service]
ExecStart=/usr/bin/tailscale serve tcp 443 http://localhost:5000
Restart=always
[Install]
WantedBy=multi-user.target
Save this as /etc/systemd/system/tailscale-funnel.service
, then:
sudo systemctl enable --now tailscale-funnel
๐ Done! Youโre Live. Youโve now got:
โ A Dockerized Python app โ Hosted on your Raspberry Pi โ Exposed via HTTPS using Tailscale โ Accessible from https://mypiapp.example.com without opening any ports
๐ง Final Thoughts
Tailscale Funnel is an absolute game-changer for developers running services on edge devices like Raspberry Pi. Itโs dead simple, secure, and domain-friendly all without poking holes in your firewall.
If youโre tired of fragile port forwarding, try this setup. It just works.