本指南专为已在 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 作为前端服务器。
若您已在主机上设置了 Nginx(例如,在与 Discourse 相同的机器上运行其他网站),您可以跳过此部分,继续下一部分。
为清理 Nginx 的端口,我们必须首先告知 Discourse 监听套接字,而非普通端口:
cd /var/discourse
nano containers/app.yml
注释掉包含 web.ssl.template.yml
和 templates/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
有错误吗?您是否获得了证书?若有,让我们继续!
若您从软件包存储库安装了 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。
请记住根据需要修改站点名称和路径。若您修改了
app.yml
的volumes:
部分,还需要更改proxy_pass
行。
让我们重新加载刚刚更改的配置:
service nginx reload
您的站点现在应该恢复正常,并通过 HTTPS 安全访问。
现在,通过在站点设置中勾选“强制 HTTPS”,告知 Discourse 它应始终使用 HTTPS URL。
我们建议您在您的站点上运行 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/
中。
若您对由不才设计师制作的页面感到满意,您可以直接盗用我的设计
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 进行测试——您应该看到新的错误页面
提供错误页面
最后,我们将设置 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”。