نشر Discourse بدون Docker

بعض التفاصيل حول حلولي:

  1. إعداد Nginx:
    خلف وكيل عكسي (haproxy)، تحتاج إلى نسخ /var/discourse/config/nginx-config-sample.conf إلى /etc/nginx/sites-enabled/discourse.conf أو هدف مشابه، ثم استبدال listen <yourreverseproxyport> (إذا لزم الأمر)، و _ في server_name باسم المضيف الخاص بك (subdmain.example.com). لا شيء آخر يجب تغييره.
  2. الصفحات لا تُعرض (رسالة “Oops”) وتسجيل مسؤولي البريد الإلكتروني لا يعمل:
    كان Magick هو سبب عدم عرض الصفحات بعد صفحات تسجيل المسؤولين عند التشغيل الأول. اتبعت الملف المشار إليه في السجل: /var/www/discourse/lib/letter_avatar.rb:112 في السطر 112، كان هناك أمران magick لم يستجيبا بالفعل. استجاب convert، لذلك استبدلت magick في هذا السطر بـ convert. بعد هذه التصحيحات، تم تسجيل خطأ آخر. محاولة نفس الإجراء باستخدام الأمر المعطى من الملف، لم يعمل أمر magick، وفشل convert. ملاحظة: magick --version كان 7.x و convert --version أعطى 6.x. السبب هو أنني قمت أولاً بتثبيت imagemagick باستخدام apt، ثم magick 7 من المصدر. كانت هناك بعض التعارضات وأخبر magick أمر convert بأنه قديم. لذلك قمت بإعادة تشغيل برنامجي باستخدام magick 7 فقط. هذا حل المشكلة فورًا وتمكنت من رؤية الصفحات الجديدة التي طال انتظارها لأيام، وعمل البريد الإلكتروني أيضًا! Magick سحري حقًا.
  3. لا تزال مشكلة المحتوى المختلط قائمة، لكن الموقع يعمل بشكل جيد على الرغم من ذلك.
    ملاحظة: في puma.rb، يجب أن يكون السطر bind ENV.fetch("PUMA_BIND", "tcp://#{ENV['PUMA_BIND_ALL'] ? '' : '127.0.0.1:'}3000") كما يلي (تصحيح المنشور الأول.)
  4. تحرير “3.”، حول فرض https لـ discourse: لا أعرف لماذا بالضبط، لكن متصفحاتي لم تعد تعرض تحذيرات “المحتوى المختلط” (ربما بسبب تحديث ذاكرة التخزين المؤقت)، لذا كل شيء على ما يرام الآن. أحتاج فقط إلى إنهاء برنامجي.
3 إعجابات

تم التأكيد على أنه يعمل!!!
ImageMagick v7 يحل مشكلة Ooops!
على حد علمي، فإنه يعمل بشكل كامل.
سأقوم باختبار باقي الميزات وسأبلغكم في أقرب وقت ممكن.

إعجاب واحد (1)

ما فعلته للاختبار هو تعيين متغير البيئة PUMA_BIND عند تشغيل puma.

فيما يتعلق بـ ImageMagick، لسبب ما يفشل Discourse في تنفيذ تحويل صورة على واجهة المستخدم الرسومية للويب، عندما أقوم بتحميل صورة كبيرة، فإنه يرفض بلطف تحويلها… ما زلت أقوم بتصحيح المشكلة.

هل هناك أي تقدم في التصحيح؟ من جهتي، أعمل على magick.
على بعض الصور التي تبلغ حوالي 50 كيلو بايت، تظهر نافذة منبثقة في المتصفح:
timeout -k 40.0 20 magick gif:/tmp/RackMultipart20250927-23598-xrrp6e.gif -auto-orient -background white -interlace none -flatten -debug all -quality 90 jpg:/tmp/image20250927-23598-9ujq3d.jpg ولا يتم تحميل أي صورة.
إذا كان الحجم أكبر، لا توجد نافذة منبثقة ولكن عجلة التحميل تدور بشكل لا نهائي دون نتيجة. لم يتم تسجيل أي خطأ في /var/www/discourse/log.

نفس المشكلة بالنسبة لي :joy::sob:

