序
因为轻量应用服务器开始承受不了immich的需求,上传图片的时候开始频繁卡顿。正好又是许久之前就有了组一台Nas的想法。在部署immich服务的内网和公网访问的时候遇到了一些问题。考虑到杂碎且后续可能频繁遇到,故在此记录。
现状与目标
现状
这是当前服务的访问情况,用户在公网发起请求,流量由nginx接管后按照域名规则,转发到本地的指定端口。在nginx上部署ssl和强制https。
原来的链路
展望
因为部署immich的nas所处的网络环境没有公网ip,所以对于公网访问的情况,我们还需要部署frp来做流量转发。
这意味这内网访问和公网访问所走的链路是完全不同的。nginx、frp需要在内外网都部署。
画个图吧
新链路
从图看,实现分流的重要一步就是DNS解析。我们只需要在家中的路由器中设置别名或者直接劫持就行了。
接下来展一下其中可能会遇到的各种问题~
公网链路
Frp服务
我们先看公网链路,DNS之前就解析着这个服务器,不用修改,nginx的反向代理也不用修改,我们只需要撤下之前的immich服务,上线一个同样监听2283端口的frp服务即可。
最新的frp默认用了toml作为配置文件,不太常见。
frps
从github下载tar.gz,解压后编辑frps.toml
文件
1 2 3 4 5
| bindPort = 7827
[auth] method = "token" token = "123123"
TOML
|
修改token后面的值为随机字符串!记得加上双引号。
服务端的配置文件确实没啥好配置的,声明用于frp传输数据的端口和认证方式即可,注意在云服务器后台放行我们声明的7827端口。
然后我们可以启动frp服务,记得用tmux或者screen让它可以后台运行
1
| ./frps -c frps.toml
SHELL
|
frpc
我们重点编辑frp客户端的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13
| serverAddr = "114.114.114.114" serverPort = 7000
[auth] method = "token" token = "123123"
[[proxies]] name = "immich" type = "tcp" localIP = "127.0.0.1" localPort = 2283 remotePort = 2283
TOML
|
修改token后面的值为frps.toml中设定的值!记得加上双引号。
修改serverAddr
字段为部署了服务器端的服务器的ip或者域名。
如果需要配置多个代理,只需要重复[[proxies]]
部分即可,比如我们再加一个Minecraft的转发,那么完整的toml配置为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| serverAddr = "114.114.114.114" serverPort = 7000
[auth] method = "token" token = "123123"
[[proxies]] name = "immich" type = "tcp" localIP = "127.0.0.1" localPort = 2283 remotePort = 2283
[[proxies]] name = "Minecraft Server" type = "tcp" localIP = "127.0.0.1" localPort = 25565 remotePort = 25565
TOML
|
注册为systemd服务
考虑到未来需要的修改配置,重启frpc需求。我们还需要将其注册为systemd服务。
1
| sudo vim /etc/systemd/system/frpc.service
SHELL
|
可以编辑为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [Unit] Description=Frp Client Service After=network.target
[Service] Type=simple User=root Restart=on-failure RestartSec=5s ExecStart=/home/yang/frp/frpc -c /home/yang/frp/frpc.toml ExecReload=/home/yang/frp/frpc reload -c /home/yang/frp/frpc.toml
[Install] WantedBy=multi-user.target
SERVICE
|
修改ExecStart
字段和ExecReload
字段的值为具体的文件路径。
记得给frpc文件赋予执行权限
1
| chmod +x /home/yang/frp/frpc
SHELL
|
重新加载systemd的配置文件
1
| systemctl daemon-reload
SHELL
|
OK!让我们使用systemctl启动frpc服务。
1
| sudo systemctl start frpc.service
SHELL
|
不要忘记为该服务设置开机自启动
1
| sudo systemctl enable frpc.service
SHELL
|
至此,公网访问链路所有流程已完成部署。尝试直接在浏览中输入https://immich.coooolfan.com访问即可。
如果访问出现5**错误,或许是frp服务启动没有成功。
查看frpc服务状态
1
| sudo systemctl status frpc.service
SHELL
|
查看frpc服务实时日志
1
| sudo journalctl -u frpc.service -f
SHELL
|
内网链路
内网DNS劫持
实现内网DNS劫持的方法有很多,这里采用的是主机名映射,直接在OpenWrt中配置对应的域名和ip即可。
公网环境下的DNS解析无须修改,因为我们本来就还要用这个服务器做流量转发。
DNS劫持
获取SSL证书
因为我们需要全程HTTPS,所以内网访问还需要部署SSL证书。因为之前用的lnmp脚本,所以这还是第一次用acme相关的东西。
安装ACME
1
| wget -O - https://get.acme.sh | sh
SHELL
|
一键脚本安装就行了,如果有提示需要提前安装cron,那就先装上cron再重新安装acme。
刷新一下环境变量,不然用不了acme.sh命令
设置默认CA为Let’s Encrypt
1
| acme.sh --set-default-ca --server letsencrypt
SHELL
|
从DNS服务商申请API并配置ACME
因为我们是在内网环境下申请SSL证书,所以只能使用DNS验证的方式验证域名的所有权。acme支持调用DNS服务商的API来自动化执行所有步骤。
acme支持超级多的DNS服务商,不同服务商需要配置的字段和其标志都不同,详情见https://github.com/acmesh-official/acme.sh/wiki/dnsapi
我们的DNS服务商是DNSPod,需要从其后台申请https://console.dnspod.cn/account/token/token
注意:DNSPod分cn和com;DNSPod的API和腾讯云API不一样,不要申请错了。
DNS API的申请
拿到ID和Token后,我们编辑acme的account.conf
文件
1
| vim .acme.sh/account.conf
SHELL
|
对于DNSPod,对应的字段为
1 2
| export DP_Id="<id>" export DP_Key="<token>"
CONF
|
然后尝试向证书服务商申请一个证书
1
| acme.sh --issue --dns dns_dp -d immich.coooolfan.com
SHELL
|
如果证书申请成功,你会看到acme打印的各种东西。我们只会用到证书链fullchain.cer
和密钥immich.coooolfan.com.key
。
如果申请失败,查看日志,不要盲目重试,证书服务商一般会显示失败次数,过多的失败次数会出发rateLimited。
生成ssl_dhparam(可选)
这是一种用于密钥交换的加密算法。
我们直接生成一个
1
| openssl dhparam -out ~/.acme.sh/dhparam.pem 2048
SHELL
|
这个过程超级无敌慢!其实不生成也没事,后面的nginx删掉对应的一行就行了。
配置Nginx服务
新服务器,啥都没装,装一下
1
| sudo apt install nginx
SHELL
|
创建一个用于配置这个站点的配置文件
1
| sudo vim /etc/nginx/sites-available/immich.coooolfan.com
SHELL
|
这东西好像也没啥要改的,公式化。
需要修改
- 两个server块的
server_name
字段为要监听的域名
ssl_certificate
、ssl_certificate_key
为之前acme输出的路径
ssl_dhparam
为之前生成的dhparam文件的文字,如果没生成那就删掉这行
location
块中的proxy_pass
为反向代理的目标地址
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
| server { listen 80; server_name immich.coooolfan.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; client_max_body_size 0; server_name immich.coooolfan.com;
ssl_certificate /home/yang/.acme.sh/immich.coooolfan.com_ecc/fullchain.cer; ssl_certificate_key /home/yang/.acme.sh/immich.coooolfan.com_ecc/immich.coooolfan.com.key; ssl_session_timeout 5m; ssl_protocols TLSv1 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_dhparam /home/yang/.acme.sh/dhparam.pem;
location / { proxy_pass http://127.0.0.1:2283; proxy_set_header Host $http_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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_redirect off; } }
CONF
|
nginx默认并不会读取文件夹sites-available下的配置文件,我们需要对其创建一个软链接,让文件夹sites-enabled下也有一个一样的文件。
1
| sudo ln -s /etc/nginx/sites-available/immich.coooolfan.com /etc/nginx/sites-enabled/immich.coooolfan.com
SHELL
|
OK!让我们检查一下nginx的配置文件有没有出错
如果没有出错,重启nginx即可
1
| sudo nginx -s reload
SHELL
|
至此,内网访问链路所有流程已完成部署。尝试直接在浏览中输入https://immich.coooolfan.com访问即可。
碎碎念
同一个域名解析得到不同的证书或许不是最佳实践,集中式的证书管理获取是更好的选择,有机会再说吧。