Skip to content

Instantly share code, notes, and snippets.

@sloppycoder
Last active July 4, 2025 15:50
Show Gist options
  • Select an option

  • Save sloppycoder/68e1a7a325b981e8629a740f4f911953 to your computer and use it in GitHub Desktop.

Select an option

Save sloppycoder/68e1a7a325b981e8629a740f4f911953 to your computer and use it in GitHub Desktop.
V2Ray setup, server, client and APT setting, etc

Install V2Ray on Debian Linux, including Raspberry Pi OS

Download V2Ray release from V2Fly Github repo, install it using the following steps

# run all below commands as root
# create v2ray user and config directory
mkdir /usr/local/etc/v2ray
useradd --system --no-create-home --shell /usr/sbin/nologin v2ray
chown v2ray:v2ray /usr/local/etc/v2ray
# optional step, create log directory for v2ray
mkdir /var/log/v2ray
chown v2ray:v2ray /var/log/v2ray

# unpack v2ray distro and copy files into place
unzip v2ray-linux-64.zip # adapt your platform
cp v2ray /usr/local/bin/.
cp geo*.dat /usr/local/bin/.
# create config file, see variants below.
cp systemd/system/v2ray.service /etc/systemd/system/.
# edit /etc/systemd/system/v2ray.service to replace user from nobody to v2ray
sed -i 's/nobody/v2ray/' systemd/system/v2ray.service

# optional, get letsentrypt certificate files for v2ray
# copy and adapt config files

# enable v2ray servide and start
systemctl enable v2ray
systemctl start v2ray
systemctl status v2ray

# check logs
cd /var/log/v2ray
tail error.log
# server version that uses vmess, tls
{
"log": {
"access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log",
"loglevel": "info"
},
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "block"
}
]
},
"inbounds": [
{
"port": 443,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "_what_ever_you_set_"
}
]
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"certificates": [
{
"certificateFile": "/usr/local/etc/v2ray/tls/<domain>/fullchain.pem",
"keyFile": "/usr/local/etc/v2ray/tls/<domain>/privkey.pem"
}
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
# the client version, vmess, connects to server 443 using tls
# create a local sock5 server on port 1080.
# v2ray resolve DNS by itself and not rely on local DNS settings
{
"log": {
"access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log",
"loglevel": "info"
},
"dns": {
"servers": ["1.1.1.1"]
},
"routing": {
"domainStrategy": "UseIP"
},
"inbounds": [
{
"port": 1080,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": true
}
},
{
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true // Need to be set as true to accept traffic from iptables
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "server.domain",
"port": 443,
"users": [
{
"id": "_this_id_must_match_whats_on_server",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
# set to true if using IP address and/or self-signed cert on server
"allowInsecure": false
}
}
}
]
}

Get real TLS cert from Letsencrypt, no more self-signed insecure nonsense

this example uses Cloudfare DNS for domain ownership verification

# install certbot and route53 library
sudo apt iinstall -y certbot python3-certbot-dns-cloudflare

# create cloudflare credential file  /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = <your_token>

# get new cert
sudo certbot certonly -v --dns-cloudflare \
    --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
    -d <domain_name>
    
# agree to t&c and enter email etc
# the cert will be downloaded to /etc/letsencrypt directory
# from where you can copy to /usr/local/etc/v2ray/tls directory
# and use in v2ray config file

# renew cert
sudo certbot renew --dns-cloudflare \
     --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
     -d <domain_name> \
     --preferred-challenges=dns

Optionally, use ddclient to update Cloudfare DNS

# /etc/ddclient.conf
daemon=300
syslog=yes
pid=/var/run/ddclient.pid
ssl=yes
use=web
web='https://cloudflare.com/cdn-cgi/trace'
web-skip='ip='

protocol=cloudflare, \
zone=<dns_zone>
ttl=1,
password='<your_api_token>'
<server.dns.name>
# /etc/apt/apt.conf.d/01proxy
# get updates via a local V2Ray socks5 proxy
Acquire::http::Proxy "socks5h://127.0.0.1:1080/";
Acquire::https::Proxy "socks5h://127.0.0.1:1080/";
export ALL_PROXY="socks5h://127.0.0.1:1080"
#!/bin/bash
# after installing RaspAP, use these rules to redirect all traffic coming from Wifi to v2ray
# adjust ip addresses according to your installation
function v2ray() {
# v2ray transparent proxy rules
iptables -t nat -N V2RAY
iptables -t nat -A V2RAY -d 10.0.0.0/8 -j RETURN
iptables -t nat -A V2RAY -d 192.168.0.0/16 -j RETURN
iptables -t nat -A V2RAY -d 127.0.0.0/8 -j RETURN
iptables -t nat -A V2RAY -d 224.0.0.0/4 -j RETURN
iptables -t nat -A V2RAY -d 240.0.0.0/4 -j RETURN
# Directly connect SO_MARK to 0xff traffic (0xff is a hexadecimal number
iptables -t nat -A V2RAY -p tcp -j RETURN -m mark --mark 0xff
# make sure the v2ray client has inboud protocol dokodemo-door enabled
iptables -t nat -A V2RAY -p tcp -j REDIRECT --to-ports 12345
iptables -t nat -A PREROUTING -i wlan0 -s 10.3.141.0/24 -p tcp -j V2RAY
# redirect pi's own traffic
iptables -t nat -A OUTPUT -p tcp -j V2RAY
}
function flush_all() {
# delete V2RAY chain
iptables -t nat -X V2RAY
# delete all nat rules first
iptables -t nat -F
}
flush_all
# raspap traffic
iptables -t nat -A POSTROUTING -s 10.3.141.0/24 -o eth0 -j MASQUERADE
if [ "$1" = "v2ray" ]; then
v2ray
fi
curl --socks5-hostname 127.0.0.1:1080 -o /dev/null -s -w "Connect: %{time_connect}s, FirstByte: %{time_starttransfer}s, Total: %{time_total}s\n" https://google.com
curl -L --socks5-hostname 127.0.0.1:1080 -o /dev/null -s -w "Speed: %{speed_download} bytes/sec\n" https://github.com/v2fly/v2ray-core/releases/download/v5.30.0/v2ray-linux-64.zip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment