Tailscale for Your Proxmox Home Lab: Secure Remote Access to LXC Containers Without Port Forwarding
Development

Tailscale for Your Proxmox Home Lab: Secure Remote Access to LXC Containers Without Port Forwarding

Ricardo Gil
December 30, 2025
8 min read
#Tailscale #Proxmox #Home Lab #Self-Hosting #Remote Access #LXC #Networking #2026

Introduction

Running applications on cloud providers is convenient—until you see the monthly bill. Between compute costs, bandwidth charges, and database fees, a simple side project can easily cost $50-100/month. But what if you already have powerful hardware sitting at home?

Self-hosting gives you complete control, zero recurring costs (except electricity), and the flexibility to experiment without worrying about quotas. The challenge has always been secure remote access. That's where Tailscale changes everything.

In this guide, I'll show you how I self-host my applications using Tailscale for zero-trust networking, making my home lab as accessible as any cloud service—but without the monthly bills.

Why Self-Host?

Before diving into the technical details, let's talk about why self-hosting makes sense:

Cost Savings

My Setup:

  • Beelink GTi13 Ultra mini PC: $799 one-time
  • Intel i9-13900HK processor (24 cores)
  • 64GB DDR5 RAM
  • 1TB NVMe SSD
  • Power consumption: ~65W under load

Cloud Equivalent:

  • AWS EC2 r6i.4xlarge: ~$700/month
  • 16 vCPUs, 128GB RAM
  • Plus: EBS storage, bandwidth, data transfer

Break-even: Less than 2 months. After that, pure savings.

Complete Control

  • No arbitrary limits on CPU, RAM, or bandwidth
  • Install anything without vendor restrictions
  • Access raw logs and system metrics
  • Customize networking however you need
  • Keep your data physically in your possession

Learning Opportunity

Self-hosting forces you to understand:

  • Linux system administration
  • Networking fundamentals
  • Security best practices
  • Database management
  • Backup strategies

These skills make you a better engineer, period.

The Traditional Problem: Port Forwarding Hell

Before Tailscale, self-hosting meant dealing with:

Security Nightmares

bash
# The old way: exposing ports to the internet
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT  # SSH exposed!

Every open port is an attack surface. SSH brute force attempts, automated scanners, and bot traffic constantly hammering your server.

Network Complexity

  • Router port forwarding configuration
  • Dynamic DNS for changing home IP
  • Certificate management for HTTPS
  • Firewall rules on router AND server
  • VPN setup for secure access

It works, but it's fragile and time-consuming to maintain.

Enter Tailscale: Zero-Trust Networking

Tailscale creates a secure overlay network using WireGuard. Each device gets a private IP address (100.x.y.z range), and all traffic is encrypted point-to-point.

How It Works

code
┌─────────────┐         ┌──────────────┐         ┌─────────────┐
│   Laptop    │         │   Tailscale  │         │  Home Lab   │
│ 100.1.2.3   │────────▶│  Coordinator │◀────────│ 100.1.2.4   │
└─────────────┘         └──────────────┘         └─────────────┘
        │                                                │
        └────────────────────────────────────────────────┘
                 Encrypted WireGuard Tunnel

Key points:

  • No port forwarding required
  • No public IP exposure
  • Zero-trust by default
  • Automatic NAT traversal
  • Encrypted everything

Setting Up Tailscale

Step 1: Install Tailscale

On your home server (Ubuntu/Debian):

bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

On your laptop:

Both devices now appear in your Tailscale network!

Step 2: Enable IP Forwarding (Optional)

If you want your server to act as an exit node:

bash
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Then advertise as exit node:

bash
sudo tailscale up --advertise-exit-node

Step 3: Set Up Magic DNS

Tailscale provides automatic DNS for your devices:

bash
# Instead of remembering IPs:
ssh 100.1.2.4

# Use friendly names:
ssh homelab.tail-scale.ts.net

Enable in the Tailscale admin console under DNS settings.

Deploying Applications