الطريقة الوحيدة التي تمكنت بها من تشغيله كانت باستخدام imagemagick من مستودع brew.

ولكنه يفشل عندما تكون الصورة أكبر من 3 ميجابايت… ربما قمت بإعداد تكوين سياسة مقيد للغاية.

جربها!!!

أنا أختبر تثبيت docker ولكني أعتقد أو أنني غبي جدًا في نشر nginx و unicorn و redis و postgresql والباقي في حاوية واحدة فقط… هذا لا معنى له على الإطلاق. ولا توجد وثائق للبنية التحتية للتوزيعات الكبيرة… لقد عملت في مجال تكنولوجيا المعلومات لأكثر من 20 عامًا ولا أرى سوى مشاكل قادمة في المستقبل القريب باستخدام مثل هذه البنية التحتية.

بدون الحديث عن “docker آكل المساحة” (مثل Dormammu) :rofl::rofl:

هذه المشكلة اختفت مع الحل التالي الموصوف في النهاية:

التصحيح 1: bundle db:create المخرجات، وأيضًا في السجلات عند أول تشغيل:


OID غير معروف 21096: فشل في التعرف على نوع ‘embeddings’. سيتم التعامل معه كسلسلة نصية.
عامل pngquant: pngquant غير موجود؛ يرجى توفير ملف ثنائي مناسب أو تعطيل هذا العامل (وسيطة --no-pngquant أو :pngquant => false عبر الخيارات)
عامل oxipng: oxipng غير موجود؛ يرجى توفير ملف ثنائي مناسب أو تعطيل هذا العامل (وسيطة --no-oxipng أو :oxipng => false عبر الخيارات)
عامل jhead: jhead غير موجود، jpegtran غير موجود؛ يرجى توفير ملف ثنائي مناسب أو تعطيل هذا العامل (وسيطة --no-jhead أو :jhead => false عبر الخيارات)
عامل jpegoptim: jpegoptim غير موجود؛ يرجى توفير ملف ثنائي مناسب أو تعطيل هذا العامل (وسيطة --no-jpegoptim أو :jpegoptim => false عبر الخيارات)

التصحيح 2: بعض أوامر magick مع مخرجات الملفات:

لا يوجد معالج فك تشفير لهذا تنسيق الصورة

تم ذكر هذه المشكلة الأخيرة هنا.

الحل هنا (يقوم بتثبيت magick مع مكونات إضافية للتنسيقات):

t=$(mktemp) && \
wget 'https://dist.1-2.dev/imei.sh' -qO "$t" && \
bash "$t" && \
rm "$t"

بعد ذلك، يمكن أن يصل حجم التحميل الخاص بي إلى 518 كيلوبايت. ما فوق ذلك لا. هذا للصور فقط. جميع المستندات والصوت والفيديو الأخرى تعمل.

حل مؤقت للمشكلة المتبقية:
لقد بحثت في إعدادات المسؤول، discourse.conf، nginx/sites-enables/discourse.conf، في مجلد git. أخيرًا في لوحة المسؤول/المعلمات/الملفات قمت بتعطيل “تمكين تحسين وسائط Composer للصور”، ثم يعمل كل شيء بشكل جيد. يمكنني تحميل أي صورة.

نعم، IMEI هو نفس الحل تقريبًا مثل استخدام brew ولكني متأكد من أنه لن يستغرق حوالي 2 جيجابايت من مساحة القرص :rofl::rofl::sob::sob::sob::face_with_symbols_on_mouth::face_with_symbols_on_mouth::face_with_symbols_on_mouth:
سأتحقق من حلك لأقصى حجم للملفات عند التحميل.
أنا أيضًا أواجه صعوبة في إيجاد حل لإرسال رسائل البريد الإلكتروني “مجانًا” (أنا في مرحلة مبكرة ولا أريد التعاقد مع mailtrap/mailgun/etc…)

لماذا لا تقوم بتثبيت خادم بريد؟ لدي خادم خاص بي وقمت بكتابة نص لتثبيته. أخبرني إذا كنت مهتمًا.

بالتأكيد! أرسل لي التعليمات أو مستودع git! :grinning_face_with_smiling_eyes:

