Connect Django Servers Over a WireGuard Private Network
Use WireGuard to connect Django app servers to PostgreSQL, Redis, and workers across hosts or providers: generate keys, configure wg0 interfaces, bind databases to the tunnel address, restrict firewalls, and keep Django connection settings on private IPs.
Problem statement
Your Django deployment has grown to several servers, perhaps a web server, a database server, and a worker, at a provider without private networking between them, or across two providers. Exposing PostgreSQL and Redis on public IPs with firewall allowlists is fragile and risky. WireGuard creates an encrypted private network between hosts with a few lines of configuration, so Django connects to 10.10.0.2:5432 and nothing listens publicly.
- Install WireGuard on every host and generate a key pair per host.
- Give each host a
wg0address in a private range (for example10.10.0.0/24) and list peers with public keys and endpoints. - Bind PostgreSQL and Redis to the WireGuard address, and add
pg_hba.confrules for the tunnel subnet. - Point Django's
DATABASE_URLandREDIS_URLat the private addresses. - Firewall: allow UDP 51820 between hosts; block database ports on public interfaces.
Step-by-step solution
1. Install and generate keys
On each host:
sudo apt-get install -y wireguard
wg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
sudo chmod 600 /etc/wireguard/private.key
Collect each host's public key; private keys never leave their host.
2. Configure interfaces
On the database server (10.10.0.2):
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.10.0.2/24
ListenPort = 51820
PrivateKey = <db private key>
[Peer]
# web-1
PublicKey = <web-1 public key>
AllowedIPs = 10.10.0.1/32
Endpoint = 203.0.113.10:51820
[Peer]
# worker-1
PublicKey = <worker-1 public key>
AllowedIPs = 10.10.0.3/32
Endpoint = 203.0.113.12:51820
The web server's file mirrors this with its own address and the database as a peer. Bring the interface up and enable it at boot:
sudo systemctl enable --now wg-quick@wg0
sudo wg show
3. Bind services to the tunnel
# postgresql.conf
listen_addresses = 'localhost,10.10.0.2'
# pg_hba.conf
hostssl shop shop 10.10.0.0/24 scram-sha-256
# redis.conf
bind 127.0.0.1 10.10.0.2
requirepass <password>
Start PostgreSQL after WireGuard so the address exists: add After=wg-quick@wg0.service and Requires=wg-quick@wg0.service to a drop-in for the PostgreSQL unit.
4. Point Django at private addresses
DATABASE_URL=postgres://shop:...@10.10.0.2:5432/shop?sslmode=require
REDIS_URL=redis://:...@10.10.0.2:6379/0
WireGuard already encrypts traffic; keeping PostgreSQL TLS on as well protects against misrouting and satisfies compliance requirements that ask for encryption at the application layer.
5. Firewall rules
sudo ufw allow from 203.0.113.0/24 to any port 51820 proto udp
sudo ufw deny 5432
sudo ufw deny 6379
sudo ufw allow in on wg0
Check from the internet that 5432 and 6379 are closed, and from the web server that psql -h 10.10.0.2 works.
Explanation
WireGuard is a kernel-level VPN that authenticates peers with public keys and encrypts traffic with modern cryptography. Each host gets a virtual interface with a private address; AllowedIPs defines which addresses each peer may use, acting as both routing table and access control. Binding PostgreSQL and Redis only to those addresses removes them from the public internet entirely, so Django's connections travel over the tunnel.
Edge cases / notes
- Many hosts. Full-mesh configurations grow quickly; tools like Tailscale, Headscale, or Netmaker manage keys and peers for you.
- MTU. Tunnels reduce the packet size available; if large queries hang, lower the interface MTU (for example
MTU = 1380). - Docker. Containers can reach the tunnel through the host's routing; publish database containers only on the WireGuard address.
Next steps
- Harden hosts further with the Django Server Hardening Checklist.
- For managed mesh networking, see Restrict Django Admin With Tailscale.
- Add web servers with Scale Django Horizontally With a Load Balancer.
FAQ
Is WireGuard fast enough for database traffic?
Yes. It runs in the kernel with low overhead, suitable for PostgreSQL and Redis traffic.
Do I still need PostgreSQL TLS over WireGuard?
It is optional but recommended as defense in depth and for compliance.
How do I add a new web server?
Generate keys, give it an unused address, add it as a peer on the database host, and reload WireGuard.
Should I use Tailscale instead?
Tailscale builds on WireGuard and manages keys and peers automatically, which is easier for more than a few hosts.