Discourseが再構築中または起動中に表示するオフラインページを追加する

フォーラムに500kbを超える.pngファイルをアップロードできない明らかな理由がありますか?このガイドに従ったのですが。

client_max_body_size 0;という行について話しているのを見ましたが、それは問題ではないはずですよね?

編集:投稿後にすぐに解決しました。設定で「:white_check_mark: force https」を確認する必要がありました。将来同様の問題が発生する人のために、この投稿を残しておきます。

「いいね!」 3

ここで指摘されているのは、次のとおりです。

nginx は Connection: close ヘッダーを無効にし、proxy_http_version 1.1 を設定することを推奨しています。そのため、以下のようになります。

    proxy_http_version 1.1;
    # デフォルトの「Connection: close」を無効にする
    proxy_set_header "Connection" "";

Connection: close が Unix ドメインソケットに影響を与えるかどうかについては、ドキュメントで見つけることができませんでしたが、このドキュメントは外部プロキシを別のシステムで実行する場合にも役立つため、ここで削除することを推奨しても問題ないかもしれません。

「いいね!」 1

SELinux(enforcingモード)が有効なシステムにデプロイした場合、ホストがコンテナと通信するためにUnixドメインソケットを使用することはできません。Unixドメインソケットのラベルを変更しても、コンテナを再起動するたびにラベルなしで再作成されてしまうためです。代わりに、2つの変更を行う必要があります。

nginxがエラーページにアクセスできるようにし、Unixドメインソケット経由のプロキシからポートへの切り替えが必要です。これにより、SELinuxをセキュリティレイヤーの1つとしてnginxを実行する際のレイテンシがリクエストごとに数マイクロ秒増加しますが、ユーザーには知覚できないでしょう。

まず、nginxがネットワーク接続を行えるようにし、エラーページにアクセスできるようにするには、次のコマンドを実行します。

setsebool -P httpd_can_network_connect 1
semanage fcontext -a -t httpd_sys_content_t /var/www
restorecon -R -v /var/www

次に、app.yamlで- "templates/web.socketed.template.yml"をコメントアウトまたは削除し、ローカルマシンで別のポートとしてポート80を公開し、コンテナを再構築します。

expose:
  - "8008:80"   # http

ここではhttpsを使用しないでください。SSLは外部nginxで終了しており、X-Forwarded-ProtoヘッダーがDiscourseにリクエストがhttps経由で受信されたことを伝えます。ポート8008(または選択したその他のポート)がファイアウォール設定によって公開されていないことを確認してください。

次に、外部nginxの設定をnginx.http.sock経由のプロキシからhttp://127.0.0.1:8008(または選択したポート)に変更し、デフォルトのConnection: closeヘッダーをクリアして、外部nginxがリクエストごとに新しいIP接続を確立する必要がないようにします。