لقد توقفت عن استخدام خوادم البريد المستضافة ذاتيًا منذ سنوات عديدة…

عند تشغيل rake assets:precompile، ظهرت رسالة No such file or directory - brotli، قم بتثبيته باستخدام مدير الحزم.

إعجابَين (2)

لقد وجدت أنه يرمي هذا الخطأ:

bundler: failed to load command: puma (/home/mry/.rbenv/versions/3.4.6/bin/puma)
/home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/puma-7.0.4/lib/puma/cluster.rb:472:in 'Puma::Cluster#run': undefined method 'wait_readable' for nil (NoMethodError)

            if read.wait_readable([0, @next_check - Time.now].max)
                   ^^^^^^^^^^^^^^
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/puma-7.0.4/lib/puma/launcher.rb:202:in 'Puma::Launcher#run'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/puma-7.0.4/lib/puma/cli.rb:73:in 'Puma::CLI#run'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/puma-7.0.4/bin/puma:10:in '<top (required)>'
        from /home/mry/.rbenv/versions/3.4.6/bin/puma:25:in 'Kernel#load'
        from /home/mry/.rbenv/versions/3.4.6/bin/puma:25:in '<top (required)>'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli/exec.rb:59:in 'Kernel.load'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli/exec.rb:59:in 'Bundler::CLI::Exec#kernel_load'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli/exec.rb:23:in 'Bundler::CLI::Exec#run'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli.rb:452:in 'Bundler::CLI#exec'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/vendor/thor/lib/thor/command.rb:28:in 'Bundler::Thor::Command#run'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in 'Bundler::Thor::Invocation#invoke_command'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/vendor/thor/lib/thor.rb:538:in 'Bundler::Thor.dispatch'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli.rb:35:in 'Bundler::CLI.dispatch'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/vendor/thor/lib/thor/base.rb:584:in 'Bundler::Thor::Base::ClassMethods#start'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/cli.rb:29:in 'Bundler::CLI.start'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/exe/bundle:28:in 'block in <top (required)>'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/lib/bundler/friendly_errors.rb:117:in 'Bundler.with_friendly_errors'
        from /home/mry/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0/gems/bundler-2.6.4/exe/bundle:20:in '<top (required)>'
        from /home/mry/.rbenv/versions/3.4.6/bin/bundle:25:in 'Kernel#load'
        from /home/mry/.rbenv/versions/3.4.6/bin/bundle:25:in '<main>'

ثم يعيد Puma تشغيل نفسه. ماذا أفعل لمنع هذا؟

تم التحرير: يبدو أن هذه مشكلة تنتمي إلى Puma منذ Ruby 3.4.0. تم حلها عن طريق تعطيل YJIT.

ثم استخدم 3.3.7. هذه هي النسخة التي أستخدمها.

أنا كسول جدًا لإعادة تنزيل الأحجار الكريمة، فقط سأعطل YJIT مع الاستمرار في استخدام 3.4.6.

Hi all,
Here is my script for a full install in three shots, without docker, on a Debian 12 container (lxc for me).
Use the if blocks to only run the parts you need.

  1. Set your parameter and run it as root with the required arguments. Be careful: the script will exit at the exit point before “### MANUAL” part.
  2. You have to pass these commands manually in the container terminal. I did not succeed to make it work in my lxc unprivileged container. (default user is root)
  3. Then run the rest.
    I tested it many times and it works but there may be some buggy parts after i adapted it to publication.
install_script
#!/bin/bash
########## SCRIPT TO INSTALL DISCOURSE ON DEBIAN 12 WITHOUT DOCKER ##################
#- last tested in december 2025
############################## RUN IT AS ROOT, best in a lxc container!!!!!!!
#- discussion source : https://meta.discourse.org/t/deploy-discourse-without-docker/351194
##############################################################################
# MANUAL PARAMETERS
certbot_contact_email=hello@domain.tld
certbot_renew_port=9785
nginx_discourse_port=8080
DISCOURSE_DEVELOPER_EMAILS='emailaddress'
DISCOURSE_SMTP_ADDRESS=smtp_server_address
DISCOURSE_SMTP_PORT=465
DISCOURSE_SMTP_USER_NAME=xxx
DISCOURSE_SMTP_PASSWORD=xxx
DISCOURSE_SMTP_DOMAIN=xxx
DISCOURSE_NOTIFICATION_EMAIL=no-reply-xxxx
DISCOURSE_MAXMIND_ACCOUNT_ID=50
# END MANUAL PARAMETERS

