
In this post we’ll walk through a stripped-down Dante SOCKS5 setup designed specifically for running WireGuard WARP traffic through a proxy. The idea is simple: we don’t need a full SOCKS proxy that handles every possible connection — just a lean, safe configuration that lets WARP send its UDP packets while blocking everything else. This keeps the setup secure, predictable, and easy to reason about.
Here’s what the setup looks like:
Client (WireGuard) → Dante SOCKS5 (Ubuntu 24) → Cloudflare WARP (UDP/2408)
Canonical Setup (validated)
- IPv4 only – no IPv6 in this config, everything runs on IPv4.
- Listening on 0.0.0.0:1080 – binds to the real network interface so clients see a usable BND.ADDR.
- Username/password authentication – using a system user (danteuser) with no login shell.
- UDP-only SOCKS5 traffic – only UDP ASSOCIATE requests are allowed, and only to the WARP endpoint on port 2408.
- Explicit udpreply rule – makes sure reply packets from the server actually reach the client.
- Everything else blocked – all TCP (CONNECT/BIND) and any other UDP traffic is denied by default.
- No UDP port pinning – Dante dynamically handles reply ports without forcing a fixed range.
Step 1. Install Dante and Create an Auth User
First, update your package list and install Dante:
sudo apt update
sudo apt install -y dante-server
- apt update refreshes the package list.
- apt install -y dante-server installs Dante without asking for confirmation.
Next, create a dedicated system user for authentication. This user won’t have a home directory and can’t log into the server (no shell access), so it’s safe to use only for proxy authentication:
# Create a system user with no home and no shell
sudo useradd --system --no-create-home --shell /usr/sbin/nologin danteuser
# Set a password for this user (you’ll enter it when WireGuard connects through SOCKS5)
sudo passwd danteuser
- –system marks it as a system account.
- –no-create-home skips creating a home directory.
- –shell /usr/sbin/nologin prevents direct login.
Finally, find the network interface Dante should bind to. This is important because Dante needs to know which real interface to use for outgoing traffic:
ip -o -4 route get 1.1.1.1 | awk '{print $5}'
- This queries the routing table for a path to 1.1.1.1 (Cloudflare’s DNS).
- The last field ($5) is your default network interface name.
- On many VPS setups, it will be something like ens3 or eth0. Keep this name handy — we’ll use it in the config file.
Step 2. Configure Dante (Lock to a Single WARP Endpoint)
Now we’ll configure Dante so it only allows UDP traffic to one specific WARP endpoint. This makes the proxy strict and predictable.
📌 Notes before editing:
- Replace ens3 with the network interface you found in the previous step.
- Replace the IP address with the exact WARP endpoint you want to use. Use a /32 mask when locking to a single IP.
- Config file path: /etc/danted.conf
# Log everything to syslog
logoutput: syslog
# Bind Dante to the real interface so UDP ASSOCIATE returns a valid BND.ADDR
internal: ens3 port = 1080
external: ens3
# Require username/password authentication (set earlier)
clientmethod: none
socksmethod: username
# Privilege separation
user.privileged: root
user.notprivileged: nobody
# Who can connect to the proxy (authentication still required at SOCKS stage)
client pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
}
# --- Allow ONLY UDP ASSOCIATE to the WireGuard endpoint on port 2408 ---
socks pass {
from: 0.0.0.0/0
to: 162.159.192.1/32 port = 2408
command: udpassociate
protocol: udp
log: connect disconnect error
}
# --- Allow UDP replies from the endpoint back to the client ---
socks pass {
from: 162.159.192.1/32 port = 2408
to: 0.0.0.0/0
command: udpreply
protocol: udp
log: connect disconnect error
}
# --- Block everything else (TCP and UDP) ---
socks block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: error
}
Alternative (Experimental): Use Hostname Instead of IP
If you’d rather lock to a hostname, Dante supports it — but keep in mind that if DNS resolves to multiple IPs, Dante may use any of them. Replies are expected from the exact IP that was contacted.
# Allow only UDP ASSOCIATE to domain:2408
socks pass {
from: 0.0.0.0/0
to: engage.cloudflareclient.com port = 2408
command: udpassociate
protocol: udp
log: connect disconnect error
}
# Allow UDP replies from the domain:2408
socks pass {
from: engage.cloudflareclient.com port = 2408
to: 0.0.0.0/0
command: udpreply
protocol: udp
log: connect disconnect error
}
👉 Using the literal IP (/32) is safer and recommended because it guarantees Dante only accepts replies from the same address you connected to.
Step 3. Start & Verify Dante
Now that the config is ready, let’s start Dante and make sure it works.
1. Parse Check (Foreground Test)
Before running as a service, confirm the config parses cleanly:
sudo /usr/sbin/danted -f /etc/danted.conf -N -D
- Runs Dante in the foreground with debugging enabled.
- If the config is valid, it will print startup logs and sit waiting.
- Press Ctrl + C to stop.
2. Run as a Service
Enable and start Dante at boot:
sudo systemctl enable --now danted
sudo systemctl --no-pager status danted
enable --now
both starts it immediately and ensures it starts on reboot.status
shows the current state and any startup errors.
Sanity Checks
1. Check if Dante is listening on IPv4 (port 1080):
ss -ltnp | grep :1080
You should see danted
bound to your chosen interface.
2. Confirm TCP is blocked:
curl -v -x socks5h://danteuser:PASS@YOUR_SERVER_IP:1080 https://example.com
This should fail, because CONNECT is disabled — exactly what we want.
3. Watch logs while testing UDP traffic:
sudo journalctl -u danted -f
Keep this running in a terminal while your WireGuard client connects. You’ll see logs for udpassociate
and udpreply
.
(Optional) Quick Packet View
If you want to be extra sure packets are flowing to the right place, capture them on your server’s interface:
IFACE=$(ip -o -4 route get 1.1.1.1 | awk '{print $5}')
sudo tcpdump -ni "$IFACE" "udp and port 2408"
- Replace
IFACE
automatically with your default interface. - You should see UDP packets going to your WARP endpoint on port 2408.
Step 4. Troubleshooting Notes (What Bit Us)
Here are a few gotchas we ran into while testing this setup — if something isn’t working, check these first:
- Parser error near
port
when using a literal IP
→ Dante expects a subnet mask. Always add/32
for single IPs.
Example:to: 162.159.192.1/32 port = 2408
- Client closes after ~5 seconds; logs show
@0.0.0.0.0
→ This happens ifinternal:
is set to0.0.0.0
.
Fix: bind Dante to the real interface name soBND.ADDR
is usable.internal: ens3 port = 1080
- Replies not delivered
→ You need an explicitudpreply
rule restricted to the endpoint. Without it, replies won’t reach the client. - UDP port-range pinning
→ By design, we don’t pin ports. Dante will use ephemeral UDP sockets.
Make sure your host firewall isn’t blocking these. Most stateful firewalls allow return traffic automatically, but double-check if you’ve applied custom rules.
Conclusion & Next Steps
With this setup, Dante acts as a very restricted SOCKS5 proxy that only allows WireGuard WARP’s UDP traffic on port 2408 to pass. Everything else — TCP connections, random UDP flows — is blocked. This makes the proxy simple, predictable, and secure, while still providing the one feature we need: the ability to route WARP through a chosen server.
This post covered the essentials: installing Dante, setting up a minimal UDP-only configuration, verifying that it works, and addressing common pitfalls. In the next part, we’ll take the next step and show how to route WARP traffic through the proxy. That includes advanced scenarios such as changing the apparent country of your WARP connection by running the proxy in different locations — a useful technique for bypassing geo-restrictions on streaming platforms like Netflix.