From time to time, I require a static IP for testing specific firewall rules. Unfortunately, my ISP does not offer static IPs, but I have access to a VPS with a static public IP. Therefore, my idea was to route my traffic through the VPS so that all outgoing requests would appear from a static IP address.
Here is a brief tutorial on how to achieve this using headscale, an open-source, self-hosted implementation of the Tailscale control server.
VPS#
Install headscale#
Follow the docs. For my Debian VPS:
export HEADSCALE_VERSION=0.28.0
export HEADSCALE_ARCH=amd64
wget --output-document=headscale.deb "https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
sudo apt install ./headscale.debConfigure headscale#
My setup is rather basic. Refer to the Documentation for all options and explanations.
/etc/headscale/config.yaml---
server_url: https://example.com
listen_addr: 127.0.0.1:8989
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v6: fd7a:115c:a1e0::/48
v4: 100.64.0.0/10
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
urls:
- https://controlplane.tailscale.com/derpmap/default
paths: []
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
log:
format: text
level: info
dns:
magic_dns: false
nameservers:
global:
- 1.1.1.1
- 1.0.0.1
- 2606:4700:4700::1111
- 2606:4700:4700::1001
database:
type: sqlite
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"Configure Nginx#
Headscale only listens on localhost because my Nginx instance handles all incoming traffic and manages HTTPS certificates via certbot. The following snippet omits the auto-generated HTTPS configuration.
/etc/nginx/sites-available/example.com.confmap $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
access_log /var/log/nginx/scale.access.log;
error_log /var/log/nginx/scale.error.log;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8989;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection $connection_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $server_name;
proxy_redirect http:// https://;
proxy_buffering off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
}
}Enable and start service#
The installed deb package includes a systemd config.
systemctl enable --now headscale
systemctl status headscale
# logs
journalctl -xeu headscale.serviceIP Forwarding#
By default, Debian does not forward traffic so we need to enabled it:
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
sysctl -pInstall tailscale#
Yes, we need tailscale installed as well! (Docs)
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list
apt update
apt install tailscaleSetup a Exit node#
From the tailscale docs
You can route all your public internet traffic by setting a device on your network as an exit node. When you route all traffic through an exit node, you’re effectively using default routes (0.0.0.0/0, ::/0), similar to how you would if you were using a typical VPN.
which is exactley what we want 😊
headscale users create max.mustermann # create a user to associate our nodes with
tailscale up --login-server https://example.net --advertise-exit-node
headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0 # "1" is the node identifierClient config#
Follow the instructions for your platform to install tailscale on your client.
tailscale login --login-server https://example.net
# Authenticate your client
tailscale set --exit-node neu # name of the new node

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.