shopt -s expand_aliases
source /etc/bash.bashrc
container=$1
cont_haproxy=$2
pool=$3
lxc_image=$4
hostname=$5
db_password=$6
maxmind_license_key=$7
DISCOURSE_HOSTNAME=$hostname
DISCOURSE_MAXMIND_LICENSE_KEY=$maxmind_license_key

### INSTALL MAGICK 7 and its plugins
# https://github.com/SoftCreatR/imei/?tab=readme-ov-file
if [ 1 == 1 ]; then
t=$(mktemp) && \
wget 'https://dist.1-2.dev/imei.sh' -qO "$t" && \
bash "$t" && \
rm "$t"
fi

### INSTALL BASICS ###
if [ 1 == 1 ]; then
apt install -y apt-utils postgresql nginx libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static redis
systemctl enable --now postgresql redis-server nginx
useradd -m -s /bin/bash discourse
usermod -aG sudo discourse
passwd -d discourse
# RVM (RUBY)
apt install -y ruby-full # nécessaire
su - discourse -c 'curl -sSL https://get.rvm.io | bash'
su - discourse -c 'source /home/discourse/.bashrc'
su - discourse -c 'source /home/discourse/.rvm/scripts/rvm' # nécessaire après rvm install
su - discourse -c 'rvm install 3.3.7' # will install node 3.3.7 as of today
source /home/discourse/.rvm/scripts/rvm
# fi
# configure POSTGRESQL
apt update && apt upgrade -y
apt autoremove -y

# YOU HAVE TO ACCEPT THE UPGRADE
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
apt install -y postgresql-18-pgvector
fi
alias mydb="sudo -u postgres psql discourse -c "
if [ 1 == 1 ]; then
su - discourse -c 'sudo -u postgres createuser -s discourse'
# fi
su - discourse -c 'sudo -u postgres createdb discourse'
su - discourse -c 'sudo -u postgres psql -c "ALTER USER discourse WITH ENCRYPTED PASSWORD '\''password'\'';"'
alias mydb="sudo -Hiu discourse psql -c "
su - discourse -c 'psql -c "GRANT CONNECT ON DATABASE discourse TO root;"'
su - discourse -c 'psql -c "CREATE EXTENSION pg_trgm;CREATE EXTENSION hstore;"'
su - discourse -c 'psql -c "ALTER DATABASE discourse OWNER TO discourse;"'
su - discourse -c 'psql -c "CREATE EXTENSION unaccent;CREATE EXTENSION plpgsql;"'
su - discourse -c 'psql -c "CREATE EXTENSION vector;"'
echo "OK"

### INSTALL DISCOURSE FROM GITHUB
cd /var/www/
git clone https://github.com/discourse/discourse
git config --global --add safe.directory /var/www/discourse
# exit
### NÉCESSAIRE POUR bundle, ruby, etc. pas pour discourse lui-même
tee -a /home/discourse/.bashrc > /dev/null <<EOT
export RAILS_ENV=production
export UNICORN_SIDEKIQ_MAX_RSS=800
export UNICORN_WORKERS=8
export UNICORN_SIDEKIQS=1
export PUMA_SIDEKIQ_MAX_RSS=800
export PUMA_WORKERS=8
export PUMA_SIDEKIQS=1
export RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000
export RUBY_GC_HEAP_INIT_SLOTS=400000
export RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5

