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

<code># 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.)
</code>

Edit frps.ini

<code>[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
</code>

Start frps with systemd

<code>[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
</code>

nginx reverse‑proxy configuration

<code># 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;
    }
}
</code>

Open firewall ports

Allow ports 7000 and 7080 in the security group.

Client configuration

Install frp client

<code># 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
</code>

Edit frpc.ini

<code>[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
</code>

Start frpc with systemd

<code>[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
</code>

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:

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

Start

frps

, then on the client set:

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

Start

frpc

and connect with:

<code>ssh -p 6000 [email protected]
</code>
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

login 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.