Postd




Chaining WireGuard Configurations

Let’s say you have multiple WireGuard configurations and want to chain them together. In this post, we’ll demonstrate how to route traffic through multiple VPN servers using Xray-Core. Our example setup routes traffic through a VPS, then through Proton VPN, and finally through Cloudflare WARP. This creates a traffic flow: Client → VPS → Proton VPN → Cloudflare WARP → Internet.

Prerequisites

Getting the Configurations

🔐 Proton VPN WireGuard Configuration

To get your Proton VPN WireGuard configuration:

  1. Log in to your Proton VPN dashboard
  2. Go to DownloadsWireGuard Configuration
  3. Select a server, generate the config, and download it

☁️ Cloudflare WARP Configuration

To generate a Cloudflare WARP WireGuard config:

  1. Download the latest wgcf binary from the GitHub Releases page

  2. Extract and make the binary executable:

    tar -xzf wgcf_*.tar.gz
    chmod +x wgcf
  3. Register and generate a configuration:

    ./wgcf register
    ./wgcf generate

This creates wgcf-profile.conf — your WARP WireGuard configuration.

Sample Configurations

Proton VPN Config (proton.conf)

[Interface]
# Bouncing = 10
# NetShield = 1
# Moderate NAT = off
# NAT-PMP (Port Forwarding) = off
# VPN Accelerator = on
PrivateKey = kOTPg8NrjXTvIMTHL4aLujsn0de4eKOaY7jrCffQNm0=
Address = 10.2.0.2/32, 2a07:b944::2:2/128
DNS = 10.2.0.1

[Peer]
# US-NY#460
PublicKey = ZZVNP1-7koLM6LPHsd89zOqW7TxWQHyc03wyRHbs82E=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 149.102.226.225:51820

Cloudflare WARP Config (warp.conf)

[Interface]
PrivateKey = qO2Bly_Luo96gNMoyX8WINOPHDmx-ouk4X4Ebt3eYXw=
Address = 172.16.0.2/32, 2606:4700:110:8980:9f47:7d49:48e3:5fab/128
DNS = 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, 2606:4700:4700::1001
MTU = 1280

[Peer]
PublicKey = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = engage.cloudflareclient.com:2408

Setting Up Xray-Core

Installation

First, download and install Xray-Core:

# Download the latest release
wget https://github.com/XTLS/Xray-core/releases/latest/download/Xray-linux-64.zip
unzip Xray-linux-64.zip
chmod +x xray

Configuration

Create the following chained.json configuration file:

{
    "log": {
        "logLevel": "warning"
    },
    "inbounds": [
        {
            "listen": "0.0.0.0",
            "port": 51820,
            "protocol": "wireguard",
            "settings": {
                "secretKey": "SERVER_PRIVATE_KEY_HERE",
                "peers": [
                    {
                        "publicKey": "CLIENT_PUBLIC_KEY_HERE",
                        "allowedIPs": ["0.0.0.0/0"]
                    }
                ],
                "mtu": 1420
            },
            "tag": "wireguard_in"
        }
    ],
    "outbounds": [
        {
            "protocol": "wireguard",
            "tag": "warp",
            "settings": {
                "secretKey": "qO2Bly_Luo96gNMoyX8WINOPHDmx-ouk4X4Ebt3eYXw=",
                "address": [
                    "172.16.0.2/32",
                    "2606:4700:110:8980:9f47:7d49:48e3:5fab/128"
                ],
                "peers": [
                    {
                        "endpoint": "engage.cloudflareclient.com:2408",
                        "publicKey": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="
                    }
                ],
                "mtu": 1280
            },
            "streamSettings": {
                "sockopt": {
                    "dialerProxy": "proton"
                }
            }
        },
        {
            "protocol": "wireguard",
            "tag": "proton",
            "settings": {
                "secretKey": "kOTPg8NrjXTvIMTHL4aLujsn0de4eKOaY7jrCffQNm0=",
                "address": ["10.2.0.2/32", "2a07:b944::2:2/128"],
                "peers": [
                    {
                        "endpoint": "149.102.226.225:51820",
                        "publicKey": "ZZVNP1-7koLM6LPHsd89zOqW7TxWQHyc03wyRHbs82E="
                    }
                ],
                "mtu": 1420
            }
        }
    ],
    "routing": {
        "rules": [
            {
                "type": "field",
                "inboundTag": ["wire_in"],
                "outboundTag": "warp"
            }
        ]
    }
}

Client Configuration

Create a client configuration file to connect to your VPS:

[Interface]
PrivateKey = CLIENT_PRIVATE_KEY_HERE
Address = 10.1.0.2/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY_HERE
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = YOUR_VPS_IP:51820

Note: Generate a new WireGuard key pair for the client:

wg genkey | tee client_private.key | wg pubkey > client_public.key

Running the Setup

  1. Start Xray-Core on your VPS:

    sudo ./xray -c chained.json
  2. Configure firewall rules (if needed):

    sudo ufw allow 51820/udp
    sudo ufw enable
  3. Connect your client using any WireGuard client with the client configuration above.

How It Works

The traffic flow in this setup is:

  1. Client connects to your VPS via WireGuard
  2. VPS (Xray-Core) receives the traffic and routes it to the Proton VPN outbound
  3. Proton VPN forwards traffic to Cloudflare WARP (due to dialerProxy setting)
  4. Cloudflare WARP sends traffic to the Internet

The dialerProxy: "proton" setting in the WARP outbound configuration tells Xray-Core to establish the WARP connection through the Proton VPN tunnel, creating the desired chain.

Troubleshooting

Common Issues

Testing the Chain

You can verify the setup is working by checking your IP address:

curl ifconfig.me

The returned IP should be from Cloudflare’s range, indicating traffic is flowing through the complete chain.

Conclusion

This setup provides enhanced privacy by routing traffic through multiple VPN providers. The combination of Proton VPN and Cloudflare WARP offers both privacy protection and performance benefits.

In future posts, we’ll explore advanced setups including split tunneling, automatic failover, load balancing across multiple servers, and comprehensive DNS leak protection.