export DISCOURSE_HOSTNAME=$hostname
export DISCOURSE_DEVELOPER_EMAILS=$DISCOURSE_DEVELOPER_EMAILS
export DISCOURSE_SMTP_ADDRESS=$DISCOURSE_SMTP_ADDRESS
export DISCOURSE_SMTP_PORT=$DISCOURSE_SMTP_PORT
export DISCOURSE_SMTP_USER_NAME=$DISCOURSE_SMTP_USER_NAME
export DISCOURSE_SMTP_PASSWORD=$DISCOURSE_SMTP_PASSWORD
export DISCOURSE_SMTP_DOMAIN=$DISCOURSE_SMTP_DOMAIN
export DISCOURSE_NOTIFICATION_EMAIL=$DISCOURSE_NOTIFICATION_EMAIL
export DISCOURSE_MAXMIND_ACCOUNT_ID=$DISCOURSE_MAXMIND_ACCOUNT_ID
export DISCOURSE_MAXMIND_LICENSE_KEY=$maxmind_license_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
EOT
cd /var/www/discourse
git stash
git pull
git checkout tests-passed 
cd plugins
for plugin in *
do
echo "ok"
    echo $plugin; cd ${plugin}; git pull; cd ..
done
# fi
chown -R discourse:discourse /var/www/discourse/     
mkdir -p /var/www/discourse/public
chown -R discourse:www-data /var/www/discourse/public
tee -a /var/www/discourse/config/discourse.conf > /dev/null <<EOT
max_data_explorer_api_req_mode = 'none'
max_user_api_reqs_per_day = '28800'
hostname = '$hostname'
redis_host = 'localhost'
smtp_user_name = $$DISCOURSE_SMTP_USER_NAME
db_password = '$db_password'
smtp_address = '$DISCOURSE_SMTP_ADDRESS'
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_DEVELOPER_EMAILS'
max_user_api_reqs_per_minute = '200'
maxmind_license_key = '$maxmind_license_key'
smtp_port = '$DISCOURSE_SMTP_PORT'
maxmind_account_id = '$DISCOURSE_MAXMIND_ACCOUNT_ID'
smtp_password = '$DISCOURSE_SMTP_PASSWORD'
max_reqs_per_ip_per_minute = '20000'
notification_email = '$DISCOURSE_NOTIFICATION_EMAIL'
db_host = 'localhost'
enable_cors = 'true'
db_port = ''
max_reqs_per_ip_mode = 'none'
smtp_domain = '$DISCOURSE_SMTP_DOMAIN'
#max_admin_api_reqs_per_minute = '600'
smtp_force_tls='true'
EOT

cd /var/www/discourse && sed -i '/gem "rails_multisite"/i gem "rails"' Gemfile
cd /var/www/discourse && sed -i '/gem "image_optim"/i gem "image_optim_pack"' Gemfile
su - discourse -c 'cd /var/www/discourse && bundle install'
# fi

### PNPM (NODEJS)
su - discourse -c 'curl -fsSL https://get.pnpm.io/install.sh' | su - discourse -c 'sh -'
su - discourse -c 'source /home/discourse/.bashrc'
source /home/discourse/.rvm/scripts/rvm
su - discourse -c 'sed -i "s/~> 3.3/3.3.7/" /var/www/discourse/Gemfile'
chown -R discourse:discourse /var/www/discourse/Gemfile Gemfile.lock
apt-get -yqq install brotli # is it needed ????????????????
# fi
su - discourse -c 'cd /var/www/discourse && bin/rails db:create'
# fi
su - discourse -c 'source /home/discourse/.rvm/scripts/rvm'
tee -a .bashrc > /dev/null <<EOT
# pnpm
export PNPM_HOME="/home/discourse/.local/share/pnpm"
case ":\$PATH:" in
  *":\$PNPM_HOME:"*) ;;
  *) export PATH="\$PNPM_HOME:\$PATH" ;;
esac
# pnpm end
EOT
which pnpm
source .bashrc
pnpm env use --global lts # will install node 22 as of today
cd /var/www/discourse && pnpm i
chown -R discourse:discourse .
chown -R discourse:www-data public
exit

#################################
######### MANUAL ################
export PATH="$PATH:/home/discourse/.rvm/bin"
rvm install "ruby-3.3.7" # install in root
cd /var/www/discourse
bundle install
bundle exec rake db:migrate
bundle exec rake themes:update
bundle exec rake assets:precompile
######### MANUAL #################
##################################

