🚀 Hands-On Guide: Building a High-Speed Tunnel with VPS + Frp + Docker
This tutorial aims to solve the following pain points: 1. Home broadband has no public IP, or ports 80/443 are blocked, so you cannot host a site directly. 2. Accessing home services in China from overseas is slow, and Cloudflare's free plan performs poorly inside China. 3. No ICP filing is required — use a VPS with a high-performance China-bound route for low-latency access.

📖 Introduction
This tutorial aims to solve the following pain points:
- Home broadband has no public IP, or ports 80/443 are blocked, so you cannot host a site directly.
- Accessing domestic services from overseas is slow, and Cloudflare’s free plan does not perform well inside China.
- No ICP filing is required — use a VPS with a high-performance route to achieve low-latency access.
Architecture:
User (HTTPS) -> VPS (Frp server) -> encrypted tunnel -> home server (Frp client) -> local Nginx (decrypt/respond)
🛠️ Prerequisites
- A VPS: ClawCloud is recommended (Hong Kong / Singapore / Japan) — optimized routes and generous bandwidth.
- A home server: with Docker and Nginx installed.
- A domain: hosted on Cloudflare/Alibaba Cloud, used to obtain an SSL certificate.
- Generate a token: run
openssl rand -hex 16in your terminal to generate a connection password.
Step 1: Server Deployment (ClawCloud VPS)
Environment: Ubuntu / Debian Goal: install frps, enable HTTPS listening, and configure auto-start on boot.
1. Download and Install
# Download the latest Frp (check the GitHub Release page for the latest version number)
wget https://github.com/fatedier/frp/releases/download/v0.58.1/frp_0.58.1_linux_amd64.tar.gz
# Extract and install
tar -zxvf frp_0.58.1_linux_amd64.tar.gz
sudo mv frp_0.58.1_linux_amd64/frps /usr/local/bin/
sudo chmod +x /usr/local/bin/frps
# Create the config directory
sudo mkdir -p /etc/frp
2. Configuration File (/etc/frp/frps.toml)
Ini, TOML
# frps internal communication port
bindPort = 7000
# [Key] Public-facing HTTPS port, receives public 443 traffic
vhostHTTPSPort = 443
# Authentication (replace with your own)
auth.method = "token"
auth.token = "a1b2c3d4e5f678901234567890abcdef"
# Dashboard configuration (optional)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin123"
3. Configure Systemd Auto-Start (/etc/systemd/system/frps.service)
Ini, TOML
[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
[Install]
WantedBy=multi-user.target
4. Start the Service and Firewall
# Start the service
sudo systemctl daemon-reload
sudo systemctl enable frps --now
# Open the system firewall
sudo ufw allow 7000/tcp
sudo ufw allow 443/tcp
sudo ufw allow 7500/tcp
⚠️ Note: Don’t forget to also allow these ports in your VPS provider’s web console (security group)!
Step 2: Client Deployment (Home Server)
Environment: Docker Goal: deploy frpc via Docker and pass HTTPS traffic through to the host machine’s Nginx.
1. Configuration File (~/frp/frpc.toml)
Ini, TOML
# Fill in the VPS public IP
serverAddr = "1.2.3.4"
serverPort = 7000
# Must match the server side
auth.method = "token"
auth.token = "a1b2c3d4e5f678901234567890abcdef"
# [Key] Enable TLS encryption to prevent the connection from being reset when crossing the firewall (Connection reset)
transport.tls.enable = true
# --- Forwarding rules ---
[[proxies]]
name = "home_web"
type = "https" # https mode passes encrypted traffic through without decrypting it
customDomains = ["www.yourdomain.com"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:443" # points to the SSL port that the host machine's Nginx listens on
2. Docker Compose File (~/frp/docker-compose.yml)
version: '3.8'
services:
frpc:
image: snowdreamtech/frpc:latest
container_name: frpc
restart: always
# [Key] Use host mode so the container can reach the host machine's Nginx port directly
network_mode: "host"
volumes:
- ./frpc.toml:/etc/frp/frpc.toml
3. Start the Client
cd ~/frp
docker compose up -d
# Check the logs to confirm the connection succeeded (seeing "start proxy success" means success)
docker logs -f frpc
Step 3: Local Nginx Configuration (SSL Endpoint)
Because this is HTTPS passthrough, the SSL certificate must be configured on the home server’s Nginx.
Nginx Configuration Example
server {
# Listen on local 443 (an ISP block on external 443 does not affect internal listening)
listen 443 ssl;
server_name www.yourdomain.com;
# SSL certificate paths
ssl_certificate /etc/nginx/cert/yourdomain.pem;
ssl_certificate_key /etc/nginx/cert/yourdomain.key;
location / {
root /var/www/html;
index index.html;
}
}
💡 Tip: It is recommended to use
acme.shorCertbotwith the DNS API method to obtain certificates, so you can auto-renew without port 80.
Step 4: DNS Resolution
Go to your domain provider (Cloudflare/Alibaba Cloud):
- Add an A record.
- Host record:
www - Value: the public IP of your ClawCloud VPS.
- (If using Cloudflare): Turn off the orange cloud (Proxy Status: DNS Only) so traffic connects directly to the VPS.
🚑 Troubleshooting
Q1: Startup error Connection lost before handshake?
- Cause 1: The system times on the VPS and the home server are out of sync. Synchronize the time.
- Cause 2: Blocked by GFW detection. Make sure
transport.tls.enable = trueis set infrpc.toml.
Q2: The web page returns 502 Bad Gateway?
- The Frp connection is fine, but local Nginx cannot be found.
- Check whether Docker uses
network_mode: "host". - Check whether the
localAddrport matches Nginx’slistenport.
Q3: The Dashboard (port 7500) won’t open?
- Check whether
webServer.addr = "0.0.0.0"is configured infrps.toml. - Key check: whether the security group in the Alibaba Cloud/ClawCloud web console allows port 7500.
Q4: Certificate error / privacy error?
- Confirm that Nginx is configured with the correct certificate and that the domain matches the one being accessed. Frp is only the carrier; certificate errors are Nginx’s problem.
Comments