As we all know, headscale can solve some limitations of Tailscale, such as the number of devices. However, deploying headscale requires a public IP. Recently, Tailscale's Funnel entered beta testing, and I happened to come across an article by a master that uses Tailscale's Funnel to expose a locally deployed headscale to the public network: Using Tailscale without using Tailscale. This means that we can use Tailscale to allow people to access our deployed headscale over the internet, and only use headscale to join devices to the node. It feels a bit like betraying the Tailscale official, poor Tailscale, only three seconds.
Next, let's briefly introduce the steps.
- Start the latest stable version of Tailscale on any of your local machines.
Installation command:
curl -fsSL https://tailscale.com/install.sh | sh
- Start a headscale, here I use docker-compose for deployment. I mostly referred to the official tutorial. Additionally, I separately started a webui for easy viewing.
version: '3.8'
services:
headscale:
image: 'headscale/headscale:latest'
container_name: headscale
volumes:
- /data/docker/headscale/config:/etc/headscale/
environment:
- TZ=Asia/Shanghai
ports:
- '9090:9090'
- '8080:8080'
restart: always
command: headscale serve
headscale-webui:
image: ghcr.io/ifargle/headscale-webui:latest
container_name: headscale-webui
restart: always
ports:
- '8083:5000'
environment:
- TZ=Asia/Shanghai
- COLOR=red # Use the base colors (ie, no darken-3, etc) -
- HS_SERVER=http://headscale:8080 # Reachable endpoint for your Headscale server
- DOMAIN_NAME=http://headscale-webui:5000 # The base domain name for this container.
- SCRIPT_NAME=/admin # This is your applications base path (wsgi requires the name "SCRIPT_NAME"). Remove if you are hosing at the root /
- KEY="" # Generate with "openssl rand -base64 32" - used to encrypt your key on disk.
- AUTH_TYPE= # AUTH_TYPE is either Basic or OIDC. Empty for no authentication
- LOG_LEVEL=info # Log level. "DEBUG", "ERROR", "WARNING", or "INFO". Default "INFO"
# ENV for Basic Auth (Used only if AUTH_TYPE is "Basic"). Can be omitted if you aren't using Basic Auth
- BASIC_AUTH_USER=user # Used for basic auth
- BASIC_AUTH_PASS=pass # Used for basic auth
# ENV for OIDC (Used only if AUTH_TYPE is "OIDC"). Can be omitted if you aren't using OIDC
- OIDC_AUTH_URL=https://auth.$DOMAIN/.well-known/openid-configuration # URL for your OIDC issuer's well-known endpoint
- OIDC_CLIENT_ID=headscale-webui # Your OIDC Issuer's Client ID for Headscale-WebUI
- OIDC_CLIENT_SECRET=YourSecretHere # Your OIDC Issuer's Secret Key for Headscale-WebUI
volumes:
- /data/docker/headscale/web-ui/data:/data # Headscale-WebUI's storage. Make sure ./volume is readable by UID 1000 (chown 1000:1000 ./volume)
- /data/docker/headscale/config/:/etc/headscale/:ro # Headscale's config storage location. Used to read your Headscale config.
- Then execute the Tailscale funnel command to expose headscale to the public network.
tailscale serve tls-terminated-tcp:443 tcp://127.0.0.1:8080
tailscale funnel 443 on
# Certificate authentication
tailscale cert [assigned domain]
- Use other clients
For iOS, you can now customize the login server by filling in your own headscale address in the settings.
For other platforms, use the following command directly:
tailscale login --login-server https://xxx.xxx.ts.net