fi
### puma.rb
#cd /var/www/discourse
cp /var/www/discourse/config/puma.rb /var/www/discourse/config/puma.rb_original

tee /var/www/discourse/config/puma.rb > /dev/null <<EOT
# frozen_string_literal: true

require "fileutils"

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"

# Load logstash logger if enabled
if enable_logstash_logger
  require_relative "../lib/discourse_logstash_logger"
  FileUtils.touch(puma_stderr_path) if !File.exist?(puma_stderr_path)
  # Note: You may need to adapt the logger initialization for 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

# Number of workers (processes)
workers ENV.fetch("PUMA_WORKERS", 8).to_i

# Set the directory
directory discourse_path

# Bind to the specified address and port
bind ENV.fetch("PUMA_BIND", "tcp://#{ENV['PUMA_BIND_ALL'] ? '' : '127.0.0.1:'}3000")

# PID file location
FileUtils.mkdir_p("#{discourse_path}/tmp/pids")
pidfile ENV.fetch("PUMA_PID_PATH", "#{discourse_path}/tmp/pids/puma.pid")

# State file - used by pumactl
state_path "#{discourse_path}/tmp/pids/puma.state"

# Environment-specific configuration
if ENV["RAILS_ENV"] == "production"
  # Production timeout
  worker_timeout 30
else
  # Development timeout
  worker_timeout ENV.fetch("PUMA_TIMEOUT", 60).to_i
end

# Preload application
preload_app!

# Handle worker boot and shutdown
before_fork do
  Discourse.preload_rails!
  Discourse.before_fork

  # Supervisor check
  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 workers
  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
        # Delay Sidekiq log reopening
        sleep 1
        Demon::Sidekiq.kill("USR2")
      end
    end
  end

  # Email sync demon
  if ENV["DISCOURSE_ENABLE_EMAIL_SYNC_DEMON"] == "true"
    puts "starting up EmailSync demon"
    Demon::EmailSync.start(1)
  end

  # Plugin demons
  DiscoursePluginRegistry.demon_processes.each do |demon_class|
    puts "starting #{demon_class.prefix} demon"
    demon_class.start(1)
  end

  # Demon monitoring thread
  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

  # Close Redis connection
  Discourse.redis.close
end

on_worker_boot do
  DiscourseEvent.trigger(:web_fork_started)
  Discourse.after_fork
end

# Worker timeout handling
worker_timeout 30

# Low-level worker options
threads 8, 32
EOT

### CERTBOT
apt install -y certbot
certbot certonly --non-interactive --agree-tos --renew-with-new-domains  --standalone --email $certbot_contact_email --rsa-key-size 4096 --http-01-port $certbot_renew_port -d $hostname
# fi

### NGINX
cp /var/www/discourse/config/nginx.sample.conf /etc/nginx/sites-enabled/discourse.conf
sed -i "s/80/$nginx_discourse_port/" /etc/nginx/sites-enabled/discourse.conf
sed -i "s/server_name _/server_name $hostname/" /etc/nginx/sites-enabled/discourse.conf
mkdir -p /var/nginx/cache
systemctl enable nginx
systemctl restart nginx
systemctl status nginx

### SYSTEMD SERVICE AUTOSTART
sudo tee /etc/systemd/system/discourse.service > /dev/null <<EOT
[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
# requires running `rvm 3.3.7 --default` before this service is run
ExecStart=/usr/bin/bash -lc '/home/discourse/.rvm/gems/ruby-3.3.7/bin/puma -C config/puma.rb'
ExecReload=/usr/bin/bash -lc '/home/discourse/.rvm/gems/ruby-3.3.7/bin/pumactl restart'
# il faut cette ligne dessous
Environment=RAILS_ENV=production
# Restart configuration
Restart=always
RestartSec=5s

# Basic security measures
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=read-only

[Install]
WantedBy=multi-user.target
EOT

systemctl enable discourse
systemctl start discourse

# OR MANUAL START
# puma -C config/puma.rb

### SETTINGS
echo "LAST MANUAL SETTINGS:"
echo ""
echo "GO in Admin>files and add wanted file extensions - vidéos, audio et documents
echo "TO FORCE HTTPS: https://domain.com/admin/config/security"