...
  location / {
    proxy_pass http://127.0.0.1:8008;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    # Disable default "Connection: close"
    proxy_set_header "Connection" "";
...
「いいね!」 1

@sam(そしておそらく@falco)さん。私はこれらの#documentation:sysadminドキュメントの一部を整理するタスクを任されています。このドキュメントは非常に多くの閲覧数がありますが、最も役に立たないものの一つだと思います。

haproxy - Official Image | Docker Hubnginx - Official Image | Docker Hub を、おそらくdocker composeで起動する代替案を作成するのは理にかなっていると思いますか?nginxコンテナがdiscourseコンテナから証明書をマウントし、haproxyがTCPモードで次のようなことを行うようにします(これは機能しないと思いますが、機能するものを突き止められると推測します)。

backend my_app_be
    balance roundrobin
    option httpchk HEAD /srv/status
    server discourse app:443 check
    server fallback nginx:80 check backup

このトピックよりも分かりやすい、実用的な解決策になるのではないかと思います。その後、このトピックは歴史的な目的のために残しておき(そしておそらく閉じる?)、上記で説明したトピックにリンクします。

「いいね!」 3

このトピックは、以下のトピックとかなりの重複があることに注意してください。

そのトピックは最近大幅に更新され(さらに重複が増えました)、オフラインページの部分をメモとしてそちらにマージし、このトピックを非推奨として代替へのリンクを示すのが理にかなっているかもしれません(すでに別のNginxインスタンスを実行している場合は簡単に追加できます)。

提案されたHAProxyトピックは、他の理由でフロントNginxをインストールしたくない人々のためのデフォルトの方法として、引き続き意味をなすでしょう。

「いいね!」 2

どうすればわかったでしょうか?

ああ。

しかし真面目な話、あなたの解決策は私のよりも優れていると思います!

そして、そのトピックには大きな文字で「高度なトピック」と書かれています。

しかし、ほとんどの人はNginxをよりよく理解しているので、それも必要ないかもしれません。今、考え始めていますが、難しいのは私を止めさせることです。 :slight_smile:

「いいね!」 3

代替手段がたくさんあるのは常に良いことです。しかし、これは最も簡単なものの1つであり(かなりの数がありますが…)、多くの人にとって馴染みのあるものです。

ですから、どうか、これをいじらないでください。

そして、これをそのままにしておくことにもう1つの利点があります。検索結果です。トラフィックが多く(タグの使用が非常に限られているため…)、ここで何か特定のものを探すのは最近非常に困難です。しかし、これは見つけやすく、非常に的を絞った目的があります。このトピックが別のものに移動すると、見つけるのがさらに難しくなります。

これがこれほど人気があるのには理由があります…DockerやHaproxyを使用することにそれほど触発されていない人はそれほど多くありません。

「いいね!」 2

ため息。まあ、それも本当だと思いますが、少なくとも4年前の情報です。最近はやっていませんが、もう手動でファイルを変更する必要はなく、acme(またはそれに類するもの?)がやってくれます。

私が本当に思うのは、ダウンタイムがほとんどない2コンテナインストールを使用する方が、ページを公開するためにこれらのハードルを飛び越えるよりもはるかに理にかなっているということです。しかし、それも人々を説得できません。

ですから、今日どのように物事が機能するかを書き直すのが良いかもしれません。

「いいね!」 1

そして、それははるかに困難です。sql-sideなどのコンテナをいつ、どこで更新するかを教えるのではなく、certbotのインストールと使用方法の指示を修正する方が簡単だと思います。

さらに、Dockerに対するもう一つの反対点があります(Discourseでさえそのように機能しています…):そもそもDockerの使用方法など、非常に基本的なレベルの質問をたくさん見つけることができます。または、ymlファイルでタイプミスを回避する方法 :wink:

それでも機能します(SSLセクションは少し紛らわしいですが、4年前でさえそうでした ;))

いいえ。私は他のソリューションに反対しているわけではありません。非常に確固たる理由なしに古いリンクやテキストを新しい場所に移動しなければならないことには非常に反対です。

「いいね!」 2

その点については意見が分かれると思いますが、あなたに同意する人がたくさんいる可能性が高いと思います。(おそらくこのソリューションは「設定して忘れる」ソリューションであり、2コンテナソリューションはPostgresのアップグレード(約2年に1回発生)に注意を払う必要があります。)

OK。その点については同意します!ですから、その部分を整理するために何ができるかを見て、haproxyソリューションを保留にするのが前進する方法だと思います。

「いいね!」 1

Discourse でこれが行われるのを見るのが待ちきれませんが、@fefrei さん、ありがとうございます!素晴らしい出来栄えです!Apache を使用してこれを行います。少なくとも基本的な手順は同じはずです。

「いいね!」 1

OK、希望通りにするのに2時間かかりました!

DiscourseメンテナンスページとApache2

rootとして

cd /var/discourse
nano containers/app.yml

これらの行をコメントアウトします:

  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

expose:
  #- "80:80"   # http
  #- "443:443" # https

templatesセクションの末尾に追加します(最後でなければなりません):

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