Now the fun part—actually running your applications!

Example 1: PostgreSQL Database

bash
# Install PostgreSQL
sudo apt update
sudo apt install postgresql postgresql-contrib

# Configure to listen on Tailscale IP only
sudo nano /etc/postgresql/16/main/postgresql.conf

Change:

code
listen_addresses = '100.1.2.4'  # Your Tailscale IP

Update authentication:

bash
sudo nano /etc/postgresql/16/main/pg_hba.conf

Add:

code
host    all    all    100.0.0.0/8    scram-sha-256

Restart:

bash
sudo systemctl restart postgresql

Now your database is accessible from any Tailscale device but invisible to the internet!

Example 2: .NET Core Web API

Here's how I deployed my PhotoManagerAPI:

bash
# Publish the application
dotnet publish -c Release -o /var/www/photomanager

# Create systemd service
sudo nano /etc/systemd/system/photomanager.service

Service file:

ini
[Unit]
Description=Photo Manager API
After=network.target

[Service]
Type=notify
User=www-data
WorkingDirectory=/var/www/photomanager
ExecStart=/usr/bin/dotnet /var/www/photomanager/PhotoManagerAPI.dll
Restart=always
RestartSec=10

Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://100.1.2.4:5000

[Install]
WantedBy=multi-user.target

Start the service:

bash
sudo systemctl enable photomanager
sudo systemctl start photomanager

Access from any device: http://homelab.tail-scale.ts.net:5000

Example 3: Docker Containers

Run multiple services with Docker:

yaml
# docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    ports:
      - "100.1.2.4:5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  api:
    build: .
    environment:
      - ConnectionStrings__DefaultConnection=${CONN_STRING}
      - ASPNETCORE_URLS=http://100.1.2.4:5000
    depends_on:
      - postgres

  nginx:
    image: nginx:alpine
    ports:
      - "100.1.2.4:80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

volumes:
  postgres_data:

Deploy:

bash
docker-compose up -d

Advanced Features

ACL Rules

Control who can access what:

json
{
  "acls": [
    {
      "action": "accept",
      "src": ["tag:dev"],
      "dst": ["tag:servers:*"]
    },
    {
      "action": "accept",
      "src": ["user@example.com"],
      "dst": ["homelab:5000,5432"]
    }
  ],
  "tagOwners": {
    "tag:dev": ["user@example.com"],
    "tag:servers": ["user@example.com"]
  }
}

Subnet Routes

Share your entire home network:

bash
sudo tailscale up --advertise-routes=192.168.1.0/24

Now access all home devices through Tailscale!

MagicDNS + HTTPS

Use Tailscale's built-in HTTPS certificates:

bash
tailscale cert homelab.tail-scale.ts.net

Configure your web server:

nginx
server {
    listen 443 ssl;
    server_name homelab.tail-scale.ts.net;
    
    ssl_certificate /root/.tailscale-certs/homelab.tail-scale.ts.net.crt;
    ssl_certificate_key /root/.tailscale-certs/homelab.tail-scale.ts.net.key;
    
    location / {
        proxy_pass http://localhost:5000;
    }
}

Security Best Practices

Even with Tailscale, follow these guidelines:

1. Principle of Least Privilege

bash
# Don't run everything as root
sudo useradd -m -s /bin/bash appuser
sudo chown -R appuser:appuser /var/www/myapp

2. Firewall Configuration

bash
# Only allow Tailscale interface
sudo ufw default deny incoming
sudo ufw allow in on tailscale0
sudo ufw enable

3. Regular Updates

bash
# Auto-update script
cat << 'EOF' > /usr/local/bin/update-system.sh
#!/bin/bash
apt update
apt upgrade -y
apt autoremove -y
systemctl restart tailscaled
EOF

chmod +x /usr/local/bin/update-system.sh

# Add to cron
echo "0 3 * * 0 /usr/local/bin/update-system.sh" | sudo crontab -

4. Backup Everything

