Docker环境中使用frp内网穿透服务

因为本人习惯用docker跑服务,所以对于frp的内网穿透服务我使用的也是docker。

frp在github上的项目地址为:https://github.com/fatedier/frp,里面有相关文档,可以参考配置。由于我使用的docker,自己做了个简单的记录。

frp的docker项目的服务器端和客户端是独立的,地址分别为:https://hub.docker.com/r/snowdreamtech/frps和https://hub.docker.com/r/snowdreamtech/frpc,文档说明地址为:https://gofrp.org/docs/。

先安装服务器端的frp,这台服务器在公网中,作为内网穿透的服务器。

拉取镜像:

1
docker pull snowdreamtech/frps

建立容器:

1
2
3
4
5
6
docker run \
--restart=always \
--network host -d \
-v /docker/frp/frps.ini:/etc/frp/frps.ini \
--name frps \
snowdreamtech/frps

由于挂载了文件到宿主主机,可以直接在宿主主机上编辑/docker/frp/frps.ini进行配置:

1
2
3
4
5
6
7
8
9
10
11
[common]
bind_port = 7000
# 启用面板
dashboard_port = 7500
# 面板登录名和密码
dashboard_user = admin
dashboard_pwd = 12345678
# 使用http代理并使用8888端口进行穿透
vhost_http_port = 8888
# 使用https代理并使用9999端口进行穿透
vhost_https_port = 9999

服务器上的frp安装配置完成,然后在你内网的客户机上安装frp。

拉取镜像:

1
docker pull snowdreamtech/frpc

建立容器:

1
2
3
4
5
6
docker run \
--restart=always \
--network host -d \
-v /docker/frp/:/etc/frp/ \
--name frpc \
snowdreamtech/frpc

在配置客户端前,我先说下这台内网机器上我跑的docker服务:

1、使用nginx和php的docker跑了2个网站,通过虚拟主机方式配置了2个网站,在虚拟网站配置文件中,server_name的域名指向分别为one.yourdomain.com和two.yourdomain.com,一个使用的80端口一个使用443端口,并在域名商处将域名全部解析到frp的服务器的ip上(注意不是客户端,因为客户端在内网没有公网ip,需要通过服务器的公网ip来穿透),在同个端口下配置了多个虚拟主机也能通过自定域名来区分服务。

使用nginx虚拟主机配置为(以https为例子):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
server {
listen 443 ssl http2;
server_name two.yourdomain.com;
index index.html index.htm index.php;
root /usr/share/nginx/html/two.yourdomain.com;

ssl_certificate /etc/nginx/SSL/two.yourdomain.com.cer;
ssl_certificate_key /etc/nginx/SSL/two.yourdomain.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
ssl_session_cache builtin:1000 shared:SSL:10m;

location ~ [^/]\.php(/|$) { # 处理php文件交给php容器
root /var/www/html/two.yourdomain.com;
fastcgi_pass php:9000; # php的容器名和端口
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/two.yourdomain.com$fastcgi_script_name;
include fastcgi_params;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
location ~ .*\.(js|css)?$ {
expires 12h;
}
location ~ /.well-known {
allow all;
}
location ~ /\. {
deny all;
}
access_log /var/log/nginx/two.yourdomain.com.log;
}

2、安装了filebrowser容器,宿主主机与容器的端口映射为8004:80,nginx配置中使用了反代但未启用ssl,已将要使用的域名file.yourdomain.com解析到公网服务器主机的ip上。

基本配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
server_name file.yourdomain.com;

# Allow large attachments
client_max_body_size 128M;

location / {
proxy_pass http://file; # filebrowser的容器名(默认端口80)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
access_log /var/log/nginx/file.yourdomain.com.log;
}

3、安装了bitwarden的容器,已将宿主主机的8008映射到了容器的80端口,同时配置了nginx进行反代,并已设置了ssl证书,已将要使用的域名pwd.yourdomain.com解析到公网服务器主机的ip上;

nginx反代bitwarden的配置文件为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
server
{
listen 443 ssl http2;
server_name pwd.yourdomain.com;
ssl_certificate /etc/nginx/SSL/pwd.yourdomain.com.cer;
ssl_certificate_key /etc/nginx/SSL/pwd.yourdomain.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
ssl_session_cache builtin:1000 shared:SSL:10m;

# Allow large attachments
client_max_body_size 128M;

location / {
proxy_pass http://bitwarden; # bitwarden的容器名(容器端口80)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /admin {
# See: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
auth_basic "Private";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://bitwarden; # bitwarden的容器名(容器端口80)
}
access_log /var/log/nginx/pwd.yourdomain.com.log;
}

按以上的实际情况,我在frp的客户端上进行了如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[common]
# server_addr为frp的服务器ip或已解析到该ip的域名
server_addr = x.x.x.x
# server_port与服务端配置bind_port一致
server_port = 7000

[ssh]
# 开启ssh内网穿透
type = tcp
local_ip = 127.0.0.1
# 内网主机ssh端口
local_port = 22
# 远程连接ssh的端口
remote_port = 2222

[http web1]
# 第一个网站,nginx配置为http访问
type = http
local_port = 80
custom_domains = one.yourdomain.com

[https web2]
# 第二个网站,nginx配置为https访问
type = https
local_port = 443
custom_domains = two.yourdomain.com

[https filebrowser]
# filebrowser容器,直接使用https访问
type = https
custom_domains = file.yourdomain.com
plugin = https2http
# 宿主机ip地址和宿主机映射到容器的端口8004
plugin_local_addr = 127.0.0.1:8004
plugin_crt_path = /etc/frp/yourdomain.com.cer
plugin_key_path = /etc/frp/yourdomain.com.key
# 宿主机的ip地址
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[https bitwarden]
# bitwarden容器,已使用nginx反代并配置为https访问
type = https
local_port = 443
custom_domains = pwd.yourdomain.com

注意:上面filebrowser和bitwarden的https配置是可以互换的,区别在于,一个直接访问容器,一个通过nginx容器进行了反代。在上面的例子中,filebrowser安装后,没有配置nginx,直接在frp配置文件中设置ssl证书,使用宿主机映射的端口8004映射到容器,完成加密传输;bitwarden安装后,配置了nginx,在nginx的配置文件中设置了ssl证书,并进行了反代,使用nginx容器的443端口完成加密传输。

安装配置完成后,即可通过http://one.yourdomain.com:8888、https://two.yourdomain.com:9999、https://file.yourdomain.com:9999和https://pwd.yourdomain.com:9999分别穿透内网,并访问不同的服务了。

对于使用ssh等其它服务,可以参考官方文档进行配置,大同小异,只是配置不同而已。gitee上的文档也可参考:https://gitee.com/yijicai/frp#frp