على الرغم من أن نشر Discourse باستخدام دليل التثبيت الرسمي هو الخيار الأكثر ملاءمة وأمانًا، إلا أنني أرغب في الغوص أعمق في الحاوية ورؤية كيفية نشرها في Linux دون استخدام Docker. أريد مشاركة الخطوات لمجرد اطلاعك. يمكنك تعديلها واستخدامها على مسؤوليتك الخاصة.
تعمق في كيفية تشغيل Discourse في حاوية
ألقي نظرة على إخراج الأمر ./launcher start-cmd webonly:
true run --shm-size=512m --link data:data -d --restart=always -e LANG=en_US.UTF-8 -e RAILS_ENV=production … --name webonly -t -v /var/discourse/shared/webonly:/shared … local_discourse/webonly /sbin/boot
ثم أنظر إلى /sbin/boot و /etc/service/unicorn/run، وأحصل على الأمر الأساسي لتشغيل Discourse:
LD_PRELOAD=$RUBY_ALLOCATOR HOME=/home/discourse USER=discourse exec thpoff chpst -u discourse:www-data -U discourse:www-data bundle exec config/unicorn_launcher -E production -c config/unicorn.conf.rb
إعداد النظام
للمعلومية، أستخدم Ubuntu 24.04 و zsh.
اتبع دليل التثبيت الرسمي الخاص بـ PG لتثبيت postgres من مستودع PostgreSQL Apt. قمت بتثبيت الإصدار 18، والذي يعمل بشكل جيد جدًا، على الرغم من أن التثبيت الرسمي يستخدم الإصدار 15 في وقت الكتابة.
قم بتثبيت redis (الإصدار 8.2 في وقت الكتابة، يستخدم التثبيت الرسمي 7.0)، و nginx وأنشئ مستخدمًا مخصصًا discourse:
apt install nginx libnginx-mod-http-brotli-static redis zsh zsh-autosuggestions zsh-syntax-highlighting
systemctl enable --now postgresql redis nginx
useradd -m -s /bin/zsh discourse
قم بتثبيت ImageMagick 7 (أستخدم IMEI) وتحقق من الإصدار. إعدادي هو:
magick --version
Version: ImageMagick 7.1.2-3 Q16-HDRI
ثم، غيّر المستخدم (su - discourse) وقم بتثبيت pnpm و rvm.
curl -fsSL https://get.pnpm.io/install.sh | zsh -
curl -sSL https://get.rvm.io | bash
ثم قم بتعديل وإضافة التكوين التالي إلى .zshrc الخاص بك
/home/discourse/.zshrc
# pnpm
export PNPM_HOME="/home/discourse/.local/share/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end
alias npm='pnpm'
alias npx='pnpx'
# إضافة RVM إلى PATH للبرمجة. تأكد من أن هذا هو تغيير متغير PATH الأخير.
export PATH="$PATH:$HOME/.rvm/bin"
export ALLOW_EMBER_CLI_PROXY_BYPASS=1
export RAILS_ENV=production
export UNICORN_SIDEKIQ_MAX_RSS=1000
export UNICORN_WORKERS=4
export UNICORN_SIDEKIQS=1
export PUMA_SIDEKIQ_MAX_RSS=1000
export PUMA_WORKERS=4
export PUMA_SIDEKIQS=1
#export RUBY_YJIT_ENABLE=1
#export RUBY_CONFIGURE_OPTS="--enable-yjit"
export DISCOURSE_HOSTNAME=example.com
export DISCOURSE_DEVELOPER_EMAILS=discourse-admin@example.com
export DISCOURSE_MAXMIND_ACCOUNT_ID=<id>
export DISCOURSE_MAXMIND_LICENSE_KEY=<key>
export DISCOURSE_ENABLE_CORS=true
export DISCOURSE_MAX_REQS_PER_IP_MODE=none
export DISCOURSE_MAX_REQS_PER_IP_PER_MINUTE=20000
export DISCOURSE_MAX_REQS_PER_IP_PER_10_SECONDS=5000
export DISCOURSE_MAX_ASSET_REQS_PER_IP_PER_10_SECONDS=20000
export DISCOURSE_MAX_REQS_RATE_LIMIT_ON_PRIVATE=false
export DISCOURSE_MAX_USER_API_REQS_PER_MINUTE=200
export DISCOURSE_MAX_USER_API_REQS_PER_DAY=28800
export DISCOURSE_MAX_ADMIN_API_REQS_PER_MINUTE=600
export DISCOURSE_MAX_DATA_EXPLORER_API_REQ_MODE=none
export DISCOURSE_MAX_REQS_PER_IP_EXCEPTIONS="127.0.0.1 ::1"
cd /var/www/discourse
قم بتسجيل الخروج وتسجيل الدخول مرة أخرى كمستخدم discourse ليتم تفعيل .zshrc.
قم بتثبيت node و ruby:
pnpm env use --global latest # سيقوم بتثبيت node 24.9 في وقت الكتابة. يستخدم التثبيت الرسمي 22
rvm get master
rvm install 3.4 # سيقوم بتثبيت ruby 3.4.6 في وقت الكتابة. يستخدم التثبيت الرسمي 3.3
rvm use 3.4 --default
إعداد قاعدة البيانات ( واستعادة نسخة احتياطية)
sudo -u postgres createuser -s discourse
sudo -u postgres createdb discourse
$sudo -u postgres psql discourse
psql>
ALTER USER discourse WITH PASSWORD 'xxx';
CREATE EXTENSION hstore;CREATE EXTENSION pg_trgm;
CREATE EXTENSION plpgsql;
CREATE EXTENSION unaccent;
CREATE EXTENSION vector;
# لاستعادة قاعدة البيانات المستخرجة من نسخة احتياطية:
$ gunzip < dump.sql.gz | psql discourse
لاستعادة النسخة الاحتياطية، تحتاج أيضًا إلى نسخ مجلدات public و plugins.
تثبيت Discourse
كمستخدم root:
cd /var/www/
git clone https://github.com/discourse/discourse
mkdir -p /var/www/discourse/public
chown -R discourse:discourse /var/www/discourse/
chown -R discourse:www-data /var/www/discourse/public
قم بتكوين config/discourse.conf:
config/discourse.conf
max_data_explorer_api_req_mode = 'none'
max_user_api_reqs_per_day = '28800'
hostname = '127.0.0.1'
hostname = 'example.com'
redis_host = '127.0.0.1'
db_password = '<password>'
db_socket = ''
max_reqs_per_ip_per_10_seconds = '5000'
max_asset_reqs_per_ip_per_10_seconds = '20000'
max_reqs_rate_limit_on_private = 'false'
developer_emails = 'discourse-admin@example.com'
max_user_api_reqs_per_minute = '200'
maxmind_license_key = '<key>'
maxmind_account_id = '<id>'
max_reqs_per_ip_per_minute = '20000'
db_host = '127.0.0.1'
enable_cors = 'true'
db_port = ''
max_reqs_per_ip_mode = 'none'
max_admin_api_reqs_per_minute = '600'
smtp_user_name = '<name>'
smtp_address = 'postal.example.com'
smtp_port = '25'
smtp_password = '<password>'
smtp_domain = 'postalsend.example.com'
notification_email = 'noreply@postalsend.example.com'
قم بتنفيذ تثبيت bundle / pnpm، وهجرة قاعدة البيانات، وتجميع الأصول مسبقًا. هذا أيضًا كيف تقوم بترقية discourse والإضافات.
كمستخدم discourse:
cd /var/www/discourse
git stash
git pull
git checkout tests-passed
cd plugins
for plugin in *
do
echo $plugin; cd ${plugin}; git pull; cd ..
done
cd ../
sed -i '/gem "rails_multisite"/i gem "rails"' Gemfile
bundle install --jobs $(($(nproc) - 1))
pnpm i
bundle exec rake db:migrate
bundle exec rake themes:update
bundle exec rake assets:precompile
لا أريد استخدام unicorn. توصي Heroku باستخدام خادم الويب Puma بدلاً من Unicorn. إليك ملف config/puma.rb الخاص بي مكتوب بعد استشارة config/unicorn.conf.rb:
config/puma.rb
# frozen_string_literal: true
require "fileutils"
#require 'puma/acme'
discourse_path = File.expand_path(File.expand_path(File.dirname(__FILE__)) + "/../")
enable_logstash_logger = ENV["ENABLE_LOGSTASH_LOGGER"] == "1"
puma_stderr_path = "#{discourse_path}/log/puma.stderr.log"
puma_stdout_path = "#{discourse_path}/log/puma.stdout.log"
# تحميل ماسح Logstash إذا كان مفعلاً
if enable_logstash_logger
require_relative "../lib/discourse_logstash_logger"
FileUtils.touch(puma_stderr_path) if !File.exist?(puma_stderr_path)
# ملاحظة: قد تحتاج إلى تعديل تهيئة الماسح لـ Puma
log_formatter =
proc do |severity, time, progname, msg|
event = {
"@timestamp" => Time.now.utc,
"message" => msg,
"severity" => severity,
"type" => "puma",
}
"#{event.to_json}\n"
end
else
stdout_redirect puma_stdout_path, puma_stderr_path, true
end
# عدد العمال (العمليات)
workers ENV.fetch("PUMA_WORKERS", 6).to_i
# تعيين الدليل
directory discourse_path
# الارتباط بعنوان ومنفذ محددين
bind ENV.fetch(
"PUMA_BIND",
"tcp://#{ENV["PUMA_BIND_ALL"] ? "" : "127.0.0.1:"}#{ENV.fetch("PUMA_PORT", 3000)}",
)
#bind 'tcp://0.0.0.0:80'
#customization:plugin :acme
#acme_server_name 'example.com'
#acme_tos_agreed true
#bind 'acme://0.0.0.0:443'
# موقع ملف PID
FileUtils.mkdir_p("#{discourse_path}/tmp/pids")
pidfile ENV.fetch("PUMA_PID_PATH", "#{discourse_path}/tmp/pids/puma.pid")
# ملف الحالة - يستخدم بواسطة pumactl
state_path "#{discourse_path}/tmp/pids/puma.state"
# تكوين خاص بالبيئة
if ENV["RAILS_ENV"] == "production"
# مهلة الإنتاج
worker_timeout 30
else
# مهلة التطوير
worker_timeout ENV.fetch("PUMA_TIMEOUT", 60).to_i
end
# تحميل التطبيق مسبقًا
preload_app!
# التعامل مع بدء وإيقاف العمال
before_fork do
Discourse.preload_rails!
Discourse.before_fork
# التحقق من المشرف
supervisor_pid = ENV["PUMA_SUPERVISOR_PID"].to_i
if supervisor_pid > 0
Thread.new do
loop do
unless File.exist?("/proc/#{supervisor_pid}")
puts "Kill self supervisor is gone"
Process.kill "TERM", Process.pid
end
sleep 2
end
end
end
# عمال Sidekiq
sidekiqs = ENV["PUMA_SIDEKIQS"].to_i
if sidekiqs > 0
puts "starting #{sidekiqs} supervised sidekiqs"
require "demon/sidekiq"
Demon::Sidekiq.after_fork { DiscourseEvent.trigger(:sidekiq_fork_started) }
Demon::Sidekiq.start(sidekiqs)
if Discourse.enable_sidekiq_logging?
Signal.trap("USR1") do
# تأخير إعادة فتح سجل Sidekiq
sleep 1
Demon::Sidekiq.kill("USR2")
end
end
end
# خادم مزامنة البريد الإلكتروني
if ENV["DISCOURSE_ENABLE_EMAIL_SYNC_DEMON"] == "true"
puts "starting up EmailSync demon"
Demon::EmailSync.start(1)
end
# خوادم الإضافات
DiscoursePluginRegistry.demon_processes.each do |demon_class|
puts "starting #{demon_class.prefix} demon"
demon_class.start(1)
end
# خيط مراقبة الخادم
Thread.new do
loop do
begin
sleep 60
if sidekiqs > 0
Demon::Sidekiq.ensure_running
Demon::Sidekiq.heartbeat_check
Demon::Sidekiq.rss_memory_check
end
if ENV["DISCOURSE_ENABLE_EMAIL_SYNC_DEMON"] == "true"
Demon::EmailSync.ensure_running
Demon::EmailSync.check_email_sync_heartbeat
end
DiscoursePluginRegistry.demon_processes.each(&:ensure_running)
rescue => e
Rails.logger.warn(
"Error in demon processes heartbeat check: #{e}\n#{e.backtrace.join("\n")}",
)
end
end
end
# إغلاق اتصال Redis
Discourse.redis.close
end
on_worker_boot do
DiscourseEvent.trigger(:web_fork_started)
Discourse.after_fork
end
# التعامل مع مهلة العمال
worker_timeout 30
# خيارات العمال منخفضة المستوى
threads 8, 32
لتشغيل Discourse، قم بتشغيل puma -C config/puma.rb
باستخدام systemd، يمكنك تشغيله عند الإقلاع وإعادة تشغيله عند الفشل. إليك ملف الخدمة:
/etc/systemd/system/discourse.service
[Unit]
Description=Discourse with Puma Server
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=discourse
Group=discourse
WorkingDirectory=/var/www/discourse
# يتطلب تشغيل `rvm 3.4.6 --default` قبل تشغيل هذه الخدمة
ExecStart=/usr/bin/zsh -lc 'source /home/discourse/.zshrc && /home/discourse/.rvm/gems/ruby-3.4.6/bin/puma -C config/puma.rb'
ExecReload=/usr/bin/zsh -lc 'source /home/discourse/.zshrc && /home/discourse/.rvm/gems/ruby-3.4.6/bin/pumactl restart'
# تكوين إعادة التشغيل
Restart=always
RestartSec=5s
# تدابير أمنية أساسية
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=read-only
[Install]
WantedBy=multi-user.target
الآن يستمع خادم puma إلى 127.0.0.1:3000. قم بتعديل ملف تكوين nginx من Docker:
/etc/nginx/sites-enabled/discourse.conf
# أنواع MIME الإضافية التي تريد من nginx التعامل معها توضع هنا
types {
text/csv csv;
#application/wasm wasm;
}
upstream discourse { server 127.0.0.1:3000; }
# inactive تعني أننا نحافظ على الأشياء لمدة 1440 دقيقة بغض النظر عن آخر وصول (أسبوع)
# levels تعني أنها تسلسل هرمي بعمق 2 لأننا يمكن أن يكون لدينا الكثير من الملفات
# max_size يحدد حجم التخزين المؤقت
proxy_cache_path /var/nginx/cache inactive=1440m levels=1:2 keys_zone=one:10m max_size=600m;
# زاد من القيمة الافتراضية لاستيعاب ملفات تعريف الارتباط الكبيرة أثناء تدفقات oAuth2
# مثل في https://meta.discourse.org/t/x/74060 وعناوين CSP و Link (preload) الكبيرة
proxy_buffer_size 32k;
proxy_buffers 4 32k;
# زاد من القيمة الافتراضية للسماح بحجم كبير من ملفات تعريف الارتباط في رؤوس الطلب
# يحاول Discourse نفسه تقليل حجم ملفات تعريف الارتباط، لكننا لا نستطيع التحكم في ملفات تعريف الارتباط الأخرى التي تحددها أدوات أخرى على النطاق نفسه.
large_client_header_buffers 4 32k;
# محاولة الحفاظ على البروتوكول، يجب أن يكون في سياق http
map $http_x_forwarded_proto $thescheme {
default $scheme;
"~https$" https;
}
log_format log_discourse '[$time_local] "$http_host" $remote_addr "$request" "$http_user_agent" "$sent_http_x_discourse_route" $status $bytes_sent "$http_referer" $upstream_response_time $request_time "$upstream_http_x_discourse_username" "$upstream_http_x_discourse_trackview" "$upstream_http_x_queue_time" "$upstream_http_x_redis_calls" "$upstream_http_x_redis_time" "$upstream_http_x_sql_calls" "$upstream_http_x_sql_time"';
# السماح بتجاوز التخزين المؤقت من localhost
#geo $bypass_cache {
# default 0;
# 127.0.0.1 1;
# ::1 1;
#}
limit_req_zone $binary_remote_addr zone=flood:10m rate=12r/s;
limit_req_zone $binary_remote_addr zone=bot:10m rate=200r/m;
limit_req_status 429;
limit_conn_zone $binary_remote_addr zone=connperip:10m;
limit_conn_status 429;
server {
access_log /var/log/nginx/access.log log_discourse;
#listen unix:/var/nginx/nginx.http.sock;
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.cer;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
set_real_ip_from unix:;
set_real_ip_from 127.0.0.1/32;
set_real_ip_from ::1/128;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 5;
gzip_types application/json text/css text/javascript application/x-javascript application/javascript image/svg+xml application/wasm;
gzip_proxied any;
# قم بإلغاء التعليق وتكوين هذا القسم لدعم HTTPS
# ملاحظة: ضع شهادة ssl في دليل nginx الرئيسي (/etc/nginx)
#
# rewrite ^/(.*) https://enter.your.web.hostname.here/$1 permanent;
#
# listen 443 ssl;
# ssl_certificate your-hostname-cert.pem;
# ssl_certificate_key your-hostname-cert.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers HIGH:!aNULL:!MD5;
#
server_tokens off;
sendfile on;
keepalive_timeout 65;
# الحد الأقصى لحجم رفع الملفات (احفظه محدثًا عند تغيير إعداد الموقع المقابل)
client_max_body_size 128m ;
# مسار المجلد العام لـ discourse
set $public /var/www/discourse/public;
# بدون علامات etag الضعيفة، لا نحصل على أي فائدة من etag على المحتوى المضغوط ديناميكيًا
# علاوة على ذلك، تعتمد etags على الملف في nginx وليس sha للبيانات
# استخدم التواريخ، إنها تحل المشكلة بشكل جيد حتى عبر الخوادم
etag off;
# منع التنزيل المباشر للنسخ الاحتياطية
location ^~ /backups/ {
internal;
}
# تجاوز طبقة rails بـ 204 رخيصة لطلبات favicon.ico
location /favicon.ico {
return 204;
access_log off;
log_not_found off;
}
location / {
root $public;
add_header ETag "";
# auth_basic on;
# auth_basic_user_file /etc/nginx/htpasswd;
location ~ ^/uploads/short-url/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
location ~ ^/(secure-media-uploads/|secure-uploads)/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
location ~* (fonts|assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico|otf)$ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location = /srv/status {
access_log off;
log_not_found off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
# بعض التخزين المؤقت البسيط هنا حتى لا نستمر في السؤال
# على المدى الطويل يجب أن نزيد ربما إلى 1y
location ~ ^/javascripts/ {
expires 1d;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location ~ ^/assets/(?<asset_path>.+)$ {
expires 1y;
# تمكين خط الأنابيب للأصول هذا
brotli_static on;
gzip_static on;
add_header Cache-Control public,immutable;
# HOOK في موقع الأصل (يستخدم للتوسع)
# TODO لا أعتقد أن هذا break ضروري، إنه يكسر فقط إعادة الكتابة
break;
}
location ~ ^/plugins/ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
# تخزين الرموز التعبيرية مؤقتًا
location ~ /images/emoji/ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location ~ ^/uploads/ {
# ملاحظة: من المزعج حقًا أننا لا نستطيع فقط تعريف الرؤوس
# في المستوى العلوي والوراثة.
#
# proxy_set_header لا يرث، حسب التصميم، يجب علينا تكراره،
# وإلا لن يتم تعيين الرؤوس بشكل صحيح
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping $public/=/downloads/;
expires 1y;
add_header Cache-Control public,immutable;
## قواعد منع الارتباط المباشر للتحميل الاختياري
#valid_referers none blocked mysite.com *.mysite.com;
#if ($invalid_referer) { return 403; }
# CSS مخصص
location ~ /stylesheet-cache/ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
# هذا يسمح لنا بتجاوز rails
location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico|webp|avif)$ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
# SVG يحتاج إلى رأس إضافي مرفق
location ~* \.(svg)$ {
}
# الصور المصغرة والصور المحسنة
location ~ /_?optimized/ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
proxy_pass http://discourse;
break;
}
location ~ ^/admin/backups/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping $public/=/downloads/;
proxy_pass http://discourse;
break;
}
# هذا الكتلة الكبيرة مطلوبة حتى نتمكن من تمكين
# التسريع بشكل انتقائي للنسخ الاحتياطية والصور الرمزية والرسوم المتحركة وما إلى ذلك.
# انظر ملاحظة التكرار أعلاه
location ~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker) {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
# إذا كان Set-Cookie موجودًا في الاستجابة، فلا يتم تخزين أي شيء مؤقتًا
# هذا سيء مزدوج لأننا لا نمرر آخر تعديل في
proxy_ignore_headers "Set-Cookie";
proxy_hide_header "Set-Cookie";
proxy_hide_header "X-Discourse-Username";
proxy_hide_header "X-Runtime";
# ملاحظة x-accel-redirect لا يمكن استخدامها مع proxy_cache
proxy_cache one;
proxy_cache_key "$scheme,$host,$request_uri";
proxy_cache_valid 200 301 302 7d;
#proxy_cache_bypass $bypass_cache;
proxy_pass http://discourse;
break;
}
# نحتاج إلى إيقاف التخزين المؤقت لرسالة bus
location /message-bus/ {
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_http_version 1.1;
proxy_buffering off;
proxy_pass http://discourse;
break;
}
# هذا يعني أن كل ملف في public يحاول أولاً
try_files $uri @discourse;
}
location /downloads/ {
internal;
alias $public/;
}
location @discourse {
limit_conn connperip 20;
limit_req zone=flood burst=12 nodelay;
limit_req zone=bot burst=100 nodelay;
proxy_set_header Host $http_host;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
}
}
الآن يمكن الوصول إلى Discourse الخاص بك من example.com:443.
الصيانة
للوصول إلى وحدة تحكم rails، ببساطة قم بتشغيل rails c كمستخدم discourse في /var/www/discourse. الأمر discourse الذي يمكن العثور عليه في الوثائق الرسمية هو في الأساس bundle exec script/discourse.
لترقية Discourse، استشر #upgrade-cmd، ثم أعد تشغيل puma باستخدام puma restart أو puma phased-restart. للفرق، استشر puma/docs/restart.md at main · puma/puma · GitHub .