bash
# Automated PostgreSQL backup
cat << 'EOF' > /usr/local/bin/backup-db.sh
#!/bin/bash
BACKUP_DIR="/backups/postgres"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR
pg_dump -U postgres photomanager > $BACKUP_DIR/backup_$DATE.sql

# Keep only last 7 days
find $BACKUP_DIR -name "backup_*.sql" -mtime +7 -delete
EOF

chmod +x /usr/local/bin/backup-db.sh
echo "0 2 * * * /usr/local/bin/backup-db.sh" | sudo crontab -

Monitoring and Maintenance

System Monitoring

I use a simple bash script for monitoring:

bash
#!/bin/bash
# /usr/local/bin/system-health.sh

CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
MEM=$(free | grep Mem | awk '{print ($3/$2) * 100.0}')
DISK=$(df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1)

echo "CPU: ${CPU}%"
echo "Memory: ${MEM}%"
echo "Disk: ${DISK}%"

# Alert if any threshold exceeded
if (( $(echo "$CPU > 80" | bc -l) )); then
    echo "WARNING: High CPU usage!"
fi

Application Logs

bash
# View application logs
sudo journalctl -u photomanager -f

# Docker logs
docker logs -f api

# Nginx access logs
tail -f /var/log/nginx/access.log

Cost Comparison

My Self-Hosted Setup:

  • Hardware: $799 (one-time)
  • Electricity: ~$10/month (65W * 24h * $0.15/kWh)
  • Internet: Already paying for it
  • Total Year 1: $919
  • Total Year 2+: $120/year

Equivalent Cloud (AWS):

  • EC2 r6i.2xlarge: $350/month
  • RDS PostgreSQL: $150/month
  • EBS Storage: $30/month
  • Total: ~$530/month = $6,360/year

Savings: $5,441/year after first year

Real-World Use Cases

I currently self-host:

  • PhotoManagerAPI: Photography business management
  • Personal blog: Angular + .NET Core
  • PostgreSQL databases: Multiple projects
  • Development environments: Testing new features
  • Game servers: Occasional Minecraft server for friends

Total monthly cloud cost if hosted elsewhere: ~$800 Actual cost: $10 electricity

Conclusion

Self-hosting with Tailscale gives you cloud-like convenience with none of the recurring costs. The initial setup takes a weekend, but then it just works—securely and reliably.

Is it for everyone? No. If you value your time at $200/hour and hate sysadmin work, cloud hosting makes sense. But if you enjoy learning, want complete control, and have capable hardware, self-hosting is incredibly rewarding.

Key Takeaways:

  • Tailscale eliminates traditional self-hosting complexity
  • Security is actually better than basic cloud setups
  • Cost savings are massive for long-term projects
  • You learn invaluable systems administration skills

Ready to start self-hosting? Install Tailscale, spin up a VM or use old hardware, and deploy your first app. You might never go back to paying monthly cloud bills.

My Setup:

  • Beelink GTi13 Ultra (i9-13900HK, 64GB RAM)
  • Ubuntu 24.04 LTS
  • Docker + Docker Compose
  • PostgreSQL 16
  • Tailscale for networking
  • Automated backups to external drive

Questions about self-hosting? Reach out—I love helping people break free from cloud costs!

Related Posts

Building with Angular + Firebase? Check out my Photography E-Commerce Platform that combines Firebase auth with Stripe payments and AWS S3 storage.

Self-hosting your projects? Learn how I host production apps on a Raspberry Pi with PM2, Nginx, and Tailscale.

About the Author: Ricardo Gil is a full-stack software engineer specializing in .NET/C#, Angular, and cloud platforms. Read more or subscribe for updates.

Want this kind of setup for your business?

I deploy private, self-hosted infrastructure on Proxmox: AI, automation and internal tools on hardware you own, documented and handed off. See the Private AI Stack →

Not sure what you need? Book a free discovery call.

📬Weekly Newsletter

Get the best home lab & AI content

No spam. One email per week. Unsubscribe anytime.

Share this article