为你的discourse增加离线页面

:warning: 本指南专为已在 Docker 容器外使用 Nginx 的高级用户而设。遵循本指南会使您的设置更加复杂,并且如果您未运行 Ubuntu 16.04 或更高版本,则会损失一些速度优势,例如 HTTP2。请谨慎操作!

当Discourse正在重建或启动时,您的用户通常会从他们的浏览器看到一条错误消息……

…抑或是来自 Nginx 的一个不太友好的 502 错误消息。:

若您如我一般追求完美,或许会觉得这难以接受。所幸,解决此问题相当直接——让我们立即开始吧!

为定制本指南,只需将您的 Discourse 运行域名填入下方框中:

域名

若您已在使用 HTTPS 且已在容器内设置(您正在使用 web.ssl.template.yml 以及可能的 web.letsencrypt.ssl.template.yml),本指南将把您的 SSL 设置从 Docker 容器移至主机上运行的 Nginx,并从 Let’s Encrypt 请求新的证书。这是必要的,因为我们需要 SSL 在 Discourse 重建其 Docker 容器或不可用时也能正常工作。这将中断自动续订,因此您需要每三个月手动续订,或在主机上设置自动续订。

设置 Nginx

若要获得更友好的错误消息,我们需要设置一个前端服务器,通常将所有请求转发至 Discourse,但在无法访问 Discourse 时注入我们的错误消息。本指南使用 Nginx 作为前端服务器。

:bell: 若您已在主机上设置了 Nginx(例如,在与 Discourse 相同的机器上运行其他网站),您可以跳过此部分,继续下一部分。

为清理 Nginx 的端口,我们必须首先告知 Discourse 监听套接字,而非普通端口:

cd /var/discourse
nano containers/app.yml

注释掉包含 web.ssl.template.ymltemplates/web.letsencrypt.ssl.template.yml 的行(如果它们正在使用中)(我们稍后将在主机上设置 HTTPS),添加

  - "templates/web.socketed.template.yml"

作为 templates: 部分的最后一行,并注释掉 expose: 部分的所有端口。

以下是其应有的样子:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 若您希望添加 Let's Encrypt (https),请取消注释以下两行
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
  - "templates/web.socketed.template.yml"

## 此容器应暴露哪些 TCP/IP 端口?
## 若您希望 Discourse 与其他 Web 服务器(如 Apache 或 Nginx)共享端口,
## 请参阅 https://meta.discourse.org/t/17247 了解详情
expose:
  #- "80:80"   # http
  #- "443:443" # https

完成后,保存文件,退出并运行:

./launcher rebuild app

若一切顺利,Discourse 将无法访问,因为它现在仅监听本地套接字。别担心,我们很快会解决这个问题!

接下来,安装 Nginx:

apt-get update
apt-get install nginx

让我们添加一个用于托管本地 Web 内容的位置,然后编辑默认的 Nginx 默认配置文件:

mkdir /var/www
nano /etc/nginx/sites-available/default

添加 HTTPS

在此,我们将配置 Nginx 将所有请求重定向至 HTTPS,并允许从 Let’s Encrypt 请求免费证书。将 /etc/nginx/sites-available/default 的内容替换为:

server {
        listen 80; listen [::]:80;
        server_name discourse.example.com;

        location /.well-known/acme-challenge/ {
                root /var/www;
        }

        location / {
                return 301 https://$host$request_uri;
        }
}

使用以下命令应用更改:

service nginx reload

现在我们可以设置 Let’s Encrypt 并获取证书。若您运行的是 Ubuntu 16.04 或更高版本,可以使用官方软件包:

apt-get update
apt-get install letsencrypt
letsencrypt certonly --webroot -w /var/www -d discourse.example.com

对于其他操作系统,您需要手动安装 certbot 并按如下方式颁发证书:

mkdir /var/letsencrypt
cd /var/letsencrypt
wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto
./certbot-auto
certbot-auto certonly --webroot -w /var/www -d discourse.example.com

有错误吗?您是否获得了证书?若有,让我们继续!

