| name | tailscale-manager |
| description | Manage Tailscale funnels across different ct project instances. Start/stop funnels and route traffic to different docker containers. |
Tailscale Funnel Manager
Purpose
This skill manages Tailscale funnels to expose local docker containers to the internet via Tailscale. Each ct* project runs on a different port, and we use Tailscale funnels to route HTTPS traffic to these local ports.
Port Mapping Pattern
Each ct project uses a specific port pattern:
| Project | API Port | Database Port | Redis Port |
|---|---|---|---|
| ct1 | 8081 | 5431 | 6371 |
| ct2 | 8082 | 5432 | 6372 |
| ct3 | 8083 | 5433 | 6373 |
| ct4 | 8084 | 5434 | 6374 |
| ct5 | 8085 | 5435 | 6375 |
| ct6 | 8086 | 5436 | 6376 |
| ct7 | 8087 | 5437 | 6377 |
| ct8 | 8088 | 5438 | 6378 |
Pattern:
- API:
808Xwhere X is the ct number - Database:
543Xwhere X is the ct number - Redis:
637Xwhere X is the ct number
⚠️ CRITICAL: Only ONE Funnel at a Time
Only one funnel can run on port 443 at a time. You MUST stop the existing funnel before starting a new one.
Foreground vs Background Mode
Tailscale funnels can run in two modes:
Foreground Mode (Default)
sudo tailscale funnel --https=443 8082
Characteristics:
- Runs ONLY while the command is active (ephemeral)
- Automatically closes when you press Ctrl+C or terminal session ends
- Does NOT show in
tailscale funnel status(this is expected!) - Must be restarted after reboot or terminal disconnect
- Good for temporary testing only
- Provides real-time feedback and logging
⚠️ IMPORTANT: tailscale funnel status will show "No serve config" even though the funnel IS working. This is because foreground funnels are ephemeral and don't write persistent configuration. Use ps aux | grep funnel to verify foreground funnels.
⚠️ WARNING: Foreground mode will stop if your terminal session ends. For persistent funnels, use background mode.
Background Mode (Persistent)
sudo tailscale funnel --bg 8082
Characteristics:
- Runs persistently until explicitly stopped
- Shows in
tailscale funnel status✅ - Survives reboots and Tailscale restarts
- Must be stopped with
sudo tailscale funnel --https=443 off - Good for long-running production use
When to use background mode:
- Long-running services
- When you need
tailscale funnel statusto show configuration - Production deployments
- When you want funnel to survive reboots
Managing Funnels
ALWAYS Check Current Status First
sudo tailscale funnel status
Expected output for BACKGROUND mode funnel:
# Funnel on:
# - https://wakeup.tail<hash>.ts.net
#
https://wakeup.tail<hash>.ts.net (Funnel on)
|-- / proxy http://127.0.0.1:8084
Expected output when no background funnel OR foreground funnel running:
# Funnel on:
No serve config
⚠️ "No serve config" does NOT mean no funnel is running! Foreground funnels don't show here. Check processes:
Check Running Funnel Processes
This is the ONLY reliable way to check if a foreground funnel is running:
ps aux | grep -E "tailscale.*funnel" | grep -v grep
Start a Funnel
Option 1: Foreground Mode (Temporary/Testing)
For ct2 (port 8082):
sudo tailscale funnel --https=443 8082
# OR shorter form:
sudo tailscale funnel 8082
For ct4 (port 8084):
sudo tailscale funnel --https=443 8084
# OR shorter form:
sudo tailscale funnel 8084
For any ct project:
# Replace X with the ct number (2, 3, 4, etc.)
sudo tailscale funnel 808X
Option 2: Background Mode (Persistent/Production)
For ct2 (port 8082):
sudo tailscale funnel --bg 8082
For ct4 (port 8084):
sudo tailscale funnel --bg 8084
For any ct project:
# Replace X with the ct number (2, 3, 4, etc.)
sudo tailscale funnel --bg 808X
Stop a Running Funnel
Stopping Background Mode Funnels
Method 1: Clean shutdown (ALWAYS USE THIS FOR BACKGROUND MODE)
sudo tailscale funnel --https=443 off
This properly removes the persistent configuration and stops the background funnel.
Stopping Foreground Mode Funnels
Method 1: Keyboard interrupt (PREFERRED)
Press Ctrl+C in the terminal where the funnel is running.
Method 2: Kill the process
# Find the funnel process
ps aux | grep "tailscale funnel" | grep -v grep
# Kill it (replace PID with actual number)
sudo kill <PID>
Last Resort: Kill Stuck Processes
Only use if the above methods don't work:
# Find stuck funnel processes
ps aux | grep "tailscale funnel" | grep -v grep
# Force kill (replace PIDs with actual numbers)
sudo kill -9 <PID>
⚠️ WARNING: Only kill tailscale funnel processes. NEVER kill the main tailscaled daemon or tailscaled be-child ssh processes.
Switch to a Different Port
MANDATORY WORKFLOW:
Check current status:
sudo tailscale funnel statusStop existing funnel:
sudo tailscale funnel --https=443 offVerify it stopped:
sudo tailscale funnel status # Should show "No serve config"Start new funnel:
sudo tailscale funnel --https=443 8082 # Switch to ct2Verify it started:
sudo tailscale funnel status
Workflow
Recommended: Background Mode (Simplest)
Check current status:
sudo tailscale funnel statusStop any existing funnel:
sudo tailscale funnel --https=443 offStart background funnel:
sudo tailscale funnel --bg 8082 # For ct2Verify it's running:
sudo tailscale funnel status # Should show configuration
Alternative: Foreground Mode (For Testing/Debugging)
⚠️ NOT RECOMMENDED: Foreground funnels stop when terminal disconnects. Use background mode instead.
Check what's currently running:
ps aux | grep "tailscale funnel"Stop any existing funnel:
- Background:
sudo tailscale funnel --https=443 off - Foreground: Press
Ctrl+Corsudo kill <PID>
- Background:
Start a new foreground funnel:
sudo tailscale funnel 8082 # For ct2Verify it's running:
ps aux | grep "tailscale funnel" # Should show process
Note: Keep your terminal open - closing it will stop the funnel.
Common Commands Reference
# List all docker containers with their ports
docker ps --format 'table {{.Names}}\t{{.Ports}}'
# Filter for specific ct project
docker ps --format 'table {{.Names}}\t{{.Ports}}' | grep ct2
# Check tailscale device status
tailscale status
# Get the public URL for your machine
tailscale status | grep $(hostname)
Troubleshooting
"No serve config" But Funnel IS Running
Cause: You're running a foreground funnel, which doesn't show in tailscale funnel status
This is NORMAL and EXPECTED behavior! Foreground funnels are ephemeral and don't write persistent configuration.
How to verify the funnel is actually working:
- Check processes:
ps aux | grep "tailscale funnel" | grep -v grep - Test locally:
curl http://localhost:8082/(or your port) - Test externally:
curl https://wakeup.tail3b4b7f.ts.net/
Solution: If you want the funnel to show in status, use background mode: sudo tailscale funnel --bg 8082
Error: "foreground already exists under this port"
Cause: Another funnel is already running or stuck
Fix:
- Check status:
sudo tailscale funnel status(for background funnels) - Check processes:
ps aux | grep "tailscale funnel" | grep -v grep(for all funnels) - Stop background funnel:
sudo tailscale funnel --https=443 off - Stop foreground funnel:
Ctrl+Corsudo kill <PID> - Start your new funnel
Funnel Stops When Terminal Closes
Cause: You're using foreground mode, which stops when the terminal session ends
Fix: Use background mode for persistent funnels:
sudo tailscale funnel --bg 8082
Funnel Not Accessible
Check if the docker container is running:
docker ps | grep ct2-apiCheck if the port is exposed:
docker ps --format 'table {{.Names}}\t{{.Ports}}' | grep ct2Test local connectivity:
curl http://localhost:8082/healthCheck tailscale funnel status:
tailscale funnel status
Integration with Docker Compose
Each ct project has a compose.override.yaml file that defines its port mappings:
ct2/compose.override.yaml:
services:
api:
ports:
- "8082:80"
ct4/compose.override.yaml:
services:
api:
ports:
- "8084:80"
Health Check
Run these commands to diagnose issues:
# 1. Check funnel status
sudo tailscale funnel status
# 2. Check for orphaned processes
ps aux | grep "tailscale funnel" | grep -v grep
# 3. Check if local services are running
docker ps --format 'table {{.Names}}\t{{.Ports}}'
# 4. Test local connectivity
curl http://localhost:8084/health
# 5. Check tailscale connection
tailscale status | grep wakeup
Quick Reference
# Check background funnel status
sudo tailscale funnel status
# Check ALL funnels (including foreground)
ps aux | grep "tailscale funnel" | grep -v grep
# Start BACKGROUND funnel (RECOMMENDED - persistent, shows in status)
sudo tailscale funnel --bg 8082 # ct2
sudo tailscale funnel --bg 8083 # ct3
sudo tailscale funnel --bg 8084 # ct4
# Start FOREGROUND funnel (NOT RECOMMENDED - stops when terminal closes)
sudo tailscale funnel 8082 # ct2
sudo tailscale funnel 8083 # ct3
sudo tailscale funnel 8084 # ct4
# Stop background funnel (REQUIRED for background mode)
sudo tailscale funnel --https=443 off
# Stop foreground funnel (Ctrl+C or kill process)
# Find PID: ps aux | grep "tailscale funnel" | grep -v grep
sudo kill <PID>
Critical Safety Rules
- Only ONE funnel at a time on port 443 - stop the old one first
- Always use clean shutdown -
sudo tailscale funnel --https=443 offbefore starting new - Run in zellij/tmux - foreground process, needs persistent session
- Never kill main daemon - only kill
tailscale funnelprocesses, nottailscaledortailscaled be-child - Check before starting - always run
sudo tailscale funnel statusfirst
Process Safety
When viewing processes (ps aux | grep tailscale), you'll see:
- Main daemon:
/usr/sbin/tailscaled --state=...(NEVER KILL) - SSH children:
/usr/sbin/tailscaled be-child ssh ...(NEVER KILL) - Funnel processes:
sudo tailscale funnel --https=443 <port>(OK to kill if stuck)
Only manage the funnel-specific processes.
When to Restart Tailscaled
Only as last resort:
sudo systemctl restart tailscaled
Most issues are resolved by properly managing funnel processes.
Notes
- Funnels must be run with
sudoto bind to port 443 (HTTPS) - The
--https=443flag configures the funnel to accept HTTPS traffic on port 443 and route it to the local port - Two modes available:
- Foreground (default): Temporary, doesn't show in status, stops when terminal closes
- Background (
--bg): Persistent, shows in status, survives terminal disconnects and reboots
- RECOMMENDATION: Always use background mode (
--bg) for persistent funnels - The public URL follows the pattern:
https://[machine-name].[tailnet].ts.net - "No serve config" is NORMAL for foreground funnels - use
ps auxto verify them