前言
最近折腾群晖 Nas
部署的时候结合路由器遇到一些问题,就写下记录,方便以后踩坑回头再看。这次遇到的问题是自动化更新 SSL
证书,由于家中路由器性能过好承担一些任务,就包括了 SSL
证书更新,群晖那边共用路由器同一个域名,但系统需要 SSL
自定义域名证书,所以本文就是根据自身情况尽节约互联网资源来更新 SSL
证书。
环境
宽带:联通 200M
,支持 IPv6
主路由器:华硕路由器 RT-AX86U
信息如下:
KoolCenter
梅林官改:3004.388.8_2- 安装
DDNS-Go
用于自动更新IP
- 安装
Let's Encrypt
插件用于自动更新域名证书 - 安装
魔法猫咪
用于畅通网络
群晖 Nas
:Synology DS220+
信息如下:
DSM
版本:DSM 7.2.2-72806 Update 1
RAID
类别:RAID0
- 安装
Docker
光猫修改
宽带师傅安装宽带的时候,默认是路由模式,但这样对宽带速度牺牲很大,主要光猫设备性能不咋的,所以要从路由模式修改成桥接,然后用路由器拨号就行,正好尝试下是否有公网地址。
我家的光猫设备类型GPON/4+1(C 系统)
首先需要知道管理员超级密码,光猫后面账号是默认密码,并没什么用,根据我的型号直接进入光猫网关:
光猫后台:http://192.168.1.1/cu.html
开启Telnet:http://192.168.1.1/telnet?enable=1&key=光猫MAC
关闭Telnet:http://192.168.1.1/telnet?enable=0&key=光猫MAC
直接开启 Telnet
后在终端输入:telnet 192.168.1.1
,账号为 admin
密码是 Fh@你家光猫的MAC地址后六位
进来之后输入命令:
/var # load_cli factory
cli main init.....argc=2 /r/n
consoleFd = 3
----cli_main_begin 475 3
########cli sip init ok########
cannot open (fh-bin)confile
cl_run_memfile_config unlocked success!
Config\factorydir# show admin_name
Success! admin_name=CUAdmin
Config\factorydir# show admin_pwd
Success! admin_pwd=CUAdminPs6nAyME
这里面的密码还会随时变,所以需要进入的时候建议从头再查看,然后进入基本配置选项中的网络连接修改成桥接模式即可,这里就不再详细描述,这类教程网上一大把。
AX86U 路由器设置
设置好光猫后在路由器设置拨号账号,输入宽带和密码即可,然后在 IPv6
设置选择 Native
选项即可获取 IPv6
地址。去无线网络 - 专业设置关闭 无线传输公平性
和 通用 Beamforming
选项可以解决家里智能设备离线的问题。去软件中心安装 Let's Encrypt
插件配置好相关配置后,在 USB 相关应用
新建一个 FTP
账号,这个账号用于给群晖自动更新证书用的,这里注意是专门新建一个文件夹,然后文件夹只授权 Read
权限,不需要给他读写权限以免账号被黑。
然后登录路由器生成 RSA
密钥对用于路由器免密登录群晖来执行脚本操作:
# 大多数环境下生成密钥是ssh-keygen,但在华硕路由器命令是dropbearkey
dropbearkey -t rsa -f id_rsa
生成好的密钥 id_rsa
文件放在 ~/.ssh
文件内,然后将 id_rsa.pub
内容复制到记录下来,到后面会用到。
路由器安装的是 Let's Encrypt 插件实际上是 acme.sh
实现的,这里就不关注细节,我找了下插件的位置,在路由器的 /koolshare/scripts/
位置下面的 acme_config.sh
,查阅代码在更新证书任何情况下会走 install_cert
方法,所以在 install_cert
方法结束后执行更新证书到 FTP
公开地方然后再执行群晖的脚本即可:
install_cert(){
# ... 更多内容就不展示了
# 在最后添加下面代码
# 复制证书并且执行群晖脚本
cp /koolshare/acme/你的域名/你的域名.cer /mnt/WDDisk/iNas/cert.pem
cp /koolshare/acme/你的域名/你的域名.key /mnt/WDDisk/iNas/key.pem
cp /koolshare/acme/你的域名/fullchain.cer /mnt/WDDisk/iNas/fullchain.pem
# 此处是群晖 ssh 免密登录执行脚本
ssh -i ~/.ssh/id_rsa root@192.168.50.2 -p2233 '/root/scripts/my_script.sh'
}
Synology 群晖设置
群晖要打开控制面板 - 终端机和 SNMP
- 启用 SSH
,然后修改端口号,建议修改成千位端口号,打开终端登录群晖的 ssh
:
ssh 你的用户名@群晖ip -p 端口号
# 登录 root 账号
sudo -i
cd /root/.ssh
# 如果提示文件不存在那就新建 .ssh 文件夹
mkdir .ssh
cd .ssh
vi authorized_keys
# 将上面路由器复制的 id_ras.pub 文件内容复制进去
chmod 755 ~
chmod 600 ~/.ssh/authorized_keys
vim /etc/ssh/sshd_config
# 编辑 sshd_config 将前面 # 删除
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
然后在群晖 控制面板 -> 终端机和 SNMP
关闭再开启 SSH
,登录路由器输入:
ssh -i ~/.ssh/id_rsa root@192.168.50.2 -p2233
是否直接能登录群晖,如果提示权限不足请检查下是否设置 authorized_keys
权限为 600
。登录成功回到群晖的 ssh
终端在 /root
新建一个文件:
mkdir scripts
vim my_script.sh
脚本内容编写如下:
#!/bin/bash
# 定义FTP相关变量
FTP_SERVER="路由器 ftp 地址包括端口号:192.168.50.1"
FTP_USER="路由器 ftp 账户名"
FTP_PASSWORD="路由器 ftp 密码"
FTP_DIR="路由器 ftp 目录,例如我的是:/WDDisk/iNas/"
# 定义本地相关变量
LOCAL_DIR="."
# 定义证书相关变量
CERT_FILE="cert.pem"
KEY_FILE="key.pem"
PRIVKEY_FILE="privkey.pem"
FULLCHAIN_FILE="fullchain.pem"
# 定义目标目录相关变量
CERT_DIRS=(
"/volume1/docker/AList/ssl/"
"/usr/syno/etc/certificate/system/default/"
"/usr/syno/etc/certificate/_archive/$(cat /usr/syno/etc/certificate/_archive/DEFAULT | tr -d '\n')/"
)
# 定义日志文件路径
LOG_FILE="$HOME/scripts/script_log.txt"
# 日志记录函数
log_message() {
local level=$1
local message=$2
local line_number=${3:-"N/A"}
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo "[$timestamp] [LINE:$line_number] [$level] $message" >> "$LOG_FILE"
}
# 错误处理函数
handle_error() {
local message=$1
local exit_code=${2:-1}
log_message "ERROR" "$message" "${BASH_LINENO[0]}"
exit "$exit_code"
}
# 检查脚本运行环境
check_environment() {
command -v wget >/dev/null 2>&1 || handle_error "wget 命令未安装,请安装后重试。" 2
command -v openssl >/dev/null 2>&1 || handle_error "openssl 命令未安装,请安装后重试。" 2
command -v systemctl >/dev/null 2>&1 || handle_error "systemctl 命令未安装,请检查环境。" 2
}
# 下载证书文件函数
download_file() {
local file=$1
log_message "INFO" "开始下载文件 $file ..." "${BASH_LINENO[0]}"
wget -t 3 -P "$LOCAL_DIR" "ftp://$FTP_USER:$FTP_PASSWORD@$FTP_SERVER$FTP_DIR$file"
if [ $? -ne 0 ]; then
handle_error "文件 $file 下载失败,请检查网络连接或FTP服务器设置。" 3
fi
}
# 转换密钥格式
convert_key_format() {
log_message "INFO" "开始转换密钥格式..." "${BASH_LINENO[0]}"
openssl pkcs8 -topk8 -inform PEM -in "$LOCAL_DIR/$KEY_FILE" -outform PEM -nocrypt -out "$LOCAL_DIR/$PRIVKEY_FILE"
if [ ! -s "$LOCAL_DIR/$PRIVKEY_FILE" ]; then
handle_error "密钥格式转换失败,请检查 openssl 配置及相关文件。" 4
fi
}
# 复制文件到目标目录
copy_and_check() {
local source_file=$1
local target_dir=$2
log_message "INFO" "复制文件 $source_file 到目录 $target_dir ..." "${BASH_LINENO[0]}"
cp -f "$source_file" "$target_dir"
if [ $? -ne 0 ]; then
handle_error "文件 $source_file 复制到 $target_dir 失败,请检查权限或磁盘空间。" 5
fi
}
# 重启服务
restart_service() {
local service=$1
log_message "INFO" "重启服务 $service ..." "${BASH_LINENO[0]}"
systemctl reload "$service"
if [ $? -ne 0 ]; then
handle_error "$service 服务重载失败,请检查配置。" 6
fi
systemctl restart "$service"
if [ $? -ne 0 ]; then
handle_error "$service 服务重启失败,请检查配置。" 7
fi
}
# 清理临时文件
cleanup_files() {
local files=("$@")
log_message "INFO" "开始清理临时文件..." "${BASH_LINENO[0]}"
for file in "${files[@]}"; do
rm -f "$file"
done
log_message "INFO" "临时文件清理完成。" "${BASH_LINENO[0]}"
}
# 主程序
main() {
check_environment
# 下载文件
download_file "$CERT_FILE"
download_file "$KEY_FILE"
download_file "$FULLCHAIN_FILE"
# 转换密钥格式
convert_key_format
# 复制文件到目标目录
for cert_dir in "${CERT_DIRS[@]}"; do
copy_and_check "$LOCAL_DIR/$CERT_FILE" "$cert_dir"
copy_and_check "$LOCAL_DIR/$PRIVKEY_FILE" "$cert_dir"
copy_and_check "$LOCAL_DIR/$FULLCHAIN_FILE" "$cert_dir"
done
# 重启服务
restart_service "nginx"
# 清理临时文件
cleanup_files "$LOCAL_DIR/$CERT_FILE" "$LOCAL_DIR/$KEY_FILE" "$LOCAL_DIR/$PRIVKEY_FILE" "$LOCAL_DIR/$FULLCHAIN_FILE"
log_message "INFO" "脚本执行完成!" "${BASH_LINENO[0]}"
}
# 执行主程序
main "$@"
编写好的脚本再授权:chmod +x ./my_script.sh
,脚本内容主要内容就是从路由器的 FTP
读取 pem
文件然后下载群晖,如果不确定 FTP
是否能用可以用命令测试下:curl ftp://账号:密码@192.168.50.1/WDDisk/iNas/cert.pem
如果有返回内容那就没问题的,群晖下载证书后,还需要将原先的 私钥
转换成 PKCS#8
的格式密钥,然后再将密钥分别复制到几个地方,除了群晖自带的 ssl
默认证书,还涉及到 AList
的 ssl
证书。如果路由器执行定时脚本就会关联执行到群晖的脚本,就不需要操心手动更新这么多证书了。
结束
脚本为什么不用 curl
是因为群晖的 curl
不支付 ftp
协议:
curl -u "iNas:123456" ftp://192.168.50.1/WDDisk/iNas/key.pem
curl: (1) Protocol "ftp" not supported or disabled in libcurl
所以没办法改用 wget
来下载证书。
另外值得注意是 控制面板 - 安全性 - 证书
要先上传自己域名的证书,作为初始化,方便后续脚本自动更新证书。