Appearance
As the saying goes, at least one of your body and mind must be on the road. The body is inside the wall, but the mind doesn't have to. So I'll share some simple solutions.
Prepare
Buy a vps that can be connected directly in China, use Ubuntu 20.04 LTS, and install docker, acme.sh, nginx-full.
sh
sudo apt-get update -y
# docker
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update -y
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER
# acme.sh
sudo apt-get install -y git
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install -m [email protected]
# nginx-full
sudo apt-get install -y nginx-full
Issue certs with acme.sh
sh
sudo mkdir -p /var/www/acmefiles
sudo chown $USER /var/www/acmefiles
acme.sh --issue -d gost.example.com -w /var/www/acmefiles/gost.example.com
acme.sh \
--install-cert -d gost.example.com \
--key-file /etc/nginx/certs/gost.example.com.key \
--fullchain-file /etc/nginx/certs/gost.example.com.cer \
--reloadcmd "sudo nginx -s reload && docker restart gost"
Install gost
sh
USER="aaron1984"
PASS="8d1HTRn1uSjynLpbxg4otZEPnd52DqAX"
DOMAIN="gost.example.com"
PORT=4430
BIND_IP=0.0.0.0
CERT_DIR=/etc/nginx/certs
CERT=/certs/${DOMAIN}.crt
KEY=/certs/${DOMAIN}.key
docker run --name gost \
--net=host \
-v ${CERT_DIR}:/certs:ro \
-d --restart=unless-stopped \
ginuerzh/gost -L "http2://${USER}:${PASS}@${BIND_IP}:${PORT}?cert=${CERT}&key=${KEY}&probe_resist=code:403&knock=www.google.com"
# test
curl -v "https://ip.gs" --proxy "https://${DOMAIN}:4430" --proxy-user "${USER}:${PASS}"
Install shadowsocks
sh
docker run --name ss \
-p 0.0.0.0:1984:1984 \
-d --restart=unless-stopped \
mritd/shadowsocks -s "-s 0.0.0.0 -p 1984 -m chacha20-ietf-poly1305 -k UiGGQvG6TszhLATP --fast-open"
Nginx and gost share 443 port
The server is deployed with nginx for web services and gost for https proxy. Both require port 443. Forwarding directly to gost with proxy_pass
in the nginx configuration does not work. Because proxy_pass
is forwarded at the layer 7 application layer, gost requires raw tcp traffic. So it needs to be forwarded at the layer 4 transport layer, which fortunately nginx supports.
Nginx provides the ngx_stream_ssl_preread_module
module to get the SNI information at layer 4 and then dispatch the traffic. It is not started by default and needs to be started manually.
Nginx provides the ngx_http_realip_module
module to hide known proxy IPs and get the real user IPs.
Nginx supports proxy protocol
, which insert client IPs and ports into tcp traffic.
Ubuntu 20.04 LTS apt install nginx
installs nginx without the above module, so you need to use apt install nginx-full
.
update nginx configurations
/etc/nginx/nginx.conf
# traffic forwarding core configuration
stream {
# Here is the SNI identification, mapping the domain name to a configuration name
map $ssl_preread_server_name $backend_name {
gost.example.com proxy_gost;
default web;
}
# The subsequent virtual host configuration should listen to 44300 instead of 443
upstream web {
server 127.0.0.1:44300;
}
upstream proxy_gost {
server 127.0.0.1:44301;
}
upstream gost {
server 127.0.0.1:4430;
}
# listen to 443 and enable ssl_preread and proxy_protocol
server {
listen 443 reuseport;
listen [::]:443 reuseport;
proxy_pass $backend_name;
proxy_protocol on;
ssl_preread on;
}
# The server here is the middle layer used to unload the proxy protocol for gost
# The original upstream gost configuration does not need to be changed
server {
listen 44301 proxy_protocol;
proxy_pass gost;
}
}
http {
# ... unchanged
}
/etc/nginx/conf.d/web.example.com.conf
server {
listen 44300 ssl http2 proxy_protocol;
server_name web.example.com;
ssl_certificate certs/web.example.com.cer;
ssl_certificate_key certs/web.example.com.key;
# Hide the IP of the forwarding layer and set remote_addr to the real client IP
# Because of this traffic forwarding configuration, which is equivalent to opening another tcp link to this 44300 port at layer 4, the client IP becomes the local IP
# So the proxy_protocol carries the original client ip, and then the following configuration changes the client ip to the real ip instead of the forwarding layer ip.
# If you don't do this, the following ip restrictions won't work either.
set_real_ip_from 172.17.0.0/24;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
real_ip_recursive on;
location / {
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;
proxy_pass http://127.0.0.1:10088;
}
access_log logs/web.example.com_access.log;
}
gost/ss behind airport with clash
Considering the price, secrecy, privacy, network speed, etc., the best option is to use ss transit through the airport. The next best option is to use gost directly.
yaml
proxies:
- name: "gost"
type: http
server: gost.example.com
port: 443
username: "aaron1984"
password: "8d1HTRn1uSjynLpbxg4otZEPnd52DqAX"
tls: true # https
- name: "ss"
type: ss
server: "IP"
port: 1984
cipher: chacha20-ietf-poly1305
password: "UiGGQvG6TszhLATP"
proxy-providers:
Airport:
type: file
path: ./airport.yaml
health-check:
enable: true
interval: 36000
url: http://www.gstatic.com/generate_204
proxy-groups:
- name: "Proxy"
type: select
use:
- Airport
proxies: ["TestPing", "gost", "airport-ss"]
- name: "TestPing"
type: url-test
use:
- Airport
proxies: []
url: "http://www.gstatic.com/generate_204"
interval: 300
- name: "airport-ss"
type: relay
proxies:
- TestPing
- ss
rules:
- GEOIP,CN,DIRECT
- MATCH,Proxy