Fault-tolerant firewall for Docker containers with Tailscale integration.
- Tailscale-only access by default: Docker containers accessible only via Tailscale network
- IPv4 and IPv6 protection: Blocks unauthorized access on both protocols
- Localhost preserved: Containers can access localhost and communicate with each other
- Configurable public ports: Expose specific ports to the public internet
- Multi-interface security: Allowlist approach blocks ALL interfaces except explicitly allowed
- Auto-detection: Automatically detects Tailscale interfaces and Docker bridge interfaces
- Interface-based security: Uses kernel-determined interface matching (cannot be spoofed)
- Fault-tolerant: Health checks with automatic rule refresh and recovery every 5 minutes
- Safe service stop: Firewall rules remain in place if service stops/crashes
curl -fsSL https://raw.githubusercontent.com/rlgrpe/docker-tailscale-guard/main/install.sh | sudo bashConfiguration: /etc/docker-tailscale-guard.conf
Or with wget:
wget -qO- https://raw.githubusercontent.com/rlgrpe/docker-tailscale-guard/main/install.sh | sudo bashgit clone https://github.com/rlgrpe/docker-tailscale-guard.git
cd docker-tailscale-guard
sudo ./install.shRe-run the installer — it updates the script and systemd units while preserving your configuration in /etc/docker-tailscale-guard.conf.
curl -fsSL https://raw.githubusercontent.com/rlgrpe/docker-tailscale-guard/main/install.sh | sudo bashOr from a local clone:
cd docker-tailscale-guard
git pull
sudo ./install.shAfter update, verify:
sudo systemctl status docker-tailscale-guard
sudo docker-tailscale-guard.sh statuscurl -fsSL https://raw.githubusercontent.com/rlgrpe/docker-tailscale-guard/main/uninstall.sh | sudo bash| Mode | Tailscale | Localhost | Public Ports | WAN |
|---|---|---|---|---|
guarded |
✓ | ✓ | Configured | ✗ |
locked |
✓ | ✓ | ✗ | ✗ |
open |
✓ | ✓ | ✓ | ✓ |
Default: Tailscale-only (no public ports exposed)
Edit /etc/docker-tailscale-guard.conf to expose public ports:
# TCP ports to expose publicly (default: none)
PUBLIC_TCP_PORTS=80,443
# UDP ports to expose publicly (default: none)
PUBLIC_UDP_PORTS=443Then reload:
sudo systemctl restart docker-tailscale-guard# Show status and current rules
sudo docker-tailscale-guard.sh status
# Apply firewall rules
sudo docker-tailscale-guard.sh apply [guarded|locked|open]
# Run health check
sudo docker-tailscale-guard.sh health# Check service status
sudo systemctl status docker-tailscale-guard
# Restart (re-apply rules)
sudo systemctl restart docker-tailscale-guard
# View logs
sudo journalctl -u docker-tailscale-guard -fUses the DOCKER-USER iptables chain with an allowlist approach:
- Allow established connections
- Allow Tailscale interface
- Allow loopback (localhost)
- Allow Docker bridge interfaces (
docker0,br-*) - Allow configured public ports
- Drop everything else
Interface matching (-i) is kernel-determined and cannot be spoofed by remote attackers.
The health timer runs every 5 minutes and re-applies rules before running health checks. This automatically picks up new Docker networks and bridge interfaces without manual intervention.
tailscale status
# If needed, manually specify:
export TS_IFACE=tailscale0
sudo docker-tailscale-guard.sh applysudo iptables -L DOCKER-USER -n -v
sudo ip6tables -L DOCKER-USER -n -vMIT