Laputa

Way back to China

Jing and I used to enjoy Japanese anime on BiliBili during lunch or dinner. However, due to political and commercial restrictions, many resources on Chinese platforms are inaccessible from overseas. Ironically, when we lived in China, we often used VPNs to bypass the GFW and access foreign platforms—now it’s the other way around.

Fortunately, ChatGPT has once again proven to be a great companion for building small tools. With its help, I established a reliable connection that bridges the UK, Germany, and China—without writing a single line of code myself.

TL;DR

uk-cn-link

Setup - Detailed Steps

Prepare VPS and Domain

To begin, I bought two VPS instances: one located in Germany (or any country with good international connectivity) and another in mainland China. The idea is to route traffic through the German VPS, which acts as a relay to the China VPS and ultimately reaches the target services.

At first, I assumed the German VPS might be unnecessary. However, I discovered that direct traffic from my UK PC to the China VPS was blocked, while requests relayed through the German VPS were accepted. This intermediate hop turned out to be crucial.

I purchased both servers on Alibaba Cloud during the 618 promotion, which offered significant discounts and excellent value.

A domain is required because I chose to use Xray with TLS encryption, which improves security. TLS requires a valid certificate issued for a specific domain—IP addresses alone won’t work. You don’t need to spend much; any affordable domain name is sufficient.

Once we have a domain, we need to configure a DNS record to point the domain to our entry point—the German VPS in my case. After that, all requests to the domain will be routed to that server. I recommend using Cloudflare for DNS—it’s fast, reliable, and free.

Why XRay + VLESS + TLS + WebSocket?

To build a secure and reliable bridge to access services in China, this setup uses XRay — a modern, modular proxy platform — along with a stack of transport layers designed to maximize compatibility and stealth.

Let’s break down the components:

VLESS — A Lightweight Transport Protocol

VLESS stands for “Vision Lightweight Extensible Secure System”. It’s a lightweight protocol designed specifically for proxy scenarios, acting as the communication layer between clients and servers.

Key features:

In my case, VLESS defines how the UK client communicates with the Germany VPS, and again from the Germany VPS to the China VPS.

TLS — Encrypting the Traffic

TLS (Transport Layer Security) encrypts the traffic between the client and server, ensuring that:

TLS is required in this setup to make the proxy traffic indistinguishable from normal encrypted web traffic.

WebSocket — Transport Over HTTP

WebSocket (WS) wraps the VLESS traffic inside standard HTTP upgrade requests, making it:

This helps bypass censorship and integrate with CDNs if needed.

Setup China VPS

Let’s configure the China VPS first, as its configurations will be used by the Germany VPS. Although I used x-ui for convenience, this guide will demonstrate how to configure the China VPS manually via XRay for better control and flexibility.

XRay can be installed via its official install script:

1
2
3
$ sudo su # switch to root
$ apt install socat uuidgen -y 
$ bash <(curl -Ls https://raw.githubusercontent.com/XTLS/Xray-install/main/install-release.sh)

Here is a sample configuration for XRay (/usr/local/etc/xray/config.json):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "port": ${INBOUND-PORT},
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": ${CHINA-VPS-UUID},
            "flow": "xtls-rprx-direct"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "ws",
        "security": "none",
        "wsSettings": {
          "path": ${INBOUND-WS-PATH}
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

Note:

Once the configuration is ready, you can manage the Xray service via systemd, which handles service startup, restart, and logging.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Start Xray service
systemctl start xray

# Enable it to auto-start on boot
systemctl enable xray

# Check service status
systemctl status xray

# Restart Xray manually (e.g., after changing config or renewing cert)
systemctl restart xray

# View latest logs (most useful for debugging)
journalctl -u xray -n 20 --no-pager

Xray will read the config from /usr/local/etc/xray/config.json by default. If something goes wrong, always start by checking the log output — for example, certificate issues or incorrect JSON will prevent Xray from starting properly.

Setup Germany VPS

Issue a Valid Certificate

First, let’s generate a valid certificate in preparation for the TLS configuration of Xray. We will use acme.sh, a lightweight and easy-to-use ACME client. To install it:

1
2
$ apt install socat -y
$ curl https://get.acme.sh | sh

Below is a script for issuing a certificate and restarting the Xray service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
ACME=~/.acme.sh/acme.sh

# 1. Configure acme.sh
export CF_Token="YOUR-CF-TOKEN"
export DOMAIN="YOUR-DOMAIN"

# 2. Generate certificate
# Switch to Let's Encrypt (ZeroSSL is the default CA otherwise)
${ACME} --set-default-ca --server letsencrypt
# Perform DNS-based verification by adding a TXT record
${ACME} --issue --dns dns_cf -d ${DOMAIN}

# 3. Install certificate and restart Xray
mkdir -p /etc/xray
${ACME} --install-cert -d ${DOMAIN} \
  --key-file       /etc/xray/cert.key \
  --fullchain-file /etc/xray/cert.crt \
  --reloadcmd      "systemctl restart xray"

# 4. (Optional) Check manually
# systemctl restart xray
# journalctl -u xray -n 20 --no-pager

Note that CF_Token is required to authorize acme.sh to manage DNS records via the Cloudflare API. You can create one in Cloudflare Dashboard → Profile → API Tokens → Generate Token → choose “Edit zone DNS” and select target domain.

It is suggested to run the script periodically to renew the certificate, which can be done via Linux cronjob:

1
45 19 * * * /root/.acme.sh/acme.sh --cron --home /root/.acme.sh > /dev/null 2>&1

Alternatively, acme.sh supports using Cloudflare’s Global API Key for authentication, by setting CF_Key and CF_Email. However, this is not recommended, as the Global API Key grants excessive permissions across all zones.

Setup XRay

Now that we’ve issued a valid TLS certificate, let’s configure Xray to enable secure and efficient proxying between the German and China VPS.

Here’s a sample configuration file /usr/local/etc/xray/config.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "port": 443,
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": ${GENERATED-UUID},
            "level": 0,
            "email": "[email protected]"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "certificates": [
            {
              "certificateFile": "/etc/xray/cert.crt",
              "keyFile": "/etc/xray/cert.key"
            }
          ]
        },
        "wsSettings": {
          "path": ${GERMANY-VPS-INBOUND-WS-PATH}
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": ${CHINA-VPS-IP},
            "port": ${CHINA-VPS-PORT},
            "users": [
              {
                "id": ${CHINA-VPS-UUID},
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings": {
          "path": ${CHINA-VPS-INBOUND-WS-PATH}
        }
      }
    }
  ]
}

Let’s break it down:

Be sure that both inbounds and outbounds are correctly aligned in terms of protocol, path, and encryption — otherwise the handshake will fail.

After setting up the China VPS and Germany VPS, you can check if the connection is working properly. The easiest way to do this is to send a test request to the Germany VPS’s WebSocket endpoint. You can use curl to do this:

1
curl -vk https://${YOUR-DOMAIN}/${YOUR-GERMANY-VPS-INBOUND-WS-PATH}

You should see a response from the server with a status code of 400 Bad Request, which indicates that the connection is working but the request is not valid for the XRay WebSocket protocol. This is expected since we are not sending a valid WebSocket handshake.

Monitor and Notification

The connection from German VPS to China VPS is crucial for the whole link. Thus I hope to monitor and report its connection status periodically. Here ChatGPT helped write a simple script for monitoring and report status via Telegram Bot.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env bash

# -------- SETTINGS --------
TARGET_IP="CHINA-VPS-IP"
TARGET_PORT="CHINA-VPS-PORT"
BOT_TOKEN="YOUR-TG-BOT-TOKEN"
CHAT_ID="YOUR-TG-BOT-CHAT-ID"
LOG_FILE="/var/log/cn_link.log"
STATE_FILE="/tmp/cn_link_state"
OK_INTERVAL=$((30*60))    # 30 min
# --------------------------

ts() { date '+%Y-%m-%d %H:%M:%S'; }

alert() {
  local MSG="$1"
  curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
       -d chat_id="${CHAT_ID}" \
       -d text="$MSG" >/dev/null
}

# --- TCP handshake ---
timeout 5 bash -c "</dev/tcp/${TARGET_IP}/${TARGET_PORT}" 2>/dev/null
STATUS=$?

if [ $STATUS -eq 0 ]; then
  echo "$(ts)  ✅  Connection OK" >> "$LOG_FILE"

  # Was down before? send recovered
  if [ -f "$STATE_FILE" ]; then
    rm -f "$STATE_FILE"
    alert "✅ Connection RESTORED to ${TARGET_IP}:${TARGET_PORT}  ($(ts))"
  else
    # Send periodic heartbeat
    NOW=$(date +%s)
    LAST=$(cat /tmp/cn_ok_last 2>/dev/null || echo 0)
    if (( NOW - LAST >= OK_INTERVAL )); then
      alert "✅ Connection still healthy  ($(ts))"
      echo "$NOW" > /tmp/cn_ok_last
    fi
  fi
  exit 0
fi

# ---- FAILED branch ----
echo "down" > "$STATE_FILE"
MSG="❌ Connection FAILED: Germany VPS cannot reach ${TARGET_IP}:${TARGET_PORT}  ($(ts))"
echo "$MSG" >> "$LOG_FILE"
alert "$MSG"

The check script can also be setup as a cronjob:

1
*/5 * * * * /root/check_cn_link.sh

In this way, we can receive real-time notifications about the connection status — whether it’s healthy, down, or has just recovered.

tgbot-notify

Check Connection

Now that all the configurations are set up properly, you can configure your local machine to use the Germany VPS as a proxy. This can be done by setting up your browser or system proxy settings to point to the Germany VPS’s IP address and port. For example, if are a iPhone user, you can use Shadowrocket to configure the proxy settings.

Via whatismyipaddress.com, you can check if your IP address is the one of your China VPS. If it is, congratulations! You have successfully set up a reliable connection from the UK to China and its time to enjoy your favorite Chinese content.

#GFW #VPS #Xray #Telegram