Setting Up Nginx with SSL on Proxmox for Tailscale Subdomains
Running a home lab on Proxmox is a great way to self-host services, but keeping track of multiple IPs and ports can get complicated. To simplify access to services, I set up custom subdomains hosted on Cloudflare that are easy to remember and restricted to my private Tailscale network.
With Nginx, Cloudflare, and Tailscale, each service in my home lab now has its own memorable, SSL-secured, private URL. Here’s how I configured my setup.
Step 1: Install Necessary Software on Proxmox PVE Host
Update the System:
sudo apt update && sudo apt upgrade -y
Install Certbot and Cloudflare DNS Plugin:
sudo apt install certbot python3-certbot-dns-cloudflare -y
Install Nginx:
sudo apt install nginx -y
Step 2: Configure Cloudflare for DNS Verification
- Log in to your Cloudflare dashboard.
- Create an API Token:
- Navigate to My Profile > API Tokens.
- Create a new token with the following settings:
- Zone: DNS - Edit
- Zone Resources: Include specific zones (your domains).
- Copy the generated token.
Store the API Token Securely:
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.ini
Add the following to the file:
dns_cloudflare_api_token = YOUR_API_TOKEN
Secure the file:
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
Step 3: Create a DNS A Record in Cloudflare
For each new subdomain:
- Create an A Record:
- Name:
<subdomain>.yourdomain.com
(e.g.,service.yourdomain.com
). - Content: Use any public IP—this doesn't need to point to your actual server, as we'll update it later. It can even be an IP registered to someone else, since this is a temporary placeholder.
- Proxy Status: Enable Cloudflare proxy (orange cloud) if desired.
- Name:
Verify the DNS Record:
ping <subdomain>.yourdomain.com
Ensure the subdomain resolves to the placeholder public IP.
Step 4: Obtain SSL Certificates
Run Certbot to generate an SSL certificate for the subdomain:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini -d <subdomain>.yourdomain.com
Certificates will be stored at:
/etc/letsencrypt/live/<subdomain>.yourdomain.com/
Step 5: Update Nginx Configuration
- Create or Edit Your Configuration File:
Open your Nginx configuration file or create a new one specifically for your setup:
sudo nano /etc/nginx/sites-available/proxmox
- Add Server Blocks for Your Subdomains:
Include a server block for each subdomain. Replace<subdomain>
,<tailscale-IP>
, and<port>
with the appropriate values:
# Redirect HTTP to HTTPS for <subdomain>.yourdomain.com
server {
listen 80;
server_name <subdomain>.yourdomain.com;
return 301 https://$host$request_uri;
}
# HTTPS server block for <subdomain>.yourdomain.com
server {
listen 443 ssl;
server_name <subdomain>.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/<subdomain>.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<subdomain>.yourdomain.com/privkey.pem;
location / {
proxy_pass http://<tailscale-IP>:<port>;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Optional: Increase timeouts for long connections
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Disable buffering for real-time data
proxy_buffering off;
}
}
- Set the New Configuration as Default:
Disable the default configuration that comes with Nginx:
sudo rm /etc/nginx/sites-enabled/default
Enable your new configuration:
sudo ln -s /etc/nginx/sites-available/proxmox /etc/nginx/sites-enabled/
Step 6: Test and Reload Nginx
If the test is successful, reload Nginx:
sudo systemctl reload nginx
Test the configuration:
sudo nginx -t
Step 7: Update DNS to Tailscale IP
- Return to the Cloudflare dashboard.
- Update the A record for the subdomain:
- Change the Content value from the public IP to the Tailscale private IP (e.g.,
100.X.X.X
).
- Change the Content value from the public IP to the Tailscale private IP (e.g.,
Verify the new DNS record:
ping <subdomain>.yourdomain.com
Ensure it resolves to your Tailscale IP.
Step 8: Verify the Setup
- Open the subdomain in a browser to verify functionality.
Test HTTPS access for the subdomain:
curl -k https://<subdomain>.yourdomain.com
Step 9: Set Up Automatic SSL Renewal
Automate SSL certificate renewal with a cron job:
sudo crontab -e
Add the following line:
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
Notes on SSL and Tailscale IPs
While Tailscale provides a highly secure private network, adding SSL to subdomains ensures that browser connections are treated as secure, eliminating those annoying warnings about "insecure connections." This makes accessing services much more seamless, especially when using modern browsers that enforce HTTPS for many functionalities.
It’s also worth noting that while Tailscale IPs are stable, they’re not static. In rare cases, a Tailscale IP could change, which might require updating the DNS record for the affected subdomain to avoid disruptions.