Operations 15 min read

Quick Guide: Deploy frp for Secure Intranet-to-Internet Access

This article explains how to set up frp, a high-performance reverse-proxy written in Go, to expose internal web and SSH services to the public Internet using domain-based virtual hosts, nginx reverse-proxy, and systemd on CentOS, complete with configuration examples and firewall considerations.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Quick Guide: Deploy frp for Secure Intranet-to-Internet Access

Introduction

frp

is a high‑performance reverse‑proxy written in Go that enables intranet penetration (NAT traversal) for TCP, UDP, HTTP and HTTPS, allowing a local web service to be exposed to the Internet.

What frp does

By deploying the frp server on a public‑IP node, internal services can be accessed from outside, with features such as:

Expose HTTP/HTTPS services from machines behind firewalls without a public IP.

Virtual‑host support for multiple domains on a single port.

Expose TCP services (e.g., SSH) from an internal network.

frp Overview

frp supports TCP, UDP, HTTP and HTTPS. The latest version at the time of writing is v0.34.2. The official documentation provides full details; this article shows a quick deployment.

How frp works

After frpc starts, it connects to frps and sends a login request, keeping a persistent connection. frps creates a listener for public requests; when a request arrives, it matches it to an existing client connection or creates a new work connection. Traffic is then forwarded between the public side and the client side, and both ends are closed together if either side disconnects.

Architecture

Practical Deployment Example

Example 1 – Access an internal web service via a domain name

Preparation

An internal server (client)

A public server/VPS (server)

A domain name pointing to the public server (e.g., rkjh.xyz)

Environment:

CentOS 7.6

nginx 1.16

frp v0.34.0

Step 1 – Start frp server and client to establish a tunnel

frps listens on port 7080 (customizable) for external HTTP requests.

frpc forwards internal web ports 8585 and 8686 to the public side.

Step 2 – Configure nginx as a reverse proxy

Map the sub‑domain dev.rkjh.xyz to frps ’s HTTP port (7080). Requests such as a.dev.rkjh.xyz or b.dev.rkjh.xyz are forwarded to the corresponding internal ports.

Step 3 – frpc processes incoming requests

If the Host header is a.dev.rkjh.xyz, forward to internal port 8585.

If the Host header is b.dev.rkjh.xyz, forward to internal port 8686.

Step 4 – Internal web service handles the request and returns a response.

Step 5 – frpc sends the response back through frps to the external client.

Step 6 – Result

Visiting a.dev.rkjh.xyz reaches localhost:8585 on the internal server.

Visiting b.dev.rkjh.xyz reaches localhost:8686.

Domain DNS configuration

Add two A records under rkjh.xyz: dev and *.dev, both pointing to the public server’s IP. All sub‑domains of dev.rkjh.xyz will resolve to that IP.

Server configuration

Install frp

# download to /data
cd /data
wget https://github.com/fatedier/frp/releases/download/v0.34.0/frp_0.34.0_linux_amd64.tar.gz
tar -zxvf frp_0.34.0_linux_amd64.tar.gz
mv frp_0.34.0_linux_amd64 frp
cd frp
# keep only server files (frps, frps.ini, etc.)

Edit frps.ini

[common]
bind_port = 7000
vhost_http_port = 7080
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = admin
log_file = /data/frp/log/frps.log
log_level = warn
log_max_days = 7
subdomain_host = dev.msh.com
authentication_method = token
authenticate_heartbeats = true
authenticate_new_work_conns = true
token = 12345678_
enable_prometheus = true
allow_ports = 20000-30000

Start frps with systemd

[Unit]
Description=frps service

[Service]
ExecStart=/data/frp/frps -c /data/frp/frps.ini
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=frp-service
User=root

[Install]
WantedBy=multi-user.target

nginx reverse‑proxy configuration

# install nginx
yum -y install epel-release
yum install -y nginx

# /etc/nginx/nginx.conf
server {
    listen 80;
    server_name *.dev.rkjh.xyz dev.rkjh.xyz;
    location / {
        proxy_pass http://127.0.0.1:7080;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
    }
    if ($http_user_agent ~* "bot|spider|curl|wget") {
        return 403;
    }
}

Open firewall ports

Allow ports 7000 and 7080 in the security group.

Client configuration

Install frp client

# download to /data
cd /data
wget https://github.com/fatedier/frp/releases/download/v0.34.0/frp_0.34.0_linux_amd64.tar.gz
tar -zxvf frp_0.34.0_linux_amd64.tar.gz
mv frp_0.34.0_linux_amd64 frp
cd frp

Edit frpc.ini

[common]
server_addr = <your_public_ip>
server_port = 7000
authentication_method = token
authenticate_heartbeats = true
authenticate_new_work_conns = true
token = 12345678_
log_file = /data/frp/log/frps.log
log_level = warn
log_max_days = 7

[web-a]
type = http
local_port = 8585
subdomain = a
use_encryption = true
use_compression = true

[web-b]
type = http
local_port = 8686
subdomain = b
use_encryption = true
use_compression = true

Start frpc with systemd

[Unit]
Description=frp service

[Service]
ExecStart=/data/frp/frpc -c /data/frp/frpc.ini
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=frp-service
User=root

[Install]
WantedBy=multi-user.target

When the log shows “start proxy success”, the tunnel is established.

Testing

Visit http://a.dev.msh.com (or b.dev.msh.com) in a browser; the request is forwarded to the corresponding internal service. The frp dashboard shows connection status.

Example 2 – SSH access to an internal machine

Configure an ssh proxy on the server:

# frps.ini
[common]
bind_port = 7000
[ssh]
listen_port = 6000
auth_token = 123456_

Start frps, then on the client set:

# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000
auth_token = 123456_
[ssh]
local_port = 22

Start frpc and connect with:

ssh -p 6000 [email protected]
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Nginxreverse proxyCentOSfrpSystemdnat traversalSSH tunneling
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.