Now that we have Headscale installed as part of our Build your own homelab series, we need to configure it to accept connections. We also want to add a reserve proxy setup, and we want to install an SSL certificate. There is a lot to do, let’s get to it.
Step 1: Headscale Configuration Files
If we look back at our helper script page (https://community-scripts.github.io/ProxmoxVE/scripts?id=headscale), we will see that they state where the config file is located:
This is the file we need to edit. If you are not logged in to your Proxmox instance, open a new browser window and navigate to your Proxmox install and log in. Expand the Datacenter
node in the left navigation window and select the Headscale LXC that was created. In the middle navigation pane, select to open an integrated console. From the main window, where the console opened, run the following command to get to the correct directory:
cd /etc/headscale/
There we need to edit our config file, so open the config file in a text editor:
nano config.yaml
You will see YAML markup with the top variables being IP addresses. We need to change them to the correct values. The first variable is server_url, we need to change this to an address that we can remember and that will be set up on our domain (you can also use your dynamic DNS address directly).
For more information, please see the article on Dynamic DNS in our Homelab, as well as the article on getting a domain purchased and set up for our homelab.
We are going to use the domain name vpn.techdecode.online
for our link to Headscale, so change the server_url
variable to (see screenshot below as well):
server_url: https://vpn.techdecode.online
Secondly, we need to change the listen_addr
variable as well. In the comments above it, it will state that we need to change it to 0.0.0.0:8080 for production, so let’s update that as well:
listen_addr: 0.0.0.0:8080
For the metrics_listen_addr
and grpc_listen_addr
variables, we can leave them as is or change their values to their network IP address values.
We can save this setup with Ctrl+S and then exit with Ctrl+X. Lastly we just need Headscale to restart, so run the command:
systemctl restart headscale.service
Step 2: nginx Configuration
Follow the same steps when we purchased and set up our own domain name for our homelab to set up a new CNAME (or A) record for your chosen name, in our case a CNAME record with the name vpn
(to create vpn.techdecode.online
) and record data being our techdecode.tplinkdns.com
.
From Proxmox, we are done with the Headscale LXC, so select the nginx VM in the left navigation window and open its console from the middle navigation window. To make our session easier, we are first going to elevate to a super user:
sudo su
We will need to enter our password again, but afterwards we will be running as an administrator. Navigate to the nginx config folder:
cd /etc/nginx/sites-available/
Now create a new file, we will name it the same as our domain we are settings up:
nano vpn.techdecode.online
Headscale’s official website has an example of an nginx config we can use – https://headscale.net/0.23.0/ref/integration/reverse-proxy/#nginx However, we still need to get our SSL installed via certbot, so our config will be a bit different (for now)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name vpn.techdecode.online;
location / {
proxy_pass http://192.168.1.250:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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;
}
}
Please remember to change the values for your server_name
to your server and also remember to change the IP address (192.168.1.250
) to the local IP address that your Headscale is running on in your network. Save the file with Ctrl+S and exit with Ctrl+X.
We need to also create a link from this created file to the directory that nginx reads its config from, so run the command (replacing the file name with the file name you used):
ln -s /etc/nginx/sites-available/vpn.techdecode.online /etc/nginx/sites-enabled/
All that is left to do now is restart nginx (or reload the config). First make sure that there isn’t any issues by running:
nginx -t
If everything is ok, reload the config with:
systemctl reload nginx
Step 3: Get an SSL Certificate installed
Follow the same steps when we got our domain set up to get an SSL certificate set up. We will need to run:
certbot --nginx
which will display a list of all the domains set up. Select the vpn domain we selected in the previous step and wait for certbot to install the SSL certificate. If there are any issues, please just remember that a domain name change can take a few hours to complete, so you might need to wait for certbot to update and get informed of your new vpn domain name.
Once installed, we need to go back to our nginx configuration file and update it according to the official documentation. Follow step 2 again to open the file, you will see settings that certbot added, including a redirect:

We need to change the entire config file to the same that the official docs state
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name vpn.techdecode.online;
location / {
proxy_pass http://192.168.1.250:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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;
}
ssl_certificate /etc/letsencrypt/live/vpn.techdecode.online/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/vpn.techdecode.online/privkey.pem; # managed by Certbot
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
ssl_protocols TLSv1.2 TLSv1.3;
}
Remember to save and reload nginx.
Conclusion
That is all there is to it to set up and configure Headscale. This was a bit of a more intricate article, but we need to get our security and config set up correctly to ensure our success with Headscale. We are, after all, going to be using it for a second layer of security to access our homelab services from outside of our network, so we really need to make sure that everything is set up correctly. Tomorrow we will set up our phone/computer to access the VPN from the internet, so then we will have our own (FREE) VPN service!