摘要:本篇主要讲解如何使用开源软件 frp 进行内网穿透,将树莓派或其它电脑设备变成自己的云服务器,提供可灵活扩展的网站和工具服务,不再受制于高配置公有云主机的昂贵费用。内容涉及安装frp server 和 client 程序,进行相应的穿透配置,以及随时随地登录和访问部署的网站服务等。
阅读本篇之前,建议您先了解 基础准备篇 的内容。
对于云盘来说,是 P2P 的技术,所以远程访问时是互相知道对方的,可以直接同步数据。但如果在梅莓派上部署了网站服务,要让不知道访问来源的任何电脑访问,就不得行了。我们必须要有一个公网的 IP 地址,才能对外提供网站服务。
另外,对于自由职业者来说,如果要将重要的版本控制代码、项目资料托管在云主机上,总会感觉不那么安全;又或者,如果要开发、测试或演示自己的软件程序,部署大型程序非常占用主机资源,全部买云主机又不划算。这时,我们就可以用到今天说的内网穿透技术了。
我们可以通过手中的树莓派设备,用最小化配置和最简洁的方式,满足自由职业者随时随地能开发和演示的需要。
下面,我们就开始来亲手打造吧。
- 准备工作
- 云主机上安装 frp server
- 树莓派上安装 frp client
- 远程登录并访问树莓派服务
准备工作
先罗列一下本篇需要准备的资源:
- 一台核心的树莓派4B设备(推荐:4GB+内存版本,32GB+ TF 卡,1TB 固态硬盘);
- 一台带公网 IP 的低配置云主机(推荐:1核CPU、1GB内存即可、2MB带宽即可);
- 一个域名(国内用请先备案)。
为了方便后续介绍,先做以下假定:
对云主机
- 云主机公网 IP:11.22.33.44
- 操作系统:Ubuntu,64-bit
- 默认工作目录:~ (/home/ubuntu)
对树莓派设备
- 树莓派内网 IP:192.168.31.199
- 操作系统:Ubuntu on Raspberry Pi,64-bit
- 默认工作目录:~ (/home/ubuntu)
然后,我们假定自己购买的域名为:mydomain.com,并已解析到公网 IP 11.22.33.44 上。另外假定:
访问云主机上服务的域名和端口:
- frps dashboard:mydomain.com:7500
访问梅莓派上服务的二级域名:
- frpc 管理控制台:frpc.mydomain.com
- 容器管理控制台:portainer.mydomain.com
- 私有网盘控制台:syncthing.mydomain.com
- git 代码托管:code.mydomain.com
- (未来可扩展更多可访问的服务)
云主机上安装 frp server
通过 ssh 登录到云主机。
ssh ubuntu@11.22.33.44
如果没有安装 wget 等相关工具,可提前用 snap 或 apt 安装好。
然后按如下命令安装 frps (frp server),您也可以再看看有没有 新版本。
FRP_VERSION=0.42.0
# 下载并解压程序包
sudo wget https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz
sudo tar -zxvf frp_${FRP_VERSION}_linux_amd64.tar.gz
# 复制程序和配置文件到系统目录
sudo mv frp_${FRP_VERSION}_linux_amd64 frp
sudo chmod +x frp/frps
sudo cp frp/frps /usr/bin/
sudo mkdir -p /etc/frp/
sudo cp frp/frps.ini /etc/frp/
# 复制 service 配置文件,以便开机以服务的方式自启动
sudo cp frp/systemd/frps@.service /lib/systemd/system/frps@.service
接下来,参考完整配置格式 frps_full.ini,并根据实际情况,编辑自己的配置文件 frps.ini。
sudo vi /etc/frp/frps.ini
# [common] is integral section
[common]
# A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
bind_addr = 0.0.0.0
bind_port = 7000
# udp port to help make udp hole to penetrate nat
bind_udp_port = 7001
# udp port used for kcp protocol, it can be same with 'bind_port'
# if not set, kcp is disabled in frps
kcp_bind_port = 7000
# specify which address proxy will listen for, default value is same with bind_addr
# proxy_bind_addr = 127.0.0.1
# if you want to support virtual host, you must set the http port for listening (optional)
# Note: http port and https port can be same with bind_port
vhost_http_port = 80
vhost_https_port = 443
# response header timeout(seconds) for vhost http server, default is 60s
# vhost_http_timeout = 60
# TcpMuxHttpConnectPort specifies the port that the server listens for TCP
# HTTP CONNECT requests. If the value is 0, the server will not multiplex TCP
# requests on one single port. If it's not - it will listen on this value for
# HTTP CONNECT requests. By default, this value is 0.
# tcpmux_httpconnect_port = 1337
# set dashboard_addr and dashboard_port to view dashboard of frps
# dashboard_addr's default value is same with bind_addr
# dashboard is available only if dashboard_port is set
dashboard_addr = 0.0.0.0
dashboard_port = 7500
# dashboard user and passwd for basic auth protect, if not set, both default value is admin
dashboard_user = admin
dashboard_pwd = mypassword
# enable_prometheus will export prometheus metrics on {dashboard_addr}:{dashboard_port} in /metrics api.
enable_prometheus = true
# dashboard assets directory(only for debug mode)
# assets_dir = ./static
# console or real logFile path like ./frps.log
log_file = /var/log/frp/frps.log
# trace, debug, info, warn, error
log_level = info
log_max_days = 3
# disable log colors when log_file is console, default is false
disable_log_color = false
# DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
detailed_errors_to_client = true
# AuthenticationMethod specifies what authentication method to use authenticate frpc with frps.
# If "token" is specified - token will be read into login message.
# If "oidc" is specified - OIDC (Open ID Connect) token will be issued using OIDC settings. By default, this value is "token".
authentication_method = token
# AuthenticateHeartBeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
authenticate_heartbeats = false
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
authenticate_new_work_conns = false
# auth token
token = mytoken
# OidcClientId specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# By default, this value is "".
oidc_client_id =
# OidcClientSecret specifies the client secret to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# By default, this value is "".
oidc_client_secret =
# OidcAudience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_audience =
# OidcTokenEndpointUrl specifies the URL which implements OIDC Token Endpoint.
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
oidc_token_endpoint_url =
# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_timeout is 90
# heartbeat_timeout = 90
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
#allow_ports = 2000-3000,3001,3003,4000-50000
# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
max_pool_count = 5
# max ports can be used for each client, default value is 0 means no limit
max_ports_per_client = 0
# TlsOnly specifies whether to only accept TLS-encrypted connections. By default, the value is false.
tls_only = false
# tls_cert_file = server.crt
# tls_key_file = server.key
# tls_trusted_ca_file = ca.crt
# if subdomain_host is not empty, you can set subdomain when type is http or https in frpc's configure file
# when subdomain is test, the host used by routing is test.frps.com
subdomain_host = mydomain.com
# if tcp stream multiplexing is used, default is true
tcp_mux = true
# custom 404 page for HTTP requests
# custom_404_page = /path/to/404.html
# specify udp packet size, unit is byte. If not set, the default value is 1500.
# This parameter should be same between client and server.
# It affects the udp and sudp proxy.
udp_packet_size = 1500
在官方的完整默认配置基础上,主要做了这几点改动:
dashboard_pwd = mypassword
log_file = /var/log/frp/frps.log
token = mytoken
#allow_ports = 2000-3000,3001,3003,4000-50000
subdomain_host = mydomain.com
说明:
- dashboard_pwd:frps 管理控制台登录密码,建议您修改一下为自己的密码;
- log_file:改放到系统常规放置的地方,注意 chmod 文件权限,否则可能出现无权限问题,比如:
# 创建日志文件
sudo mkdir -p /var/log/frp
sudo touch /var/log/frp/frps.log
sudo chmod -R 666 /var/log/frp/frps.log
- token: frp client 与 server 之间的约定令牌,两端必须相同。建议自己通过 uuidgen 生成一个唯一的令牌,比如:
uuidgen | sed 's/-//g'
ff9acab846cd4de88d5bc8840fa181e2
- allow_ports:为了方便开发和测试,暂不配置,即允许所有端口(待需要时再添加)。
- subdomain:填写自己购买的域名,方便 vhost 配置的子域名访问。
接下来,因为配置文件名是frps.ini,所以使用 @frps.service 方式启动或管理服务。
# 注册和启动服务
sudo systemctl enable frps@frps.service
sudo systemctl start frps@frps.service
如果要检查是否启动成功、查看日志等,可以使用:
# 查询服务状态和日志
sudo systemctl status frps@frps.service
sudo journalctl -e -u frps@frps.service
其它可能还会偶尔用到的命令:
# 修改配置后,重启服务
sudo systemctl daemon-reload
sudo systemctl restart frps@frps.service
# 停止或关闭服务
sudo systemctl stop frps@frps.service
sudo systemctl disable frps@frps.service
补充1:
如果配置了 vhost 参数,希望直接使用 80 和 443 这种 1024 以下的端口,可能出现无法启动 frps 的情况,查看服务日志,可以看到是因为无权限。
frps[126933]: Create vhost http listener error, listen tcp 0.0.0.0:80: bind: permission denied
这时需要 +s 提升当前启动服务的用户权限:
sudo chmod u+s /usr/bin/frps
ls -l /usr/bin/frps
-rwsr-xr-x 1 root root 13205504 Oct 24 22:48 /usr/bin/frps
树莓派上安装 frp client
下载并解压程序包:
FRP_VERSION=0.42.0
sudo wget https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_arm64.tar.gz
sudo tar -zxvf frp_${FRP_VERSION}_linux_arm64.tar.gz
# 复制程序和配置文件到系统目录:
sudo mv frp_${FRP_VERSION}_linux_arm64 frp
sudo chmod +x frp/frpc
sudo cp frp/frpc /usr/bin/
sudo mkdir -p /etc/frp/
sudo cp frp/frpc.ini /etc/frp/
复制 service 配置文件,以便开机以服务的方式自启动:
sudo cp frp/systemd/frpc@.service /lib/systemd/system/frpc@.service
接下来,参考完整配置格式 frpc_full.ini,并根据实际情况,编辑自己的配置文件 frpc.ini。
# [common] is integral section
[common]
# A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
server_addr = 11.22.33.44
server_port = 7000
# console or real logFile path like ./frpc.log
log_file = /var/log/frp/frpc.log
# trace, debug, info, warn, error
log_level = info
log_max_days = 3
# disable log colors when log_file is console, default is false
disable_log_color = false
# for authentication
token = mytoken
# set admin address for control frpc's action by http api such as reload
admin_addr = 0.0.0.0
admin_port = 7400
admin_user = admin
admin_pwd =mypassword
# Admin assets directory. By default, these assets are bundled with frpc.
# assets_dir = ./static
# connections will be established in advance, default value is zero
#pool_count = 5
# if tcp stream multiplexing is used, default is true, it must be same with frps
tcp_mux = true
# your proxy name will be changed to {user}.{proxy}
user = raspi
# 'ssh' is the unique proxy name
# if user in [common] section is not empty, it will be changed to {user}.{proxy} such as 'your_name.ssh'
[ssh]
# tcp | udp | http | https | stcp | xtcp, default is tcp
type = tcp
local_ip = 127.0.0.1
local_port = 22
# limit bandwidth for this proxy, unit is KB and MB
bandwidth_limit = 2MB
# true or false, if true, messages between frps and frpc will be encrypted, default is false
use_encryption = false
# if true, message will be compressed
use_compression = false
# remote port listen by frps
remote_port = 6022
在官方的完整默认配置的基础部分之上,主要做了这几点改动:
server_addr = 11.22.33.44
log_file = /var/log/frp/frpc.log
token = mytoken
admin_pwd =mypassword
user = raspi
[ssh] bandwidth_limit = 2MB
[ssh] remote_port = 6022
说明:
- server_addr:frps 所在云主机的公网 IP 地址;
- log_file:改放到系统常规放置的地方,注意 chmod 文件权限,否则可能出现无权限问题,比如:
# 创建日志文件
sudo mkdir -p /var/log/frp
sudo touch /var/log/frp/frpc.log
sudo chmod -R 666 /var/log/frp/frpc.log
- token: frp client 与 server 之间的约定令牌,两端必须相同;
- admin_pwd:frp client 的管理控制台密码;
- user: 这个相当于给下面的代理名称加个前缀,以避免同其它客户端的配置出现名称重复
- [ssh] bandwidth_limit:限定带宽,可以根据您实际购买的公网带宽修改,或者注释掉。
- [ssh] remote_port:公网 IP 上暴露的端口,用于远程登录时的访问。
有了以上的配置,我们其实就可以通过 ssh 远程登录到树莓派,进行相应的系统管理了。
不过,按我们的原定计划,继续配置各应用服务的代理,以便提供更多服务访问。
# Resolve your domain names to [server_addr] so you can use http://xxx.mydomain.com to browse xxx.
[frpc-admin-http]
type = http
local_port = 7400
subdomain = frpc
[portainer-http]
type = http
local_port = 9000
subdomain = portainer
[syncthing-http]
type = http
local_port = 8384
subdomain = syncthing
[gitea-http]
type = http
local_port = 3000
subdomain = code
# more ...
frp 支持的更多功能,请参见官方的帮助文档:https://github.com/fatedier/frp。
接下来,因为配置文件名是frpc.ini,所以使用 @frpc.service 方式启动或管理服务。
# 注册和启动服务
sudo systemctl enable frpc@frpc.service
sudo systemctl start frpc@frpc.service
如果要检查是否启动成功、查看日志等,可以使用:
# 查询服务状态和日志
sudo systemctl status frpc@frpc.service
sudo journalctl -e -u frpc@frpc.service
其它可能还会偶尔用到的命令:
# 修改配置后,重启服务
sudo systemctl daemon-reload
sudo systemctl restart frpc@frpc.service
# 停止或关闭服务
sudo systemctl stop frpc@frpc.service
sudo systemctl disable frpc@frpc.service
注意
当有 frp 新版本,要进行升级时,请在本机或局域网内主机操作。因为,如果远程断开 frpc 服务后,就无法再连接上,只有回到本地网络中。当然,如果您有两个树莓派的话,也可以互相当跳板机进行升级。
远程登录并访问树莓派服务
现在,可以分别访问自己的服务网站了。
还可以通过 ssh 远程访问树莓派,进行系统管理了:
sudo ssh ubuntu@11.22.33.44:6022
Welcome to Ubuntu ...
ubuntu@raspi:~$
恭喜您,已完成整个内网穿透的搭建。如果您还想扩展更多的开发或演示网站,添加相应的代理配置就可以了。
我是几昆虫,一个追求终身成长的努力者。感谢您完整阅读这篇文章,期待与您的思想相遇。