前期准备(默认你已经具备)

  1. 如果你的内网nas使用的是群晖系统,则一定要先干掉系统自带的的nginx
  2. 一个合法的域名。(本文均使用www.rikinyoung.com示例)
  3. 公网服务器,无需高配。
  4. 你的内网nas。(后文均使用docker安装所用项目)
  5. 均能使用ssh连接上述两台实例。
  6. 文中代码块出现的中文部分,均需根据读者情况自行修改。
  7. 会使用命令行等方式安装和启动docker镜像。

打通公网

1. 安装 frps

在公网服务器中安装frps,ssh登录公网服务器,创建frps目录:

mkdir /usr/local/frps && cd /usr/local/frps

在frp的官方仓库中找到对应系统的tar包,以笔者为例,get下来:

wget https://github.com/fatedier/frp/releases/download/v0.65.0/**frp_0.65.0_linux_arm64**.tar.gz && tar -xzvf **frp_0.65.0_linux_arm64**.tar.gz

我们只用到其中的fprs,提取出来:

mv ./**frp_0.65.0_linux_arm64**/frps ./ && mv ./**frp_0.65.0_linux_arm64**/frps.toml ./

然后就可以把其他的删了。

2. 配置 frps

不同版本的frp,其配置文件的书写差距较大,笔者安装的为最新版本的frps,使用toml格式的配置文件,下列仅供参考:

#监听端口和域名
bindPort = frp监听端口

#webui面板端口,可选
[webServer]
addr = "127.0.0.1"
port = 7500
user = "账户名"
password = "账户密码"

#身份验证
[auth]
method = "token"
token = "你的frp密钥"

3. 使用 systemd 管理 frps 服务

安装systemd:(如果没有)

# 使用 yum 安装 systemd(CentOS/RHEL)
yum install systemd

# 使用 apt 安装 systemd(Debian/Ubuntu)
apt install systemd

创建 frps.service 文件:

vim /etc/systemd/system/frps.service

写入内容:

[Unit]
# 服务名称,可自定义
Description = frp server
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /usr/local/frp/frps -c /usr/local/frp/frps.toml

[Install]
WantedBy = multi-user.target

启动frps:

sudo systemctl start frps

设置frps开机自启动:

sudo systemctl enable frps

至此公网服务器的任务完成。

4. 安装 frpc

在内网nas上安装frpc,使用镜像snowdreamtech/frpc,网络使用host模式,映射容器路径/etc/frp,将下述toml文件放进去。
我知道你还没有安装ss服务,先配置了再说。

# 服务端连接配置
serverAddr = "你的公网服务器ip地址"
serverPort = frp监听端口

[auth]
method = "token"
token = "你的frp密钥"

# 映射 ss
proxies
name = "ss"
type = "tcp"
localIP = "你的NAS的ip"
localPort = ss监听端口(尽量大一点)
remotePort = ss监听端口(可以与上述端口不同,笔者建议保持一致)

启动frpc,不出所料你应该能在frps的webui中看到已经成功打通ss监听端口。
需要注意的是,不要忘记在公网服务器上打开防火墙端口!,包括frp的监听端口和ss监听端口。

5. 安装 ss

不作详细展开,使用**teddysun/shadowsocks-rust**镜像,host网络安装,映射容器路径/etc/**shadowsocks-rust**/config.json对应下述json文件。注意映射路径和镜像名的对应关系。

{
    "server": "::",
    "server_port": ss监听端口(尽量大一点),
    "password": "ss的连接密钥",
    "method": "2022-blake3-aes-128-gcm",
    "dns": "你的NAS的ip",
    "mode": "tcp_and_udp" 
}

启动ss,后续再配置相关代理。
注意,ss的连接密钥需要在终端中使用openssl rand -base64 16命令生成,自己填则会报错
值得一提的是,如果读者使用的加密方式为aes-256-gcm,则需要将上述命令的16改为32。

打通内网

1. 安装 Caddy

群晖系统请确认已经干掉自带的nginx。
创建名为caddy的docker网络:

docker network create -d bridge caddy

进入你的docker目录,克隆Caddy仓库:

git clone https://github.com/Xm798/docker-caddy.git

更改docker-compose文件,以下供参考:

services:
  caddy:
    container_name: caddy
    image: xm798/caddy:latest
    user: 1026:100
    extra_hosts:
      - "host.docker.internal:host-gateway"
    dns:
      - 8.8.8.8
      - 1.1.1.1
      - 1.0.0.1
      - 223.5.5.5
      - 119.29.29.29
    networks:
      - caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfiles:/etc/caddy
      - ./data:/data
      - ./config:/config
      - ./log:/log
      - ./srv:/srv
    restart: always

networks:
  caddy:
    external: true

使用上述配置文件后,Caddy后续配置可用host.docker.internal代替Nas的ip。
创建映射所需的目录:

mkdir data config log srv

docker,启动!

docker compose up -d
#群晖环境使用:
docker-compose up -d

2. 配置 Caddy

启动过一次后,编辑 Cad­dy­files 目录下 Cad­dy­file 文件,在第一个花括号内,添加你正在使用的 DNS 提供商的信息,为后续自动申请 SSL 证书做准备:
阿里云:

{
    http_port 80
    https_port 443
    email 你的阿里云登录账户
    acme_dns alidns {
        access_key_id "密钥id"
        access_key_secret "登录密钥"
    }
}

Cloud­flare:

{
    http_port 80
    https_port 443
    email user@example.com
        acme_dns cloudflare "你CF的token"
}

DNS­POD:

{
    http_port 80
    https_port 443
    email user@example.com
        acme_dns dnspod "你的id,你的token"
}

务必确认使用的Caddy镜像中,包含你使用的DNS服务商的对应插件,否则Caddy将无法启动。

3. 配置Caddy反代服务

在Cad­dy­files 目录下新建后缀名为Cad­dy­file的文件,例如反代https下群晖的DSM,并忽略证书验证,新建nas.Cad­dy­file

nas.rikinyoung.com {
  reverse_proxy {
        to https://host.docker.internal:5001
        transport http {
            tls
            tls_insecure_skip_verify
        }
    }
}

是不是很简单?来点进阶的,记得我们刚刚创建了名为caddy的docker网络吗?
将需要反代的容器全都放进caddy网络内,则可以不映射服务端口,在docker网络内部直接通过Caddy反代访问服务。如果不理解docker网络的话,听着可能有些绕,我们以emby举例:

emby.rikinyoung.com {
  reverse_proxy http://emby:8096
  #此时可以使用容器名:端口号的方式
}

将emby加入到caddy网络中,此时尽管8096端口没有映射,依然可以访问!
这样做的好处是不暴露容器端口,相对更加安全。
对这部分感兴趣的话,可以学习了解下docker网络的工作原理,官方文档事无巨细。
笔者的docker知识基本全是在官方文档学的
当然,你也可以像nginx那样把静态网页托管给Caddy,它的srv路径相当于nginx的www,例如:

home.rikinyoung.com {
  root * /srv/homepage
  file_server
}

这样在内网环境下访问home.rikinyoung.com会进入homepage页面。
修改Cad­dy­file文件后使用下列命令重载配置:

docker exec -w /etc/caddy caddy sh -c "caddy fmt --overwrite && caddy reload"

4. 安装 adguard

adguard在这里只负责改写DNS,且只改内网Nas的DNS,这样才能正确通过上述的域名和子域名访问对应服务。
以下compose文件供参考:

services:

  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguard
    network_mode: host
    volumes:
      - ./work:/opt/adguardhome/work
      - ./conf:/opt/adguardhome/conf
    environment:
      - PUID=1026
      - PGID=100
      - TZ=Asia/Shanghai
    logging:
      driver: "json-file"
      options:
        max-file: "10"
        max-size: 10m
    restart: always
    dns:
      - 223.5.5.5
      - 119.29.29.29

访问你的nas的ip:3000进入adguard的安装页面,将网页管理也就是webui的端口配置为3000,设置帐号密码。
安装完成后使用ctrl F5的组合键刷新网页,否则可能无法登录。

5. 配置 adguard

建议将内网服务托管到子域名,而不要占用根域名。
登录成功后点击过滤器-DNS重写-添加DNS重写,将泛域名*.rikinyoung.com重写到你的Nas的ip
至此所有准备都已经完成~

配置代理

在你的神秘软件中,添加自己的节点,切换为全局模式进行测试,添加格式为:

proxies:
    - name: 节点名
      type: ss
      server: www.rikinyoung.com
      port: ss监听端口(尽量大一点)
      password: ss的连接密钥
      udp: true
      cipher: 2022-blake3-aes-128-gcm

若此时成功访问home.rikinyoung.com进入homepage页面,或是访问nas.rikinyoung.com进入DSM,则恭喜你,欢迎回家!

覆写代理

上述的回家方式限制居多,包括但不限于无法正常访问其他页面,无法访问某些“不存在的页面”。
若直接写入订阅中,订阅的频繁更新则会覆盖配置,笔者也不止一个订阅,非常的不现实。
但是如果你的神秘软件有覆写功能,建议将节点写到全局覆写中。
以下仅供参考!

+proxies:
    - name: 节点名
      type: ss
      server: www.rikinyoung.com
      port: ss监听端口(尽量大一点)
      password: ss的连接密钥
      udp: true
      cipher: 2022-blake3-aes-128-gcm

+proxy-groups:
  - name: 内网
    type: select
    proxies:
    - 节点名

+rules:
  - DOMAIN,www.rikinyoung.com,DIRECT
  - DOMAIN,static.rikinyoung.com,DIRECT
  - DOMAIN-SUFFIX,rikinyoung.com,内网

实现只在访问内网服务的时候流量走代理,而访问博客、博客的静态资源等其他流量照常。
直连规则需配置在内网规则前,靠前的规则会覆盖靠后的规则。
顺带的,可以在公网服务器上,把rikinyoung.com不用的子域名统统重定向到根域名,这样无论公网怎么访问,都会跳转到笔者的博客页面。

原理

启动神秘软件后,主机访问内网服务.rikinyoung.com时流量会走代理,也就是frp映射出来的ss端口,ss将流量转发到Nas,因为Nas收到的是域名,会查询DNS找对应的ip,而DNS被adguard改写了,找到的是Caddy,通过Caddy反代访问实际服务,藉此通过域名实现了公网访问内网服务。
一环扣一环,环环相扣,一人一句docker码头nb来!

参考