V2Ray Websocket Server Behind Cloudflare’s CDN In Docker


In this guide, I’ll show how to start a V2Ray Websocket server behind Cloudflare’s CDN all inside a Docker container.


Before We Start


This will only proxy HTTP/s traffic and isn’t meant to replace a VPN.

The purpose of this is to bypass VPN blocks and firewalls that block VPS providers IP addresses.

V2Ray with Cloudflare’s CDN isn’t fast, so don’t expect to game, this is meant for standard usage which will be fine.

Your traffic will look like you’re connecting to a website, so it will be difficult to block.

I’m not a security expert and I don’t know how secure this truley is.

Buying A VPS


  • I will be buying Vultr they offer a decent server for a cheap price.
  • If you plan to use something other than Vultr make sure it’s a reliable, reputable service.

Let’s start by going to Vultr’s website and making a new account.

  • Vultr offers $250 USD in credit for free to new customers here.

On your homepage at the top right there will be a “Deploy” button, press that, and press deploy new server.

I’ll be deploying the cheapest option for $5 USD this should be enough for most people, you’ll get 1TB of bandwidth monthly.

Select “Cloud Compute – Shared CPU”.

Select the location, for fast speeds and low ping the closest location to you will be the best.

Choosing the OS is up to you, just pick a standard Linux distribution, I’ll use “Rocky Linux 9”.

For the plan, select “Regular Cloud Compute” and choose the cheapest option. If you get an offer like I did, say “No Thanks”.

On “Additional Features” disable “Auto Backups” then enable “IPv6” and “Limited User Login” which will save you the hassle of creating a user account.

For “Server Settings” you can ignore this, the distribution you chose should have a built-in firewall already.

Give the server a hostname and label, this can be whatever you want.

The last thing to do is hit deploy at the bottom.

The server will start deploying, you can see that after you click on the “Compute” tab to the left.

Your Domain


Buy your domain from Cloudflare if you can because it’s the most convenient option.

If you don’t want to buy from Cloudflare, NameCheap or Porkbun are viable alternatives.

Try buying a “.com” or “.net” domain because they are less suspicious.

After you’ve bought the domain, enable WHOIS privacy.

Cloudflare’s CDN


If you bought your domain from Cloudflare, go to your dashboard and your domain will be under “websites” on the top left.

Otherwise, if you bought your domain from another registrar, sign up for Cloudflare, click the websites tab then “Get started” to add your domain.

After you added the domain select the free tier, this will always be free.

Now you’ll need to point your domain to your VPS IP address. if you bought from Cloudflare you can do this in “DNS > Records” on the side panel.

  • Make sure the “Proxy Status” is “Proxied” otherwise you won’t be behind the CDN.

Add “A” and “AAAA” the “Name” can be set to “@” as for the IP addresses, make sure they point to your VPS IP which can be found by clicking your VPS in Vultr’s “Compute” tab.

On the next step, Cloudflare will need to add their nameservers, that’s registrar specific, so I won’t provide instructions, look it up for your registrar.

Cloudflare will take a while to add your domain behind their CDN.

Setting Everything Up


SSH Into The VPS

With MacOS or Linux, you can SSH into your VPS by using the terminal.

On Windows, the recommended SSH tool is PuTTY, but PowerShell also has SSH.

Before you SSH into the VPS, you’ll need the IP and the user password.

Head over to the “Compute” tab and click on your VPS name.

You’ll see the VPS IP address for IPv4 and IPv6 also your user account information.

In terminal, run ssh YOURSERVERIP@linuxuser and enter your password.

Downloading Docker

First update the system, if you chose Rocky Linux 9 run sudo dnf upgrade.

After you updated you need to install Docker but don’t install it from your distribution’s repository because it’s usually outdated.

Instead, go to Dockers Install page and follow the instructions.

Once Docker installed, follow the instructions on Dockers post-installation page.

Configuring For Docker

Run mkdir data then run mkdir data/{v2ray,nginx,ssl}.