注意:これにより、Discourseは内部IPのみでリッスンし、apache2が80/443ポートとSSL終端を引き継ぎます。

注意:これが有効になるには、Discourseを再構築する必要があります:

cd /var/discourse
./launcher rebuild app

apache2とcertbotをインストールします

apt install -y apache2 certbot python3-certbot-apache

HTMLページ用のディレクトリを作成します:

mkdir /var/www/discourse_maintenance

HTMLページ:
/var/www/discourse_maintenance/discourse_maintenance.html

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="refresh" content="5">
        <title>Discourse Maintenance</title>
        <style>
            .center {
                display: flex;
                justify-content: center;
            }
            .container {
                max-width: 500px;
                padding: 50px 50px 30px 50px;
            }
            .title {
                padding-top: 20px;
            }
            h1, p {
                font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
            }
        </style>
    </head>
    <body>
        <div class="center">
            <div class="container">
                <h1 class="title">Discourse Maintenance&hellip;</h1>
                <p>We are currently upgrading the site, or performing scheduled maintenance.</p>
                <p>You'll automatically be redirected to the site once it's available.</p>
            </div>
        </div>
    </body>
</html>

Proxyモジュールを有効にします:

a2enmod proxy
a2enmod proxy_http
a2enmod headers

Apache vhostファイル:

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName your.discourse.domain
  ServerAdmin your@email.com
  DocumentRoot /var/www/discourse_maintenance

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  # Maintenance Mode
  RewriteEngine On
  RewriteCond /var/www/under_maintenance -f
  # safety check to prevent redirect loops 
  RewriteCond %{REQUEST_URI} !/discourse_maintenance.html$
  # redirect internally all requests to maintenance.html 
  RewriteRule ^.*$ /var/www/discourse_maintenance/discourse_maintenance.html

  ProxyPass / unix:///var/discourse/shared/standalone/nginx.http.sock|http://127.0.0.1/
  ProxyPassReverse / unix:///var/discourse/shared/standalone/nginx.http.sock|http://127.0.0.1/

  SSLCertificateFile /etc/letsencrypt/live/your.discourse.domain/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/your.discourse.domain/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

メンテナンスを有効にするには touch /var/www/under_maintenance を実行します。

メンテナンスを無効にするには touch /var/www/under_maintenance を実行します。

クレジット:Add an offline page to display when Discourse is rebuilding or starting up (初期のアイデア、HTMLページ(私の好みに合わせてトリミング/編集)、およびそれに基づいてApache構成を作成したnginx構成について)

編集:502/503が応答した場合に自動化する提案を歓迎します。試しましたが、希望通りに動作させることができなかったため、バックエンドアプリケーションがメンテナンスなどでダウンしている場合に他のWebサーバーで使用している既知の方法を採用しました。

「いいね!」 2

システム再起動時に、dockerが起動するまでエラー/メンテナンスページが表示されるのを遅らせることになりますが、これはシステムの起動よりもかなり時間がかかります。また、システムnginxのシステム提供のSELinux保護のオプションも提供されません。システムnginxを使用すると、少なくともsystemdで管理されているシステムでは、起動が速いため、起動から数秒以内にエラーページを表示できます。私の場合、これはシステムアップデートで再起動が必要な場合に、システムが非常に速くメンテナンスページで応答することを意味します。(私はホストでAlmaLinux 9を実行しており、nginxまで非常に速く起動します。)

haproxyの代替案を文書化し、経験を比較することは理にかなっているかもしれませんが、docker内のhaproxyは外部nginxの直接的な代替ではありません。このトピックを閉じるのは間違いでしょう。

可用性だけの問題ではありません。

IPv4経由で外部トラフィックにdockerを使用すると、内部nginxとDiscourseから外部IPv6アドレスが隠されます。 haproxyでも同じ問題が発生します。127.0.0.1または172.* RFC1918のローカル専用IPアドレス空間のアドレスについてログを確認してください。外部プロキシを使用しないと、すべてのIPv6トラフィックが同じIPとして表示され、すべてのIPv6トラフィックを単一のゾーンと見なす内部nginxのゾーンレート制限が壊れます。

