Short answer: No, not for serious production workloads.
Tailscale Funnel is excellent for what it is — a quick, zero-config way to expose a local service to the internet. But it has hard limitations that make it unsuitable for production:
| Limitation | Why It Matters |
|---|---|
| Your URL is tied to your Tailscale machine name | You can't use a custom domain like myapp.com |
| Single machine only | No load balancing, no failover |
| Tailscale is a dependency | If Tailscale's infrastructure has an outage, your app goes down |
| Not designed for high traffic | No CDN, no DDoS protection, no caching |
| No SLA | Tailscale Funnel is a convenience feature, not an infrastructure product |
| Certificate tied to Tailscale | You can't bring your own TLS cert |
Tailscale Funnel is perfect for: demos, internal tools, hobby projects, sharing a dev server with a client temporarily. Stop there.
The standard production stack for a self-hosted app (on a VPS, mini PC, or home server) is:
User's Browser
│ HTTPS (your domain, e.g. myapp.com)
▼
Cloudflare ◄─── DNS + DDoS protection + CDN + TLS termination
│ HTTP or HTTPS (proxied)
▼
Your Server (public IP)
│
▼
nginx ◄─── Reverse proxy, port 80/443
│
▼
Node.js app :3000
The three core components are:
myapp.comBuy a domain from any registrar: Namecheap, Cloudflare Registrar (cheapest, no markup), Porkbun, Google Domains (now Squarespace).
Cloudflare Registrar (cloudflare.com/products/registrar) sells at wholesale cost — recommended if you're already using Cloudflare.
Cloudflare acts as your DNS provider and sits as a reverse proxy in front of your server. This gives you:
1. Create a free Cloudflare account at cloudflare.com
2. Add your domain
3. Update your domain's nameservers
aria.ns.cloudflare.com4. Add a DNS A record pointing to your server
A@ (root domain) or www5. Set SSL/TLS mode
Even with Cloudflare handling the browser-facing TLS, your server needs its own certificate for the Cloudflare → server leg (required for Full Strict mode).
Certbot is the standard tool for getting free Let's Encrypt certificates.
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d myapp.com -d www.myapp.com
Certbot will:
Verify auto-renewal works:
sudo certbot renew --dry-run
After Certbot runs, your nginx config will look like this:
server {
listen 80;
server_name myapp.com www.myapp.com;
return 301 https://$host$request_uri; # redirect HTTP → HTTPS
}
server {
listen 443 ssl;
server_name myapp.com www.myapp.com;
ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
# Cloudflare recommended: only allow Cloudflare IPs
# (optional but hardens your server)
include /etc/nginx/cloudflare-ips.conf;
deny all;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_cf_connecting_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
}
Note:
$http_cf_connecting_ip— when Cloudflare proxies traffic, the real client IP comes in theCF-Connecting-IPheader. Use this instead of$remote_addrso your app logs real IPs, not Cloudflare's.
In production, your Node app must restart automatically if it crashes or the server reboots. Use PM2:
npm install -g pm2
# Start your app
pm2 start server.js --name myapp
# Save the process list and enable startup on boot
pm2 save
pm2 startup # follow the printed instruction to register with systemd
PM2 gives you:
pm2 logs myapp)pm2 reload myapp)pm2 monit)[ ] Buy a domain (Cloudflare Registrar recommended)
[ ] Point domain nameservers to Cloudflare
[ ] Add A record in Cloudflare DNS → your server IP (Proxied)
[ ] Set Cloudflare SSL/TLS to Full (strict)
[ ] Install Certbot on server, get Let's Encrypt certificate
[ ] Configure nginx with TLS + reverse proxy to your app
[ ] Optionally restrict nginx to Cloudflare IPs only
[ ] Use PM2 (Node) or systemd to keep your app running
[ ] Set up PM2 startup script for auto-start on reboot
This setup assumes your server has a static public IP. A mini PC at home or on a local network typically sits behind a home router with:
If that's the case, your options are:
| Option | How |
|---|---|
| Rent a cheap VPS (recommended) | DigitalOcean/Hetzner/Vultr from ~$4–6/month. Deploy your app there instead. Static IP included. |
| Cloudflare Tunnel | Like Tailscale Funnel but Cloudflare-grade. No public IP needed, works behind CGNAT, ties into your own domain. Free tier available. |
| Port forwarding + DDNS | Forward port 80/443 on your router to this PC. Use a DDNS service (Cloudflare DDNS, DuckDNS) to keep your domain pointing at your dynamic IP. Fragile. |
If you want to keep using this mini PC but need production-grade infrastructure, Cloudflare Tunnel is the right tool — it's essentially Tailscale Funnel but:
# Install cloudflared
winget install Cloudflare.cloudflared
# Authenticate
cloudflared tunnel login
# Create a tunnel
cloudflared tunnel create myapp
# Route your domain to the tunnel
cloudflared tunnel route dns myapp myapp.com
# Run the tunnel (points to your local Node app)
cloudflared tunnel run --url http://localhost:3000 myapp
Then run as a Windows service so it starts on boot:
cloudflared service install
Your app becomes available at https://myapp.com — fully proxied through Cloudflare, with all the DDoS protection, TLS, and analytics that comes with it.