This is a plugin for [Traefik](https://traefik.io) to build a **feature-rich static file server** as a middleware.
See the forums for further discussion here Make Traefik a powerful and secure rp!
A Traefik middleware plugin that provides secure access control by actually testing Tailscale connectivity rather than relying on unreliable IP address checking. This plugin solves the complex challenge of verifying real Tailscale connections in modern networking environments with a simple, efficient, client-side approach.
Instead of guessing IP addresses, we actually test if the client can reach your Tailscale network:
ā
Real Connectivity Test: JavaScript-based verification that actually tries to connect to your .ts.net domain
ā
Proxy-Agnostic: Works regardless of how many proxies are between client and server
ā
Container-Friendly: No dependency on IP address visibility
ā
Ultra-Fast: Client-side verification with zero server roundtrips
ā
Secure Sessions: Cryptographically secure session tokens after verification
ā
Beautiful UI: Modern, responsive verification interface
ā
Zero Configuration: Works out of the box with minimal setup
Our simplified approach eliminates complex server-side verification endpoints:
.ts.net domain using multiple methodsWhen accessing a protected resource without verification, users see a beautiful verification page that:
# traefik.yml (static configuration)experimental:plugins:tailscale-connectivity:moduleName: github.com/hhftechnology/tailscale-accessversion: v2.0.0
# dynamic-config.yml (dynamic configuration)http:middlewares:tailscale-auth:plugin:tailscale-connectivity:testDomain: "your-company.ts.net" # REQUIRED: Your Tailscale domainsessionTimeout: "24h" # How long verification lastsallowLocalhost: true # Allow localhost for development
http:routers:protected-service:rule: "Host(`internal.company.com`)"service: "my-backend-service"middlewares:- "tailscale-auth"tls: {}
tailscale-connectivity:testDomain: "mycompany.ts.net" # REQUIRED: Your Tailscale domain to test againstsessionTimeout: "24h" # Session validity duration (default: 24h)allowLocalhost: true # Allow localhost bypass for development (default: true)enableDebugLogging: false # Enable debug logging (default: false)
tailscale-connectivity:testDomain: "production.ts.net"sessionTimeout: "8h" # Shorter sessions for productionallowLocalhost: false # No localhost bypass in productionsecureOnly: true # Require HTTPS for cookies (default: true)cookieDomain: ".company.com" # Restrict cookie scopecustomErrorMessage: "Company VPN connection required"successMessage: "VPN verified! Redirecting to dashboard..."
tailscale-connectivity:testDomain: "company.ts.net"customCSS: |/* Company branding */body {background: linear-gradient(135deg, #1e3a8a 0%, #3730a3 100%);}.verification-card {border-top: 5px solid #f59e0b;}.header h1 {color: #1e3a8a;}customScript: |// Custom analytics or additional logicconsole.log('Company Tailscale verification loaded');// gtag('event', 'tailscale_verification_started');
tailscale-connectivity:# RequiredtestDomain: "company.ts.net"# Session ManagementsessionTimeout: "24h" # Duration (e.g., "1h", "30m", "24h")# SecuritysecureOnly: true # HTTPS-only cookiescookieDomain: ".example.com" # Cookie domain restrictionrequireUserAgent: true # Require User-Agent header# DevelopmentallowLocalhost: true # Localhost bypassenableDebugLogging: false # Debug output# CustomizationcustomErrorMessage: "Custom error message"successMessage: "Custom success message"customCSS: "/* Custom styles */"customScript: "/* Custom JavaScript */"
Protect company dashboards, admin panels, and internal APIs:
internal-tools-auth:plugin:tailscale-connectivity:testDomain: "corp.ts.net"sessionTimeout: "8h"allowLocalhost: falsecustomErrorMessage: "Internal tools require corporate VPN access"
Allow both Tailscale and localhost access for development:
dev-auth:plugin:tailscale-connectivity:testDomain: "dev.ts.net"sessionTimeout: "168h" # 1 week for convenienceallowLocalhost: trueenableDebugLogging: true
Different Tailscale networks for different user groups:
# Customer portalcustomer-auth:plugin:tailscale-connectivity:testDomain: "customers.ts.net"sessionTimeout: "4h"customCSS: |.header h1 { color: #2563eb; }body { background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); }# Partner APIpartner-auth:plugin:tailscale-connectivity:testDomain: "partners.ts.net"sessionTimeout: "2h"requireUserAgent: true
version: '3.8'services:traefik:image: traefik:v3.0command:- "--experimental.plugins.tailscale-connectivity.modulename=github.com/hhftechnology/tailscale-access"- "--experimental.plugins.tailscale-connectivity.version=v2.0.0"volumes:- ./config:/etc/traefik/dynamic- /var/run/docker.sock:/var/run/docker.sockports:- "80:80"- "443:443"labels:- "traefik.enable=false"my-app:image: nginx:alpinelabels:- "traefik.enable=true"- "traefik.http.routers.my-app.rule=Host(`app.company.com`)"- "traefik.http.routers.my-app.middlewares=tailscale-auth"- "traefik.http.routers.my-app.tls=true"
apiVersion: traefik.containo.us/v1alpha1kind: Middlewaremetadata:name: tailscale-authspec:plugin:tailscale-connectivity:testDomain: "k8s-cluster.ts.net"sessionTimeout: "12h"allowLocalhost: falsecustomErrorMessage: "Kubernetes access requires Tailscale VPN"---apiVersion: traefik.containo.us/v1alpha1kind: IngressRoutemetadata:name: protected-ingressspec:entryPoints:- websecureroutes:- match: Host(`dashboard.k8s.company.com`)kind: Rulemiddlewares:- name: tailscale-authservices:- name: kubernetes-dashboardport: 443tls:secretName: dashboard-tls
tailscale-connectivity:enableDebugLogging: true
Look for debug output in Traefik logs:
docker logs traefik 2>&1 | grep -i tailscale
ā "testDomain must be configured"
ā Verification always fails
curl -I https://your-domain.ts.net/ā Mixed Content errors in browser console
ā Sessions expire too quickly
sessionTimeout value (e.g., "168h" for 1 week)ā Plugin not loading
tailscale-connectivityVerify your Tailscale domain is accessible:
# From a Tailscale-connected device:curl -I https://your-domain.ts.net/# Should return HTTP 200
Test the verification flow:
Check browser developer tools:
go test -bench=. -benchmemBenchmarkVerifiedRequest-8 5000000 0.05 ms/op 0 B/op 0 allocs/opBenchmarkVerificationPage-8 1000000 1.2 ms/op 4096 B/op 1 allocs/op
customErrorMessage: |š This service requires connection to our company VPN.Please install Tailscale from https://tailscale.com and connect to the 'Company' network.Need help? Contact IT support at support@company.comsuccessMessage: |ā VPN connection verified! Welcome to the secure portal.You'll be redirected automatically in a few seconds.
customCSS: |/* Dark theme */body {background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);color: #fff;}.verification-card {background: #2d2d2d;border: 1px solid #444;}/* Company branding */.tailscale-logo { display: none; }.header::before {content: url('data:image/svg+xml;base64,...'); /* Your logo */display: block;margin: 0 auto 20px;}/* Custom animations */.verification-card {animation: slideUp 0.6s ease-out, glow 2s infinite;}@keyframes glow {0%, 100% { box-shadow: 0 0 20px rgba(59, 130, 246, 0.3); }50% { box-shadow: 0 0 30px rgba(59, 130, 246, 0.6); }}
customScript: |// Analytics trackingif (typeof gtag !== 'undefined') {gtag('event', 'tailscale_verification_started', {'test_domain': testDomain,'page_location': window.location.href});}// Additional security checksif (navigator.userAgent.includes('bot')) {console.warn('Bot detected during verification');}// Custom success handlerwindow.addEventListener('tailscale_verification_success', function() {console.log('Custom verification success handler');});
If you're upgrading from an IP-based version:
# Old IP-based approach:old-tailscale-auth:tailscaleRanges: ["100.64.0.0/10"]additionalRanges: ["10.0.0.0/8"]headersToCheck: ["X-Forwarded-For", "X-Real-IP"]trustedProxies: ["10.0.0.1"]# New connectivity-based approach:tailscale-connectivity:testDomain: "your-domain.ts.net" # Much simpler!sessionTimeout: "24h"allowLocalhost: true
Delete these old configurations:
tailscaleRangesadditionalRangesheadersToChecktrustedProxies# Change from:experimental:plugins:old-tailscale-auth:moduleName: github.com/company/old-plugin# To:experimental:plugins:tailscale-connectivity:moduleName: github.com/hhftechnology/tailscale-access
The new approach works completely differently:
# Basic testsgo test -v ./...# With coveragego test -v -cover ./...# Benchmarksgo test -bench=. -benchmem# Specific test categoriesgo test -v -run TestBasicFunctionalitygo test -v -run TestConfigurationgo test -v -run TestSecurity
Test verification flow:
# Without Tailscale - should show verification pagecurl -v https://your-protected-site.com/# With Tailscale - should work after verificationcurl -v https://your-protected-site.com/
Test localhost bypass:
curl -v http://localhost:8080/protected# Should bypass verification if allowLocalhost: true
We welcome contributions! This plugin is open source and community-driven.
git clone https://github.com/hhftechnology/tailscale-accesscd tailscale-accessgo mod tidymake test
# Run all testsmake test# Run with Yaegi (Traefik's interpreter)yaegi test -v .# Benchmarksgo test -bench=. -benchmem# Integration testsgo test -v -run TestIntegration
When reporting issues, please include:
Apache License 2.0 - see LICENSE file for details.
Ready to secure your services the smart way?
Install the Tailscale Connectivity Authentication plugin and never worry about complex IP detection again! This simplified approach provides rock-solid security with zero configuration headaches. Get started in under 5 minutes with our quick setup guide above!