DropVPS Team
Writer: Cooper Reagan
how to install v2ray websocket tls on debian 12

Table of Contents
What you will read?
- 1 Step 1 — Prerequisites and DNS
- 2 Step 2 — Update Debian 12.11 and install base tools
- 3 Step 3 — Install Nginx
- 4 Step 4 — Prepare variables
- 5 Step 5 — Create HTTP server block and webroot
- 6 Step 6 — Issue Let’s Encrypt TLS certificate (webroot)
- 7 Step 7 — Install V2Ray core
- 8 Step 8 — Configure V2Ray (VMess over WebSocket)
- 9 Step 9 — Nginx TLS reverse proxy for WebSocket
- 10 Step 10 — Start and enable V2Ray
- 11 Step 11 — Configure UFW firewall
- 12 Step 12 — Create a client profile
- 13 Step 13 — Enable certificate auto-renew
- 14 Step 14 — Quick troubleshooting
Deploying V2Ray with WebSocket over TLS on Debian 12.11 improves privacy, reliability, and CDN compatibility. The stack uses Nginx for TLS termination and V2Ray for VMess over WebSocket. A valid domain and DNS A record are required. Commands assume root or sudo privileges and ports 80/443 open on the server firewall.
Step 1 — Prerequisites and DNS
Set a fully qualified domain (e.g., v2.example.com) with an A record pointing to your server’s public IP. Confirm DNS resolution before moving on.
dig +short v2.example.com
curl -I http://v2.example.com
Step 2 — Update Debian 12.11 and install base tools
Bring the system current and install required utilities. This ensures predictable behavior and available dependencies.
apt update && apt -y upgrade
apt -y install curl gnupg2 ca-certificates lsb-release ufw jq
Step 3 — Install Nginx
Nginx will handle TLS and reverse proxy WebSocket traffic to V2Ray on localhost. Install and enable the service.
apt -y install nginx
systemctl enable --now nginx
nginx -t && systemctl status nginx --no-pager
Step 4 — Prepare variables
Set environment variables to avoid mistakes. Replace the domain and email with your own. Choose a secret WebSocket path.
export DOMAIN="v2.example.com"
export EMAIL="[email protected]"
export WS_PATH="/ray"
export V2_PORT="10000"
export UUID="$(cat /proc/sys/kernel/random/uuid)"
Step 5 — Create HTTP server block and webroot
Configure a minimal HTTP site for ACME webroot validation. This keeps certificate issuance simple and repeatable.
mkdir -p /var/www/${DOMAIN}
chown -R www-data:www-data /var/www/${DOMAIN}
cat >/etc/nginx/sites-available/${DOMAIN}.conf <<'EOF'
server {
listen 80;
listen [::]:80;
server_name DOMAIN_PLACEHOLDER;
root /var/www/DOMAIN_PLACEHOLDER;
location / {
return 200 "OK\n";
add_header Content-Type text/plain;
}
location ^~ /.well-known/acme-challenge/ { }
}
EOF
sed -i "s/DOMAIN_PLACEHOLDER/${DOMAIN}/g" /etc/nginx/sites-available/${DOMAIN}.conf
ln -s /etc/nginx/sites-available/${DOMAIN}.conf /etc/nginx/sites-enabled/${DOMAIN}.conf
nginx -t && systemctl reload nginx
Step 6 — Issue Let’s Encrypt TLS certificate (webroot)
Obtain a valid certificate using Certbot with webroot mode. Certificates will be stored under /etc/letsencrypt/live/DOMAIN.
apt -y install certbot
certbot certonly --webroot -w /var/www/${DOMAIN} -d ${DOMAIN} --agree-tos -m ${EMAIL} --no-eff-email --non-interactive
ls -l /etc/letsencrypt/live/${DOMAIN}
Step 7 — Install V2Ray core
Use the official FHS installer from v2fly to install V2Ray with systemd units placed correctly.
curl -fsSL https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh | bash
v2ray version
Step 8 — Configure V2Ray (VMess over WebSocket)
Bind V2Ray on localhost with VMess over WebSocket. Set your UUID and WebSocket path. TLS is handled by Nginx.
cat >/usr/local/etc/v2ray/config.json <<EOF
{
"log": {
"access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log",
"loglevel": "warning"
},
"inbounds": [{
"listen": "127.0.0.1",
"port": V2_PORT_PLACEHOLDER,
"protocol": "vmess",
"settings": {
"clients": [
{ "id": "UUID_PLACEHOLDER", "alterId": 0 }
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "WS_PATH_PLACEHOLDER",
"headers": { "Host": "DOMAIN_PLACEHOLDER" }
}
}
}],
"outbounds": [
{ "protocol": "freedom" },
{ "protocol": "blackhole", "tag": "blocked" }
]
}
EOF
sed -i "s/V2_PORT_PLACEHOLDER/${V2_PORT}/g" /usr/local/etc/v2ray/config.json
sed -i "s#WS_PATH_PLACEHOLDER#${WS_PATH}#g" /usr/local/etc/v2ray/config.json
sed -i "s/UUID_PLACEHOLDER/${UUID}/g" /usr/local/etc/v2ray/config.json
sed -i "s/DOMAIN_PLACEHOLDER/${DOMAIN}/g" /usr/local/etc/v2ray/config.json
mkdir -p /var/log/v2ray
chown -R nobody:nogroup /var/log/v2ray
/usr/local/bin/v2ray -test -config /usr/local/etc/v2ray/config.json
Step 9 — Nginx TLS reverse proxy for WebSocket
Create an HTTPS server block that upgrades WebSocket connections and proxies to V2Ray on localhost. Keep a basic index for camouflage.
cat >/etc/nginx/sites-available/${DOMAIN}-tls.conf <<'EOF'
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name DOMAIN_PLACEHOLDER;
ssl_certificate /etc/letsencrypt/live/DOMAIN_PLACEHOLDER/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_PLACEHOLDER/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
root /var/www/DOMAIN_PLACEHOLDER;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location WS_PATH_PLACEHOLDER {
proxy_redirect off;
proxy_pass http://127.0.0.1:V2_PORT_PLACEHOLDER;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
listen [::]:80;
server_name DOMAIN_PLACEHOLDER;
return 301 https://$host$request_uri;
}
EOF
sed -i "s/DOMAIN_PLACEHOLDER/${DOMAIN}/g" /etc/nginx/sites-available/${DOMAIN}-tls.conf
sed -i "s#WS_PATH_PLACEHOLDER#${WS_PATH}#g" /etc/nginx/sites-available/${DOMAIN}-tls.conf
sed -i "s/V2_PORT_PLACEHOLDER/${V2_PORT}/g" /etc/nginx/sites-available/${DOMAIN}-tls.conf
ln -s /etc/nginx/sites-available/${DOMAIN}-tls.conf /etc/nginx/sites-enabled/${DOMAIN}-tls.conf
# Optional cover page
echo "<h1>${DOMAIN}</h1>" >/var/www/${DOMAIN}/index.html
nginx -t && systemctl reload nginx
Step 10 — Start and enable V2Ray
Start V2Ray and enable autostart. Confirm the service is healthy.
systemctl enable --now v2ray
systemctl status v2ray --no-pager
ss -tulpn | grep -E "(:80|:443|:${V2_PORT})"
● v2ray.service - V2Ray Service
Loaded: loaded (/etc/systemd/system/v2ray.service; enabled)
Active: active (running) since ...
Main PID: 1234 (v2ray)
Step 11 — Configure UFW firewall
Allow SSH, HTTP, and HTTPS. Block everything else by default if needed.
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
ufw status
Step 12 — Create a client profile
Use the generated values to add a VMess profile in v2rayN, v2rayNG, or Qv2ray. Replace placeholders with your variables.
Type: VMess
Address: v2.example.com
Port: 443
UUID: YOUR_UUID
Security: auto
Transport: WebSocket
WS Path: /ray
SNI/Host: v2.example.com
TLS: enabled
ALPN: http/1.1
VMess link example:
vmess://BASE64({
"v": "2",
"ps": "v2ray-ws-tls",
"add": "v2.example.com",
"port": "443",
"id": "YOUR_UUID",
"aid": "0",
"scy": "auto",
"net": "ws",
"type": "none",
"host": "v2.example.com",
"path": "/ray",
"tls": "tls",
"sni": "v2.example.com",
"alpn": "http/1.1"
})
Step 13 — Enable certificate auto-renew
Certbot sets a systemd timer by default. Verify timers and simulate a renewal to ensure no downtime.
systemctl list-timers | grep certbot
certbot renew --dry-run
systemctl reload nginx
Step 14 — Quick troubleshooting
Check logs and connectivity if the client fails to connect. Validate DNS, TLS, WebSocket path, and UUID.
journalctl -u v2ray -e --no-pager
tail -f /var/log/v2ray/error.log
nginx -t && journalctl -u nginx -e --no-pager
curl -I https://${DOMAIN}
curl -svo /dev/null https://${DOMAIN}${WS_PATH} --http1.1 -H "Upgrade: websocket" -H "Connection: Upgrade"
Installation complete: V2Ray with WebSocket + TLS is now running on Debian 12.11 behind Nginx. Keep your UUID private, monitor logs, and renew your certificates on time. For more tutorials, guidance, and to buy various servers with support, visit dropvps.