Expose Local Services via Cloud Gateway with FRP: Practical Guide
This guide demonstrates how to use a low-cost cloud server running FRP (frps) as a secure gateway to expose local services (web, AI, databases) to the internet without migrating compute or data, covering architecture, security hardening, systemd deployment, Nginx integration, verification steps, and suitability for personal projects and small teams.
Architecture Overview
The article presents a pattern where a cloud server (Alibaba Cloud or Tencent Cloud lightweight instance) acts solely as a gateway ("gatekeeper") providing a stable public IP and running the FRP server ( frps). Local servers (home, office, or on-premises) run the FRP client ( frpc) and initiate an outbound encrypted TLS connection to the cloud. Users access the public domain or IP; traffic is tunneled via FRP to the local Nginx reverse proxy, which forwards to the actual applications (Web/API/AI services). Databases (MySQL, Redis), model files, and GPU resources remain on the local network. Only the required web entry points are exposed.
Mobile / PC User
│ Access https://demo.example.com
▼
Alibaba / Tencent Cloud Lightweight Server
Public IP + Security Group + frps
│ FRP encrypted connection
▼
Home / Office / Local Datacenter
frpc → Nginx → Web / API / AI services
│
├── MySQL
├── Redis
└── Local files / GPUKey boundaries: public sees only the cloud server; local server initiates outbound connection (no inbound ports needed, works behind CGNAT); internal services stay private; only necessary web endpoints are published.
Why This Approach
1. Retain Local Compute
If local hardware already provides high-performance CPU, GPU, large disks, or a prepared data environment, there is no need to replicate that costly configuration in the cloud. The cloud server only handles connection forwarding, so its CPU/memory demands are low; the critical cloud resources are public bandwidth, traffic quota, and line quality.
2. Avoid Home Broadband Hassles
Many residential connections lack a public IPv4 address. Even with router port mapping, external access often fails due to carrier-grade NAT. FRP solves this because frpc initiates the connection outward, eliminating dependence on a public IP or control over upstream routers.
3. Data Stays Local
Databases, files, models, and internal components remain on-premises. Only authenticated business interfaces are served publicly. This suits personal projects, demos, AI inference services, and small-team internal tools.
4. Fast On/Offboarding
Adding a new application only requires a new proxy configuration entry; removing it is just disabling that proxy — no full server migration.
Prerequisites
A cloud server with a public IP (lightweight instance sufficient for low concurrency; bandwidth becomes the bottleneck for media/model transfers).
Choose a region close to you and your users; verify the instance has a public IP.
Consider renewal price, public bandwidth cap, and monthly traffic limit, not just first-year pricing.
Local server with internet access (any OS supported by FRP).
Domain name (optional but recommended for HTTPS).
FRP binary (same version on both ends) from the official GitHub releases.
Step 1: Configure Cloud Security Groups
Security groups act as the cloud provider's external firewall. For an HTTPS site, allow only necessary ports (e.g., 80, 443, 7000 for frps). Do not open all ports. Never expose database ports (3306, 5432, 6379) directly. Both Alibaba Cloud and Tencent Cloud separate inbound and outbound rules; custom ports must be explicitly allowed, otherwise public access is blocked even if the process listens.
Step 2: Deploy frps on Cloud Server
Download the matching architecture binary (typically linux_amd64 or linux_arm64; verify with uname -m). Place frps in /usr/local/bin/frps and create /etc/frp/frps.toml:
bindPort = 7000
# Only allow clients to request ports 80 and 443, preventing arbitrary port exposure
allowPorts = [
{ single = 80 },
{ single = 443 }
]
# Enforce TLS for all client connections
transport.tls.force = true
# FRP 0.64.0+ supports loading token from a separate file
auth.tokenSource.type = "file"
auth.tokenSource.file.path = "/etc/frp/token"Create /etc/frp/token with a long random string and restrict permissions: sudo chmod 600 /etc/frp/token Do not use weak tokens or commit them to Git. File-based token loading is safer than embedding secrets in the config file. Verify config with frps verify -c /etc/frp/frps.toml. Then manage via systemd ( /etc/systemd/system/frps.service):
[Unit]
Description=FRP Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo systemctl status frpsStep 3: Deploy frpc on Local Server
Use the same FRP version. Create /etc/frp/frpc.toml:
serverAddr = "your-cloud-public-IP"
serverPort = 7000
transport.tls.enable = true
auth.tokenSource.type = "file"
auth.tokenSource.file.path = "/etc/frp/token"
[[proxies]]
name = "my-web-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80
remotePort = 80
[[proxies]]
name = "my-web-https"
type = "tcp"
localIP = "127.0.0.1"
localPort = 443
remotePort = 443Copy the identical token file to /etc/frp/token with chmod 600. Verify with frpc verify -c /etc/frp/frpc.toml. Systemd unit ( /etc/systemd/system/frpc.service):
[Unit]
Description=FRP Client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.targetStart:
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo systemctl status frpcNow accessing the cloud server's ports 80/443 forwards traffic to the local server's corresponding ports.
Step 4: Use Nginx as Local Entry Point
Do not let FRP connect directly to a temporary dev port. Instead, run a local Nginx to handle domain routing, HTTPS, WebSocket, upload limits, and timeouts, then reverse-proxy to the actual app (e.g., 127.0.0.1:8000). Example Nginx config:
server {
listen 127.0.0.1:80;
server_name demo.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}After configuring HTTPS (via Certbot, acme.sh, or another ACME client with auto-renewal), redirect port 80 to 443. Point the domain's A record to the cloud public IP. If using a mainland China cloud provider for web serving, complete ICP filing and public security filing. For temporary testing, a raw IP with a high port can verify the tunnel, but never treat a non-HTTPS entry as production.
Step 5: Verify Along the Real Access Path
Do not rely solely on systemctl showing active. Perform layered checks:
# Local app health
curl -I http://127.0.0.1:8000
# Local Nginx health
curl -I http://127.0.0.1
# frpc connection to frps
journalctl -u frpc -n 100 --no-pager
# External public endpoint
curl -I https://demo.example.comFinally, disable Wi-Fi on your phone and test over 4G/5G. Local success does not guarantee public DNS, certificates, carrier routing, or mobile rendering work. For systems with login, file upload, WebSocket, or APIs, additionally verify:
Login page loads.
Unauthenticated access to protected APIs returns 401/403.
Image and large file uploads succeed.
WebSocket connections stay alive.
After local network loss, frpc auto-reconnects when connectivity returns.
Both servers auto-start services on reboot.
Real-World Experience
The author exposed a locally running collaboration system to mobile devices. Frontend, backend, and Redis stayed on local addresses; the cloud server's existing port 80 hosted another site, so a separate HTTPS forwarding entry was added without disrupting the old service. Public login and mobile pages worked; unauthenticated API calls returned expected 401; FRP tunnel and certificate renewal were managed by systemd. The key takeaway: the value of internal network penetration is not merely "port connectivity" but enabling a locally developed product to be accessed by real users on real devices.
Suitability Assessment
Well Suited For
Personal sites, portfolio demos, home services.
Small-team internal systems.
Local GPU inference, AI demos.
Temporary test environments and client demos.
Applications needing large local storage but modest public traffic.
Not Suited For
Production core systems with strict SLA requirements.
High-concurrency, high-bandwidth video distribution.
Environments with frequent power or network outages.
Services requiring multi-region disaster recovery.
Publicly exposed systems that cannot receive continuous security updates and monitoring.
Because the cloud server is only the entry point, any local power loss, network failure, or app crash interrupts the public service. FRP solves "how to connect in," not high availability itself.
Multi-Project Setup When Cloud Ports 80/443 Are Occupied
A single cloud server can serve multiple projects without stopping existing sites. Recommended structure:
Public 80/443
│
Cloud Nginx (domain-based routing, unified cert issuance)
│
127.0.0.1:18080 (FRP mapped port, not exposed publicly)
│
Local app 127.0.0.1:8000Configure frps proxy ports to listen only on 127.0.0.1, then let cloud Nginx forward. This keeps public exposure limited to 80/443 while multiple domains share one cloud server — a more maintainable approach than assigning a separate high port per project.
Final Reminders
A cloud server need not host all compute and data; it can be a bridge linking a stable public entrance to your existing local compute. For individual developers and small teams, this model means you can run the product on hardware you already own, then put it in front of real users at minimal cloud cost. But remember: once a public entrance is open, you face the entire internet, not just your LAN. Keep the connection simple, the boundaries clear, and never skip security. If you have a spare PC, mini-PC, NAS, or GPU workstation, start with a read-only demo and get it accessible on a phone. When the first external user loads the page, you'll realize the gap between your local server and the internet was never a "big migration" — just a carefully restrained tunnel.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