Now run nano docker-compose.yml. Inside nano copy and paste what I’ve left below then save and exit.

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    restart: unless-stopped
    networks:
      pwnnet:
        ipv4_address: 172.20.0.10
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./ssl:/etc/ssl
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - v2ray

  v2ray:
    image: ghcr.io/xtls/xray-core:latest
    container_name: v2ray
    restart: unless-stopped
    networks:
      pwnnet:
        ipv4_address: 172.20.0.20
    command: run -c /etc/v2ray/config.json
    volumes:
      - ./v2ray/config.json:/etc/v2ray/config.json
    expose:
      - "10000"

networks:
  pwnnet:
    ipam:
      driver: default
      config:
        - subnet: "172.20.0.0/16"

This is a Docker compose file and will run both Nginx and V2ray inside Docker on its own network.

Running V2ray and Nginx on its own Docker network will make things more isolated from other potential Docker containers and the system.

Configuring V2ray

Run nano data/v2ray/config.json.

Inside nano copy and paste what I’ve left below, but you will have to generate a random UUID, you can do that here.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
            {
            "port": 10000,
            "listen": "172.20.0.20",
            "protocol": "vless",
            "settings": {
                "clients": [
                    {
                        "id": "", # PLACE YOUR UUID BETWEEN "".
                        "level": 0
                    }
                ],
                "decryption": "none"
            },
            "streamSettings": {
                "network": "ws",
                "security": "none",
                "wsSettings": {
                    "path": "/v2ray"
                }
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "freedom"
        }
    ]
}

Save and exit.

Configuring Nginx

Run nano data/nginx/default.conf. Copy and paste what I’ve left below but don’t forget to change “server_name” to your domain.

server {
	listen 443 ssl;
	listen [::]:443 ssl;
	server_name yourdomain.com; #CHANGE THIS TO YOUR DOMAIN

	index index.html;
	root /var/www/html;
	ssl_certificate /etc/ssl/cloudflare-origin-cert.pem;
	ssl_certificate_key /etc/ssl/cloudflare-origin-key.key;
	ssl_client_certificate /etc/ssl/authenticated_origin_pull_ca.pem;
	ssl_verify_client on;
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
	
	location /v2ray {
	if ($http_upgrade != "websocket") {
		return 404;
	}
        proxy_pass http://172.20.0.20:10000;
	proxy_redirect off;
        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_read_timeout 5d;
    }
}

Save and exit.

Getting SSL Certificates

Go to your Cloudflare dashboard.

On the side panel, click “SSL/TLS > Overview”.

On the page, select “Full (strict)” this will encrypt the data between Cloudflare’s CDN and your VPS.

Go to “SSL/TLS > Origin Server”

Under “Origin Certificates” click create certificate.

Continue with the default options.

Keep the key format as “PEM” then copy the “Origin Certificate” and “Private Key” into a text editor temporarily.

Back up the private key because Cloudflare only lets you download it this once.

In your VPS, run nano data/ssl/cloudflare-origin-cert.pem and copy and paste your “Origin Certificate”.

Next run nano data/ssl/cloudflare-origin-key.key and copy and paste your “Private Key”.

Lastly run nano data/ssl/authenticated_origin_pull_ca.pem and paste what I’ve left below, this certificate is the same for everyone. If you don’t trust me, you can download it from Cloudflare here.

