感谢——我可以确认认证后的信息源本身现在在我这边正在正确生成。
剩下的问题似乎是客户端兼容性:Google 日历和 Outlook 都似乎不愿意直接订阅这种形式的经过身份验证的 ICS 信息源,所以目前我计划通过在单容器 Discourse 安装前面放置一个主机级别的 Nginx 反向代理来解决这个问题,并改为在那里提供一个纯粹的 .ics 文件。
由于我使用的是标准的单容器设置,我认为这意味着需要将端口 80/443 从容器上移开,让 Discourse 监听一个内部的高位端口,然后让主机 Nginx 代理论坛,并同时提供一个静态的日历信息源路径。
粗略地说,我预期会使用的命令是:
# 1. 安装主机 nginx + certbot
sudo apt update
sudo apt install -y nginx snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
# 2. 停止 Discourse 容器以便释放 80/443 端口
cd /var/discourse
sudo ./launcher stop app
# 3. 编辑容器配置,使 Discourse 不再直接绑定到 80/443
sudo nano /var/discourse/containers/app.yml
然后在 app.yml 中将 expose 部分从:
expose:
- "80:80"
- "443:443"
更改为类似以下内容:
expose:
- "127.0.0.1:8080:80"
并且,如果存在,则移除容器 SSL / Let’s Encrypt 模板,以便 TLS 在主机反向代理处终止。
然后重建:
cd /var/discourse
sudo ./launcher rebuild app
然后在主机级别创建一个 Nginx 站点,例如:
sudo nano /etc/nginx/sites-available/discourse
内容大致如下:
server {
listen 80;
listen [::]:80;
server_name forum.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
location /private-calendar/ethan.ics {
alias /var/www/private-calendar/ethan.ics;
default_type text/calendar;
add_header Content-Type "text/calendar; charset=utf-8";
}
}
启用它并重新加载:
sudo mkdir -p /var/www/private-calendar
sudo mkdir -p /var/www/certbot
sudo ln -s /etc/nginx/sites-available/discourse /etc/nginx/sites-enabled/discourse
sudo nginx -t
sudo systemctl reload nginx
然后使用 Certbot 获取 Let’s Encrypt 证书,并让它更新 Nginx 配置:
sudo certbot --nginx -d forum.example.com
sudo nginx -t
sudo systemctl reload nginx
之后,Nginx 配置通常也会包含一个 HTTPS 服务器块,例如:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name forum.example.com;
ssl_certificate /etc/letsencrypt/live/forum.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/forum.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
location /private-calendar/ethan.ics {
alias /var/www/private-calendar/ethan.ics;
default_type text/calendar;
add_header Content-Type "text/calendar; charset=utf-8";
}
}
到那时,我就可以在主机上使用脚本/定时器来获取经过身份验证的 Discourse ICS 并写入:
/var/www/private-calendar/ethan.ics
这样 Google 日历/Outlook 就可以像订阅正常的公共 ICS URL 一样订阅它了。
因此,从我的角度来看,Discourse 这边现在看起来已经解决了;实际剩下的难点主要在于主要的日历客户端对经过身份验证的 ICS 信息源处理得不太好,这就是我目前回退到使用公共代理/静态文件方法的原因。
我还在假设 Certbot 是这里最简单的途径,因为它可以直接针对主机 Nginx 管理 Let’s Encrypt 的签发/续订。我也可以使用 acme.sh,但我的印象是对于这种特定设置,它会是一种更手动化的选择,而不是最直接的路径。