frp+docker | 通过内网穿透部署博客项目
前言
最近买了mac mini m4 32G,性能很强劲啊!干活更流畅了,于是打算作为家庭服务器去运行一些项目,最好还能把目前在云服务器上运行的项目转移到本地去跑。
而这样一来亟待解决的是公网IP的问题,以往我的云端项目,比如网站,通过云服务器厂商提供的公网IP进行域名解析,就可以通过公网访问到我的域名,再包括一些web项目也需要通过公网IP去进行访问,所以说公网IP还是必要的。参考过很多方案,比如向通信运营商申请公网IP或租赁费用更划算带宽更高的云服务器,最后发现依然是「内网穿透」最能满足我的需求,整个配置流程也很直接很迅速。
提供内网穿透服务的平台有很多,我用的是:www.natfrp.com,目前配置的方案是10元/月的套餐,带宽限速24 Mbps,隧道数量10条,每月流量5 GiB + 108 GiB,非常划算了!
FRP与内网穿透
FRP(Fast Reverse Proxy)是一款开源的内网穿透工具,核心功能是通过反向代理技术,让位于内网或防火墙后的设备(如个人服务器、路由器、智能家居等)被公网访问。
内网穿透,乍一听好像是一门很高端很深奥的黑客技术。但其实可以理解它带来的作用就一个,就是让你可以通过公网来访问到你本地局域网里的东西。比如我在家里电脑的一份文件,我希望在公司通过某种方式来访问到这份文件,那内网穿透服务就可以达到这种效果。
总体来说,整套frp服务分为「服务端」和「客户端」,客户端就是你的本地环境。
实际上如果你有一台云服务器,也可以在上面自己搭建一套frp服务端,不难,可能就是配置信息上面的通信需要花点时间去调通,同时访问速度也受限于云服务器的带宽速度。
frp服务端
使用frp服务在「服务端」所需要的配置过程如下:
-
创建隧道
以我使用的付费frp服务为例,在隧道配置页面,点击创建隧道,
比如我现在需要给我的网站配置一个隧道,实现公网通过域名访问到我的网站,那么在配置时可以选「https建站隧道」,后面的配置根据自己的情况来填写域名,
配置好了之后点开配置查看,这个配置信息就是等一下需要在客户端填写的内容。
frp客户端
使用frp服务在「客户端」所需要的配置过程如下:
-
下载frp客户端
本地项目所有应用我使用的是
docker compose
容器编排部署的方案,包括frp客户端,这一步需要将frp项目的文件下载到本地,项目线上地址:https://github.com/fatedier/frp/releases, 下载到本地之后项目目录中的frpc.ini
文件就是需要编辑的配置文件,将上一步获取的配置信息填写进来:这一步的
[server]
部分的配置,首先[server]
对应的是创建隧道时的隧道名,必须要对应上。然后
local_ip
和local_port
,由于我要进行内网穿透的web服务是通过nginx容器代理转发,并且容器之间通过局域网互相通信,所以这里我写的server_nginx
对应的是nginx容器名称,如果是本地服务,那么一般填写localhost
,根据具体情况来。一般这一步都需要一些时间去耐心调整配置信息,才能顺利地跟服务端通信。
-
制作frp镜像
这一步是可选的,镜像用于下一步的yml文件的镜像配置,我的方案是自己制作一个轻量的frp镜像。
我的目录层级关系如下:
在Dockerfile中填写:
FROM busybox:latest MAINTAINER Billy_Chen COPY ./frp /bin/frp ENV TZ=Asia/Shanghai \ PATH="/bin/frp:$PATH"
主要的构建步骤就是把本地的frp项目文件复制进去,其中比较重要的两个文件,一个是客户端配置文件「frpc.ini」,一个是客户端执行文件「frpc」,执行文件就是用来在容器中执行整套frp客户端应用的。
使用build命令制作镜像:
docker build -t chenxuefan/server_frp:v1 --platform linux/arm64 .
,由于我本地运行的机器是Mac m4处理器,因此架构是linux/arm64
。更多使用操作参考:使用-dockerfile-构建项目
-
配置docker-compose.yml文件
server_frp: image: chenxuefan/server_frp:v1 container_name: server_frp restart: always environment: TZ: ${TZ} volumes: - ./server_frp/frp:/bin/frp - ./server_frp/logs:/var/log ports: - "8010-8050:8010-8050" command: [ "frpc", "-c", "/bin/frp/frpc.ini" ] networks: - server healthcheck: test: [ "CMD", "ps", "-ef", "|", "grep", "frpc", "|", "grep", "-v", "grep" ] interval: 30s timeout: 10s retries: 3 start_period: 40s
server_frp
服务连同我的其他服务都配置在yml文件中,最后通过命令docker-compose up
起来,整个部署流程就完成了。通过server.chenxuefan.cn域名即可访问到我本地电脑启动的服务。
所有服务都在容器中隔离运行,我的mac mini也设置成永不休眠,所以理论上只要家里不断网,就可以一直访问到,很稳定!
一些好用的应用 & yml文件配置
minio
server_minio:
image: minio/minio:latest
container_name: server_minio
restart: unless-stopped
volumes:
- ./server_minio/data:/data
- ./server_minio/config:/root/.minio
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
TZ: ${TZ}
ports:
- "9005:9000"
- "9006:9001"
command: [ "server", "/data", "--console-address", ":9001" ]
healthcheck:
test: [ "CMD", "curl", "--silent", "--fail", "http://localhost:9000/minio/health/live" ]
interval: 30s
retries: 3
start_period: 40s
timeout: 10s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "7"
networks:
- server
umami
server_umami:
image: ghcr.io/umami-software/umami:postgresql-latest
container_name: server_umami
ports:
- "8009:3000"
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@server_postgres:${POSTGRES_PORT}/${POSTGRES_DB_UMAMI}
DATABASE_TYPE: postgresql
HASH_SALT: replace-me-with-a-random-string
depends_on:
- server_postgres
restart: always
networks:
- server
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
joplin
server_joplin:
image: joplin/server:latest
container_name: server_joplin
restart: unless-stopped
user: root
ports:
- "8007:22300"
volumes:
- ./server_joplin/data:/var/lib/joplin
- ./server_joplin/config:/config
environment:
APP_PORT: ${JOPLIN_APP_PORT}
DISABLE_CORS: ${JOPLIN_DISABLE_CORS}
CORS_ALLOWED_ORIGINS: ${JOPLIN_CORS_ALLOWED_ORIGINS}
APP_BASE_URL: ${JOPLIN_APP_BASE_URL}
APP_DB: ${JOPLIN_APP_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_DATABASE: ${POSTGRES_DB_JOPLIN}
POSTGRES_PORT: ${POSTGRES_PORT}
TZ: ${TZ}
YARN_CACHE_FOLDER: ${JOPLIN_YARN_CACHE_FOLDER}
command: sh -c "mkdir -p /tmp/yarn-cache && yarn start"
depends_on:
- server_postgres
networks:
- server
healthcheck:
test: ["CMD", "curl", "--silent", "--fail", "http://localhost:22300"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
code-server
server_code-server:
image: codercom/code-server:latest
container_name: server_code-server
restart: unless-stopped
user: root
ports:
- "8006:8080"
volumes:
- ./server_code_server/data:/home/coder/project
environment:
PASSWORD: ${CODE_SERVER_PASSWORD}
TZ: ${TZ}
networks:
- server
healthcheck:
test: ["CMD", "curl", "--silent", "--fail", "http://localhost:8080"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
portainer
server_portainer:
image: portainer/portainer-ce:latest
container_name: server_portainer
restart: unless-stopped
ports:
- "8005:9000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./server_portainer/data:/data
environment:
TZ: ${TZ}
networks:
- server
healthcheck:
test: ["CMD", "curl", "--silent", "--fail", "http://localhost:9000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
sun-panel
server_index_panel:
image: "hslr/sun-panel:latest"
container_name: server_index_panel
environment:
TZ: ${TZ}
volumes:
- ./server_sun-panel/conf:/app/conf
- /var/run/docker.sock:/var/run/docker.sock
- ./server_sun-panel/runtime:/app/runtime
ports:
- "8008:3002"
restart: always
networks:
- server
healthcheck:
test: ["CMD", "curl", "--silent", "--fail", "http://localhost:3002"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
certd
这个项目可以自动生成供域名所使用的SSL证书,保证域名可以通过https进行请求。到期后台自动重新申请,这样可保证网站的长期正常运行。
项目地址:https://github.com/certd/certd
server_certd:
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
container_name: server_certd # 容器名
restart: unless-stopped # 自动重启
volumes:
- ./server_certd/data/certd:/app/data
- ./server_nginx/ssl:/ssl
ports: # 端口映射
- "7001:7001"
- "7002:7002"
labels:
com.centurylinklabs.watchtower.enable: "true"
environment:
- certd_system_resetAdminPasswd=false
networks:
- server