-----BEGIN CERTIFICATE-----
MIIGCjCCA/KgAwIBAgIIV5G6lVbCLmEwDQYJKoZIhvcNAQENBQAwgZAxCzAJBgNV
BAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMRQwEgYDVQQLEwtPcmln
aW4gUHVsbDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEjMCEGA1UEAxMab3JpZ2luLXB1bGwuY2xvdWRmbGFyZS5uZXQwHhcNMTkx
MDEwMTg0NTAwWhcNMjkxMTAxMTcwMDAwWjCBkDELMAkGA1UEBhMCVVMxGTAXBgNV
BAoTEENsb3VkRmxhcmUsIEluYy4xFDASBgNVBAsTC09yaWdpbiBQdWxsMRYwFAYD
VQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMSMwIQYDVQQD
ExpvcmlnaW4tcHVsbC5jbG91ZGZsYXJlLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAN2y2zojYfl0bKfhp0AJBFeV+jQqbCw3sHmvEPwLmqDLqynI
42tZXR5y914ZB9ZrwbL/K5O46exd/LujJnV2b3dzcx5rtiQzso0xzljqbnbQT20e
ihx/WrF4OkZKydZzsdaJsWAPuplDH5P7J82q3re88jQdgE5hqjqFZ3clCG7lxoBw
hLaazm3NJJlUfzdk97ouRvnFGAuXd5cQVx8jYOOeU60sWqmMe4QHdOvpqB91bJoY
QSKVFjUgHeTpN8tNpKJfb9LIn3pun3bC9NKNHtRKMNX3Kl/sAPq7q/AlndvA2Kw3
Dkum2mHQUGdzVHqcOgea9BGjLK2h7SuX93zTWL02u799dr6Xkrad/WShHchfjjRn
aL35niJUDr02YJtPgxWObsrfOU63B8juLUphW/4BOjjJyAG5l9j1//aUGEi/sEe5
lqVv0P78QrxoxR+MMXiJwQab5FB8TG/ac6mRHgF9CmkX90uaRh+OC07XjTdfSKGR
PpM9hB2ZhLol/nf8qmoLdoD5HvODZuKu2+muKeVHXgw2/A6wM7OwrinxZiyBk5Hh
CvaADH7PZpU6z/zv5NU5HSvXiKtCzFuDu4/Zfi34RfHXeCUfHAb4KfNRXJwMsxUa
+4ZpSAX2G6RnGU5meuXpU5/V+DQJp/e69XyyY6RXDoMywaEFlIlXBqjRRA2pAgMB
AAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1Ud
DgQWBBRDWUsraYuA4REzalfNVzjann3F6zAfBgNVHSMEGDAWgBRDWUsraYuA4REz
alfNVzjann3F6zANBgkqhkiG9w0BAQ0FAAOCAgEAkQ+T9nqcSlAuW/90DeYmQOW1
QhqOor5psBEGvxbNGV2hdLJY8h6QUq48BCevcMChg/L1CkznBNI40i3/6heDn3IS
zVEwXKf34pPFCACWVMZxbQjkNRTiH8iRur9EsaNQ5oXCPJkhwg2+IFyoPAAYURoX
VcI9SCDUa45clmYHJ/XYwV1icGVI8/9b2JUqklnOTa5tugwIUi5sTfipNcJXHhgz
6BKYDl0/UP0lLKbsUETXeTGDiDpxZYIgbcFrRDDkHC6BSvdWVEiH5b9mH2BON60z
0O0j8EEKTwi9jnafVtZQXP/D8yoVowdFDjXcKkOPF/1gIh9qrFR6GdoPVgB3SkLc
5ulBqZaCHm563jsvWb/kXJnlFxW+1bsO9BDD6DweBcGdNurgmH625wBXksSdD7y/
fakk8DagjbjKShYlPEFOAqEcliwjF45eabL0t27MJV61O/jHzHL3dknXeE4BDa2j
bA+JbyJeUMtU7KMsxvx82RmhqBEJJDBCJ3scVptvhDMRrtqDBW5JShxoAOcpFQGm
iYWicn46nPDjgTU0bX1ZPpTpryXbvciVL5RkVBuyX2ntcOLDPlZWgxZCBp96x07F
AnOzKgZk4RzZPNAxCXERVxajn/FLcOhglVAKo5H0ac+AitlQ0ip55D2/mf8o72tM
fVQ6VpyjEXdiIXWUq/o=
-----END CERTIFICATE-----

Firewalld Portforward

If you are using Rocky Linux 9 run sudo firewall-cmd –zone=public –permanent –add-service={http,https} && sudo firewall-cmd –reload.

Starting everything Up

Make sure you are in the data directory we made, by running cd data.

Run docker compose up -d or docker-compose up -d Docker will pull everything then start running the containers.

After you’ve finished I recommend securing your server.

If you need something simpler then check out my posts for shadowsocks-rust or IVPN.

Leave a Comment

Your email address will not be published. Required fields are marked *