:alarm_clock: 若您从软件包存储库安装了 certbot,续订通常会自动进行。否则,请设置提醒,在证书过期前运行 letsencrypt renew && systemctl reload nginx.service

让我们再次编辑 Nginx 配置以添加 HTTPS 支持:

nano /etc/nginx/sites-available/default

文件中旧的 server 块需要保留——它会将所有用户重定向至 HTTPS。我们需要在旧的 server 块下方添加一个新的 server 块:

server {
  listen 443 ssl http2;  listen [::]:443 ssl http2;
  server_name discourse.example.com;

  # ssl on; <-- 此指令已弃用,请改用 `listen 443 ssl`。
  # 根据需要更改这些路径
  ssl_certificate      /etc/letsencrypt/live/discourse.example.com/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/discourse.example.com/privkey.pem;

  ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
  ssl_protocols TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  add_header Strict-Transport-Security "max-age=63072000;";
  ssl_stapling on;
  ssl_stapling_verify on;

  client_max_body_size 0;

  location / {
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

若您使用的 Nginx 版本尚不支持 HTTP2,请删除上面的 http2(两次)。Ubuntu 16.04.1 中提供的 Nginx 版本可以处理 HTTP2。

:warning: 请记住根据需要修改站点名称和路径。若您修改了 app.ymlvolumes: 部分,还需要更改 proxy_pass 行。

让我们重新加载刚刚更改的配置:

service nginx reload

您的站点现在应该恢复正常,并通过 HTTPS 安全访问。:tada:

现在,通过在站点设置中勾选“强制 HTTPS”,告知 Discourse 它应始终使用 HTTPS URL。

:bell: 我们建议您在您的站点上运行 SSL Server Test (Powered by Qualys SSL Labs),以验证您的 HTTPS 设置是否安全可靠。

创建错误页面

接下来,您需要设计一个错误页面,以便在 Discourse 离线时显示。让我们为其创建一个路径。

mkdir /var/www/errorpages
  • 若您是才华横溢的设计师,请随意自行构建精美的页面,并在此处分享!
  • 若您需要使用外部资源(如图像),请从 /errorpages/ 加载它们。
  • 我建议您在页面中包含 <meta http-equiv="refresh" content="120">——这将每 120 秒刷新页面,这意味着 Discourse 一旦可用,将自动加载。
  • 将您的主 HTML 文件命名为 discourse_offline.html,并将所有文件放置在 /var/www/errorpages/ 中。

若您对由不才设计师制作的页面感到满意,您可以直接盗用我的设计 :blush:

discourse_offline.html|附件 (1.9 KB)
d-logo-sketch.png|附件 (14 KB)
sob.png|附件 (1 KB)

(若您需要帮助将这些文件复制到您的服务器,此帖子 可能会有所帮助。)

完成后,编辑 Nginx 配置以提供您刚刚创建的页面:

nano /etc/nginx/sites-available/default

只需将

location /errorpages/ {
    alias /var/www/errorpages/;
}

添加到 Nginx 配置的 HTTPS server 部分,然后重新加载。

service nginx reload

通过在浏览器中访问 https://discourse.example.com/errorpages/discourse_offline.html 进行测试——您应该看到新的错误页面 :no_entry:

提供错误页面

最后,我们将设置 Nginx,使其在无法访问 Discourse 或 Discourse 尚未准备就绪时提供您的错误页面。将以下行添加到 location / 块:

error_page 502 =502 /errorpages/discourse_offline.html;
proxy_intercept_errors on;

像往常一样应用您的更改:

service nginx reload

若要测试您的设置,请运行

cd /var/discourse
./launcher stop app

使您的站点离线并尝试访问它:

之后不要忘记运行

cd /var/discourse
./launcher start app

以便您的 Discourse 再次可用!

附言:请勿尝试在一周内重复此过程超过 2-3 次。因为 Let’s Encrypt 不允许您从其服务器获取证书超过 5 次。若您已达到此限制,则要么必须等待 7 天(从您在 7 次尝试中请求第一个证书之日起计算),要么必须在某个子域中设置您的站点,例如在其前面添加“www”。