#linux #network #homelab #securityThis guide explains how to set up a VPN tunnel using Wireguard and NGINX to securely connect your homelab to the internet without opening ports on your router. Youโll need a domain and a VPS with a static public IP. The VPS will forward traffic to your home network via TLS passthrough, while your homelab server connects to the VPS without requiring any port forwarding (see Figure). This setup provides secure, remote access while keeping your internal network shielded.

Firewall Setup
The following ports must be open on the Server (VPS):| Port | Protocol | Service |
| 80 | TCP | HTTP |
| 443 | TCP | HTTPS |
| 22 | TCP | SSH (best to restrict access to specific IPs) |
| 51820 | UDP | WireGuard |
The following ports must be open on the Client (Home Proxy):| Port | Protocol | Service |
| 80 | TCP | HTTP |
| 443 | TCP | HTTPS |
| 22 | TCP | SSH (best to restrict access to specific IPs) |
Example commands using ufw:sudo ufw allow in on wg0 from 172.31.0.1 to any port 80 proto tcp
sudo ufw allow in on wg0 from 172.31.0.1 to any port 433 proto tcp
Generate Keys (CLIENT, SERVER)
To start, generate the keys for both the client and server. Store them securely (the location is not critical). Run the following commands:sudo su
mkdir /etc/wireguard/keys && cd /etc/wireguard/keys/
umask 077; wg genkey | tee private | wg pubkey > public
chmod 600 /etc/wireguard/keys/private # Only root can read/write
Create WireGuard Config (CLIENT, SERVER)
Server Configuration: /etc/wireguard/wg0.conf[Interface]
Address = 172.31.0.1/32
MTU = 1420 # Adjust message size (important)
SaveConfig = true
ListenPort = 51820 # Ensure port 51820 is open on your VPS
PrivateKey = <server priv-key> # The server's private key
[Peer]
PublicKey = <client1 pub-key> # The client's public key
AllowedIPs = 172.31.0.2/32
# To add more clients (peers), use the following format:
# [Peer]
# PublicKey = <client2 pub-key>
# AllowedIPs = 172.31.0.3/32
Client Config: /etc/wireguard/wg0.conf[Interface]
PrivateKey = <client priv-key>
Address = 172.31.0.2/32
MTU = 1360 # Adjust message size (important)
[Peer]
PublicKey = <server pub-key>
Endpoint = <server pub ip>:51820
AllowedIPs = 172.31.0.1/32
PersistentKeepalive = 25
On both:sudo wg-quick up wg0 # Starting the interfaces
sudo systemctl enable wg-quick@wg0 # Enable WireGuard at boot
To verify the VPN connection, you can ping the server's internal IP from the client or vice versa.~ ยป ping 172.31.0.1
PING 172.31.0.1 (172.31.0.1) 56(84) bytes of data.
64 bytes from 172.31.0.1: icmp_seq=1 ttl=64 time=31.6 ms
64 bytes from 172.31.0.1: icmp_seq=2 ttl=64 time=31.0 ms
This concludes the VPN Tunnel Setup.
Setup TSL Pass-Through with NGINX
Before configuring TLS pass-through, you must enable IPv4 forwarding.Enable IPv4 Forwarding
To enable IPv4 forwarding, edit the /etc/sysctl.conf file and either add the following line:net.ipv4.ip\_forward\=1
Or, if the line already exists, simply uncomment it by removing the # at the beginning. After saving your changes, apply the new configuration by running:sudo sysctl-p
Install NGINX with the ngx_stream_core_module
On Debian-based distributions, the recommended way to install this is by running:sudo apt install nginx-full
Edit Config
Base config that includes the passthrough.conf: /etc/nginx/nginx.confuser www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log warn;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 75;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
include /etc/nginx/passthrough.conf;
Streaming module config: /etc/nginx/passthrough.confstream {
# Define upstream backend servers
upstream syslaf-http {
server 172.31.0.2:80 max_fails=3 fail_timeout=10s;
}
upstream syslaf-https {
server 172.31.0.2:443 max_fails=3 fail_timeout=10s;
}
# Configure logging format and log file locations
log_format basic '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time" '
'"$request"';
access_log /var/log/nginx/syslaf_access.log basic;
error_log /var/log/nginx/syslaf_error.log;
# Configure server blocks for listening on specified ports
server {
listen 80;
proxy_pass syslaf-http; # Forward HTTP traffic to syslaf-http
}
server {
listen 443;
proxy_pass syslaf-https; # Forward HTTPS traffic to syslaf-https
# Uncommented since only one backend server is there currently
# proxy_next_upstream on;
}
}Tighten access for the log files- Allow root full access
- Allow only users in the adm group to read logs (e.g., admins, log rotation tools)
- Block regular users
sudo chmod 640 /var/log/nginx/syslaf_*.log
sudo chown root:adm /var/log/nginx/syslaf_*.log