IPv6はますます重要になっています。

「いいね!」 2

今朝、偶然にもこの手順が Unix ソケットの適用を回避するだけでなく、real_ip モジュールの使用も削除し、レート制限が IP ごとのすべての接続ではなく、すべての接続全体で適用されることを発見しました。おそらく、変数を含む新しいテンプレートに貢献すべきですが、現時点では、これを app container YAML ファイルに追加しました。

run:
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 80;/
     to: |
       listen unix:/shared/nginx.http.sock;
       set_real_ip_from 172.0.0.0/24;
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 443 ssl http2;/
     to: |
       listen unix:/shared/nginx.https.sock ssl http2;
       set_real_ip_from 172.0.0.0/24;

たとえば、Unix ドメインソケットを使用せずに、アドレスの変数を持つ templates/web.httpratelimit.yml ファイルのようなものを持つことが理にかなっているかどうかはわかりません。それについての考えは?

「いいね!」 2
server {
  listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2;
  server_name DOMAIN;
  ssl_certificate      /etc/letsencrypt/live/DOMAIN/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/DOMAIN/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 / {
    error_page 502 =502 /errorpages/offline.html;
    proxy_intercept_errors on;

    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;
  }

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

! # ドメインとエラーファイルのパスを変更してください

SSL付きで動作するスクリプトを入手しました

「いいね!」 2

このガイドを試しましたが、動作しませんでした。

まず、Nginxプロキシを使用して単一のDiscourseコンテナから2つのサイトを実行しました。エラーページの部分を追加したかっただけなので、https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247と重複するように見えた部分はスキップしました。しかし、重要なステップをいくつか見落としたようです。最終的に、[このDigitalOceanチュートリアル](https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-to-use-custom-error-pages-on-ubuntu-22-04)から必要なものを得ました。手動で設定するのは難しいことではありませんが、もっと良い方法があるはずだと思います。

Discourseを実行する標準的な方法としてDockerが普及していることを考えると、これはより良い方法のように思えます。一度設定すれば、あとは忘れてしまえるようなものだと想定しています。

「いいね!」 3

このスレッド内のアイデアは、スタンドアロンアプリケーションとして、またはCloudflare Tunnelsを使用している場合であっても、リバースプロキシとしてCaddyを実行している私たちにとっても素晴らしいものです。

discourse.example.org {
        reverse_proxy <host | ip>:port

        handle_errors 5xx {
                root * /path/to/error-pages
                rewrite * /error.html
                file_server {
                        status 404
                }
        }
}

status 404セクションは、Cloudflare Tunnelsを使用している場合にのみ重要です。CaddyがCloudflareに5xxを返すと、Cloudflare Tunnelは独自の切断エラーを表示します。ステータスを変更すると、Cloudflareにエラーページを提供する有効なライブ接続があることを示します。

「いいね!」 2

私の理解が間違っているかもしれませんが、リフレッシュはすでに開いているページをリフレッシュするだけではありませんか?それによって、どのようにして別のURLに戻るのですか?

URLを変更する必要はありません。トリックは、エラーページがユーザーがアクセスしようとしたURL(例:https://meta.discourse.org/t/add-an-offline-page-to-display-when-discourse-is-rebuilding-or-starting-up/45238/158)で直接提供され、リロードされるのはその正確なURLであるため、再度同じエラーが表示されるか、ユーザーが求めていたページが表示されることです :slight_smile:

なるほど、わかりました。オフラインページ用に別のサーバーを使用しているので、全体の設定を注意深く読んでいませんでした。万が一マシンがダウンしたときに備えてのことです。
しかし、理にかなっていますね。今は、元のURLにリダイレクトするはずのJavaScriptを動作させることを試みているところです…