Спасибо — могу подтвердить, что аутентифицированная лента теперь генерируется корректно с моей стороны.
Оставшаяся проблема, похоже, связана с совместимостью клиентов: ни Google Calendar, ни Outlook не хотят подписываться напрямую на аутентифицированную ICS-ленту в таком виде, поэтому пока я планирую обойти это, установив обратный прокси Nginx на уровне хоста перед моей одноконтейнерной установкой Discourse и предоставляя там обычный файл .ics.
Поскольку я использую стандартную одноконтейнерную конфигурацию, это означает перенос портов 80/443 с контейнера, настройку Discourse на прослушивание внутреннего высокопортового порта, а затем использование Nginx на хосте для проксирования форума и обслуживания статического пути к календарной ленте.
Примерно команды, которые я планирую использовать:
# 1. Установка host 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
Затем получить сертификат Let’s Encrypt с помощью Certbot и разрешить ему обновить конфигурацию 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";
}
}
На этом этапе я могу использовать скрипт/таймер на хосте для получения аутентифицированной ICS-ленты Discourse и записи в:
/var/www/private-calendar/ethan.ics
что Google Calendar / Outlook смогут подписаться как на обычную публичную ICS-ссылку.
Таким образом, с моей стороны сторона Discourse теперь выглядит решённой; остаётся лишь практический пробел в том, что основные клиенты календарей не особенно хорошо работают с аутентифицированными ICS-лентами, поэтому я пока возвращаюсь к подходу с публичным прокси/статическим файлом.
Я также предполагаю, что Certbot — самый простой путь здесь, поскольку он может напрямую управлять выпуском/обновлением сертификатов Let’s Encrypt для Nginx на хосте. Я также мог бы использовать acme.sh, но, по моим представлениям, это потребовало бы более ручного выбора и не было бы самым прямым путём для данной конкретной конфигурации.