Best Practice with FRP

FRP is a tool for reverse proxy. By using FRP, we can easily expose service in local network to public internet. Though the official documents provides some configurations for specific condition, it can still be confusing for new users. Thus I would like to record how I use it.

Installation

FRP doesn’t provide any installation script, maybe because it’s quite easy to run under command. But FRP does provided systemd configs, thus we can manage FRP service though systemd.

Download latest tarball from FRP Binary and unpack it, then execute following command to install on Linux with systemd:

1
2
3
4
5
6
7
8
9
10
11
# on frp client
mkdir /etc/frp
cp frpc /usr/bin
cp frpc_full.ini /etc/
cp systemd/frpc@.service /lib/systemd/system/

# on frp server
mkdir /etc/frp
cp frps /usr/bin
cp frps_full.ini /etc/
cp systemd/frps@.service /lib/systemd/system/

Configration

You may notice that we use frpc@.service rather than frpc.service, this is a kind of systemd grammar. We can append extra string after @, and systemd will use the config file with the same name.

SSH

Client

  • Add config file /etc/frp/ssh.ini

    Local sshd listens at 127.0.0.1:22 and we would like to access it through <server ip>:7022 . Multiple client can make use of the same server with different tag [ssh] and different remote_port.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [common]
    server_addr = <ip or domain>
    server_port = 7000
    token = <password>

    [ssh]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 22
    remote_port = 7022
  • Enable and start service

    1
    2
    systemctl enable frpc@ssh
    systemctl start frpc@ssh

Server

  • Add config file /etc/frp/ssh.ini

    1
    2
    3
    4
    [common]
    bind_addr = 0.0.0.0
    bind_port = 7000
    token = <password>
  • Enable and start service

    1
    2
    systemctl enable frps@ssh
    systemctl start frps@ssh

Http service with Nginx

Under this condition, we have a http service in local network and would like to access it through Nginx.

Client

  • Add config file /etc/frp/http.ini

    Suppose we have a local http server listening at http://127.0.0.1:80

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [common]
    server_addr = <ip or domain>
    server_port = 7000
    token = <password>

    [http_service]
    type = http
    local_port = 80
    custom_domains = <bound doamin>
  • Enable and start service

    1
    2
    systemctl enable frpc@http
    systemctl start frpc@http

Server

  • Add config file /etc/frp/http.ini

    In this config, FRP server will listen at 0.0.0.0:7000, and the exposed http service will listen at 127.0.0.1:7080. The limitation is that 1 server can only serve 1 client if you don’t use the locations, while FRP can not rewrite URL path as this work should belong to Nginx.

    1
    2
    3
    4
    5
    6
    [common]
    bind_addr = 0.0.0.0
    bind_port = 7000
    proxy_bind_addr = 127.0.0.1
    vhost_http_port = 7080
    token = <password>
  • Enable and start service

    1
    2
    systemctl enable frps@http
    systemctl start frps@http
  • Add Nginx location

    1
    2
    3
    4
    5
    6
    7
    8
    location / {
    proxy_redirect off;
    proxy_pass http://127.0.0.1:7080/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    }

Https service with Nginx

Under this condition, we have a https service in local network and would like to access it through Nginx. You may ask: Why use https for internal service? Well, sometimes this can happen and we can not change, such as Proxmox VE, it only supports https for web service, and it’s hard to switch to http.

Client

  • Add config file /etc/frp/https.ini

    Suppose we have a local https service https://127.0.0.1:443

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [common]
    server_addr = <ip or domain>
    server_port = 7000
    token = 'password'

    [proxmox]
    type = https
    local_port = 443
    custom_domains = <bound domain>
  • Enable and start service

    1
    2
    systemctl enable frpc@https
    systemctl start frpc@https

Server

  • Add config file /etc/frp/https.ini

    In this config, FRP server will listen at 0.0.0.0:7000, and the exposed https service will listen at 127.0.0.1:7443. The limitation is that 1 server can only serve 1 client if you don’t use the locations, while FRP can not rewrite URL path as this work should belong to Nginx.

    1
    2
    3
    4
    5
    6
    [common]
    bind_addr = 0.0.0.0
    bind_port = 7000
    proxy_bind_addr = 127.0.0.1
    vhost_https_port = 7443
    token = <password>
  • Enable and start service

    1
    2
    systemctl enable frps@https
    systemctl start frps@https
  • Add Nginx location

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    location / {
    proxy_ssl_server_name on;
    proxy_ssl_name $host;
    proxy_ssl_verify off;
    proxy_pass https://127.0.0.1:7443;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header cookie $http_cookie;
    proxy_set_header Proxy-Connection "";
    proxy_http_version 1.1;
    }