Success - New Multisite Install on Dedicated server using ServerPilot, Nginx and Apache

Here’s what I did to install a successful installation of Discourse for multiple instances on a dedicated server that uses Nginx and Apache.

I decided to create a new topic since my installation seems to be a little unique from what I have seen others having to go through. I am very new to Nginx webservers and thought this might help others who may be struggling to connect the dots. I’m also at a beginner level when it comes to using the terminal to access my server, I still have to look up commands for most of the stuff I want to do, but I am finding it so much faster and powerful vs FTP. I still use FTP for a visual representation to locate files and text editing (I don’t like vi or nano editing in the terminal) I use Coda (on a Mac) as my text editor so I have direct access to the server. Which means I can live edit my files just as one would do in the terminal.

I’m using ServerPilot as the control panel to manage my websites on an Ubuntu 14.04 installation. ServerPilot uses Nginx as a reverse proxy in front of the Apache webserver. At first I was a bit confused with this, and basically what they have done is use Nginx as the hub where website requests come into the Nginx server and get routed to Apache to be executed and then back through Nginx to be displayed. This proved to cause some trouble with my installation as I had to figure out where all the config files and such were located.

I started with this tutorial for installing the first instance of Discourse as a dev version …

https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md

Pay special attention to the TCP/IP ports as that was the first place I stumbled, and I see a lot of other posts in the forums from other people who have done the same. If you leave them at the default “80:80” you may get an error stating that port is already in use.

Change the first half of the ports to a port that is not being used, I used 85

This got me through the installation with no errors, but when I went to the url I setup for the forum nothing was showing up. I could connect to the forum using the IP with the port number. Since the forum doesn’t need Apache, I found the conf file that was directing the site to the Apache server with a local IP. I changed this IP to the forum IP with port number.

The path to that section (if you’re also using ServerPilot)

/etc/nginx-sp/vhosts.d/main.conf
(ServerPilot recommends that you change the name of the main.conf file so it is not overwritten on updates)

Now I had a working instance of Discourse, and here’s what I did to set up the multiple instances.

I started with this tutorial, but I was having trouble understanding how the structure was supposed to be setup

If you scroll down to this section …

https://meta.discourse.org/t/multisite-configuration-with-docker/14084/18

This is where I based my installation from, however I did not use the hook settings in the original post. Instead, I duplicated the app.yml file for each site I was creating (only two sites) and renamed them for site specific use. I’ll use the example - site1 and site2.

So in the /var/discourse/containers the files there are as such …

app.yml
site1.yml
site2.yml

(these are your separate containers, which was a term that I didn’t understand at first)

For each file you need to make sure to change the following areas to be specific to your instance …

## which TCP/IP ports should this container expose?
expose:
  - "127.0.0.1:4000:80"   # fwd host port 80   to container port 80 (http)
  - "2222:22" # fwd host port 2222 to container port 22 (ssh)

Notice I changed the first port on both, otherwise you will get port conflict errors.

  ## TODO: List of comma delimited emails that will be made admin and developer
  ## on initial signup example 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'changeme@site1.com'

change the developer email to the email you will use for the admin account

In the mailserver section that follows, be sure to change any settings that are specific to this site such as the username and password. I ended up using Mandrill so the smtp and port numbers were the same for all instances, but I created two accounts. (one for each website)

This next section to edit is key to you getting a separate database for each site. Be sure to change the ‘yoursite’ to something unique to each site.

## These containers are stateless, all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/yoursite
      guest: /shared
  - volume:
      host: /var/discourse/shared/yoursite/log/var-log
      guest: /var/log

The next thing to do is make sure you have the Nginx proxy URL (the one that is pointing to Apache) changed to match the port you configured in the TCP/IP section. So using the port I used as an example your file should look like this and as I mentioned above, ServerPilot recommends changing the name of the file if you MUST edit (that’s why they give the do not edit warning)

###############################################################################
# DO NOT EDIT THIS FILE.
#
# Your changes to this file will be overwritten by ServerPilot.
#
# For information on how to customize nginx settings, see
# https://serverpilot.io/community/articles/customize-nginx-settings.html
###############################################################################

# Send all requests to apache.
location / {
    proxy_pass      http://localhost:4000;

Be sure to restart Nginx if you make changes to the .conf file (I forgot to do this) and with ServerPilot the restart command is a little different than I had seen elsewhere, this is what did it for me …

service nginx-sp restart

Then start bootstrapping your containers. (do this for each site your configured) Enter these commands in the terminal

./launcher bootstrap site1
(after that is done)
./launcher start site1

You should now be able to load the URL you have for the forum and see your Discourse forum.

I ended up with one of the sites not recognizing the Admin account when I registered with the developer email, and I found I had a stray character at the end of the URL that caused the email to be different. I then went into the /var/discourse/shared/ directory and deleted the folder matching that site. Then I used ./launcher destroy site2 command followed by ./launcher bootstrap site2 and then ./launcher start site2 I’m not sure a rebuild would work since you want the database to be recreated.

I know I probably over-simplified this is some areas, but from what I have seen in other topics/threads, some people need instructions that are overly simplified :wink:

Please let me know if I left any holes, or there is any need for clarification as long as you understand I can only speak for what worked for me since I barely understand this myself HA!!!

One more thing … does any one see any issue with duplicating the app.yml file to be used in this way? It seems this would work perfectly for updating as well.

Best regards … Pops

Actually, ports <1024 are considered “privileged”, using them without assignment is… not technically wrong, but ugly. Also, you should bind Discourse to the local interface:

expose:
  - "127.0.0.1:4000:80"

Change your nginx config accordingly to proxy_pass http://localhost:4000;

Overall, nice write-up, but do turn your YAML and other config file snippets into proper fenced code blocks (``` on a line by itself before and after the code block). Especially for YAML, indentation is really important and it gets lost in simple quote blocks. :wink:

That makes complete sense, I made the changes suggested to my server and they work perfectly. I also changed them in the above instructions as well as used the code markdown instead of the quote markdown (thanks for pointing that out)

… Pops

@elberet hmmm, something isn’t quite right when changing the ports on the production sites

Changing the ports as you suggested on the app.yml file worked great, but after changing the two additional container files with the appropriate changes I get a 502 bad gateway error.

I made the changes to the exposed port, as well as the proxy_pass, I then rebuilt the the instance using ./launcher rebuild as well as restarted the Nginx server.

Any idea what’s wrong?

… Pops

EDIT: very weird … I was issuing the restart command for Nginx, but when I stopped it, and then started instead of “restart” everything is working fine

You can also stop exporting ports entirely by using web.socketed.template.yml:

I saw that post, but had a difficult time understanding how to implement it in the way my server is set up since Nginx is already installed and running in front of Apache.

It had to do with the last step, the path you referenced for sites-enabled an sites-available doesn’t exist and if I just needed to create them, I didn’t know how the files as a whole were to be set. (just a lack of knowledge on my part)

@PopsRocker Hi Pops!

Like you I’m trying to set up Discourse on DigitalOcean with ServerPilot, already running another website in a ServerPilot app (app named ‘test’). I only need a single Discourse site, so my setup will be simpler than yours.

Along with app#1 (test) hosting a website, I’ve got a 2nd ServerPilot app (named ‘discourse’) set up for purposes of pointing to the Discourse install. This gives me the /etc/nginx-sp/vhosts.d/discourse.conf and /etc/nginx-sp/vhosts.d/discourse.d/main.conf files.

So my question: what modifications did you make to your .conf files to get it to forward requests to discourse? I’ve got Discourse running and can access it from discourse.example.com:8888. What is it I need to do in the nginx conf files so that I can see Discourse at discourse.example.com, without appending the port number?

Thx

Sorry, replied too soon and then found my answer above:

in app.yml:

expose:
  - "127.0.0.1:8888:80" # fwd host port 80 to container port 8888 (http)
  - "2222:22" # fwd host port 22 to container port 2222 (ssh)

in /etc/nginx-sp/vhosts.d/discourse.d/main.conf (renamed to main.custom.conf as suggested):

location / {
    proxy_pass $backend_protocol://$backend_host:8888;
}

I’m still a little confused with this Serverpilot / Discourse setup. When you created your “discourse” app in Serverpilot, what did you put in the apps/discourse/public/ directory? I have my current discourse installation in the /var/discourse directory but am not sure how Serverpilot is suppose to recognize that?

You don’t actually have to put anything in the apps/discourse/public/ directory. Instead, you want requests to that Serverpilot app forwarded to your Discourse install living in /var/.

This is accomplished via the /var/discourse/containers/app.yml and /etc/nginx-sp/vhosts.d/discourse.d/main.custom.conf modifications referenced in my previous post.

Thanks for your help! I was able to get it up and running.

I’m using ServerPilot too. Glad I found this article. I will let you know, how it’s worked up for me.
Thank you.

Thanks for the info on this. I know it has been a while, does anyone happen to know what kind of increase in resources on the system end up being consumed when you have a second one?

Maybe it’s because this post is from 2015 … but now I can not find the nginx-sp directory in my installation (I did it with the docker automatically).

I have all the second.yml completely changed, but I don’t know where it’s the nginx file to do the proxy thing.

(تم سحب المنشور من قبل المؤلف، سيتم حذفه تلقائيًا خلال 24 ساعة ما لم يتم وضع علامة عليه)

ألا يجب أن يحتوي هذا المسار على /standalone/ في الموقع الأول؟

أتساءل عما إذا كان هناك خلط بين نظام المواقع المتعددة ونظام ووردبريس مع ديسكورد في إعداد الحاويتين المزدوجتين؟ :face_with_raised_eyebrow:

نحن ندير عدة تطبيقات Discourse بسهولة (على نفس الخادم) باستخدام حاوية واحدة للبيانات وحاوية واحدة للتطبيق لكل “مثيل نطاق” نديره.

بالإضافة إلى ذلك، ندير حاويتين للتطبيق لكل “مثيل نطاق”. وهذا يعني عدم وجود توقف عند إعادة بناء الحاوية.

لماذا؟

لأنه عند تشغيل “الحاوية أ”، نقوم بإعادة بناء “الحاوية ب”؛ وبعد إعادة بناء “الحاوية ب”، ننتظر حوالي دقيقة واحدة ثم نعيد تكوين وكيل العكس (reverse proxy) ليعمل على منفذ Unix الخاص بـ “الحاوية ب” ونقوم بتشغيل الأمر service apache2 restart (في حالة apache2).

هذا يعني عدم وجود توقف فعلي (ربما بضع أجزاء من الألف من الثانية) عند التبديل بين الحاويات.

لقد تابعت هذا الموضوع بإعجاب أمام مدى صعوبة (أو تعقيد) ما يفعله الكثيرون في شيء هو في الأساس بسيط جدًا.

يعمل Discourse في بيئة الإنتاج داخل حاوية Docker؛ وفريق Discourse الممتاز قدم القوالب الأساسية للكشف عن Discourse إما عبر منفذ TCP/IP أو منفذ نطاق Unix (لكل مثيل تطبيق). بالإضافة إلى ذلك، قدم فريق meta الممتاز القالب الأساسي لتشغيل حاوية البيانات (PostgreSQL) بشكل منفصل عن حاوية التطبيق (Rails, JS).

ينطبق نفس المفهوم تمامًا على أي تطبيق node.js يعمل داخل حاوية. هذه التكوينات (وكلاء العكس إلى الحاويات) هي مهام Docker أساسية تنطبق على أي تطبيقات ويب تعمل داخل حاويات، وDiscourse مجرد واحدة منها، وهي من الأفضل كما نعلم جميعًا :slight_smile:

في بعض الأحيان أعتقد أن الفريق الممتاز في meta Discourse يجعل تشغيل حاويتهم سهلاً جدًا بفضل سكريبتات التغليف المصممة جيدًا، مما يؤدي إلى أن يفشل المستخدمون في فهم أن الأساسيات الكامنة لتشغيل تطبيق ويب قائم على Docker خلف وكيل عكسي هي في الواقع بسيطة جدًا.

يمكننا تشغيل “أي عدد من تطبيقات Discourse” نرغب فيه كاستضافات افتراضية، تمامًا كما يفعل مسؤول موقع ويب عند تشغيل 20 تطبيق ويب “قديم الطراز LAMP” على نفس الخادم. الفرق الوحيد هو أنه بدلاً من الاستضافة الافتراضية لمجلد من ملفات PHP، لدينا استضافة افتراضية لـ (في حالتنا) منفذ نطاق Unix. يجعل Docker هذا فعالاً للغاية من خلال مشاركة المكتبات الأساسية والطبقات الفائقة بين الحاويات!

بالإضافة إلى ذلك، نظرًا لأن الشبكات بين الحاويات مدمجة في Docker، فمن السهل جدًا إعداد Discourse (كحاوية تطبيق) للعمل مع حاوية PostgreSQL (البيانات)؛ والتي يوفرها فريق meta الممتاز كقالب مثال لجميع المستخدمين لأولئك الذين يرغبون في تشغيل Discourse بطرق “أكثر إثارة للاهتمام” (تكوينات).

نصيحتي، مهما كانت قيمتها، هي أن تفهم أن Discourse هو ببساطة تطبيق ويب يعمل داخل حاوية خلف وكيل عكسي، مثل أي تطبيق ويب. نحن أيضًا ندير سجل Docker الخاص بنا (أكثر من واحد في الواقع) بنفس الطريقة؛ تطبيق Docker خلف نفس وكيل العكس إلى المنفذ 5000 (منفذ سجل Docker الافتراضي).

Discourse، في حكمة جعل الحياة سهلة للمستخدمين (وجعل Discourse في متناول غير خبراء إدارة الأنظمة)، يوفر القدرة على الكشف عن تطبيقات الويب مباشرة (بدون وكيل عكسي) في تكوينها الافتراضي (OOTB). بالإضافة إلى ذلك، فإن إعداد وكيل عكسي خارج حاوية Docker هو نفسه لجميع تطبيقات الويب هذه المعبأة في Docker. يقدم فريق meta هذه القوالب أيضًا (دعم رائع إذا فكرت في الأمر!).

في الختام، من السهل جدًا تشغيل تطبيق واحد أو عشرين أو أكثر من التطبيقات المعبأة في Docker خلف وكيل عكسي. هي مجرد حاويات (وكلها يمكن أن تكون منتدى Discourse مختلفًا)، واختيار كيفية كشف الحاويات يعود للمستخدم (مدير النظام)، وكذلك خيارات كيفية إعداد وحدات التخزين الدائمة بما في ذلك قواعد البيانات.

أعتقد أن هذا بسيط جدًا، وأن فريق meta جعله بسيطًا للجميع؛ ولكن أحد الآثار الجانبية لجعله بسيطًا جدًا هو أن الناس نسوا (أو لم يتعلموا) الأساسيات حول مدى سهولة وأناقة التكوين المعبأ في Docker (خلف وكيل عكسي) في الواقع (بغض النظر عن Discourse).

آمل أن يساعد هذا بطريقة صغيرة ما.

كل التوفيق!

الأمر بسيط للغاية…

كل تطبيق له حجم مشترك خاص به، وهذا الحجم هو المكان الذي يعمل فيه سوكيت نطاق يونكس (حيث تُخزن أيضًا جميع البيانات الدائمة الأخرى مثل التحميلات وما إلى ذلك).

لا تحتاج إلى العمل مباشرة مع docker-compose، أو توجيهات pup الخاصة، أو تغيير أي شيء على الإطلاق (فقط قم بإعداد ملفات yml الأساسية بشكل صحيح للحاويات، ثم شغّل launcher).

إذا كان أحد مواقع/discourse أو تطبيقاتك يُسمى “farmer_forums”، فإن سوكيت نطاق يونكس الخاص بك يقع (افتراضيًا)، على سبيل المثال:

/var/discourse/shared/farmer_forums/nginx.http.socket

إذا كان موقع/discourse أو تطبيقك التالي يُسمى “race_car_forums”، فإن سوكيت نطاق يونكس الخاص بك يقع (على سبيل المثال) هنا:

/var/discourse/shared/race_car_forums/nginx.http.socket

يمكنك فعل ذلك لمئات المنتديات إذا رغبت؛ وكل منها مجرد إدخال في وكيل عكسي يشير إلى ذلك السوكيت. فقط قم بتسمية ملفات yml الخاصة بالحاويات بشكل مناسب.

كل واحد من هذه المنتديات سيكون له حاوية بيانات خاصة به أيضًا. يمكنك استخدام أي تسمية تريدها لتلك الحاويات، على سبيل المثال:

  • farmer_forums_data
  • race_car_forums_data

بالطبع، سيكون لكل واحدة منها حجمها المشترك الخاص بقاعدة بياناتها (قواعد بياناتها).

كل ما تحتاجه هو إنشاء حل “حاويتين” يعمل بشكل صحيح وتكراره خلف وكيل عكسي. إنشاء موقع واحد، أو 100 موقع، كل شيء متشابه إذا اتبعت هذه الطريقة البسيطة.

ملاحظة: لقد سمعت (قرأت) أن بعض الناس يحاولون استخدام حاوية قاعدة بيانات واحدة للعديد من المنتديات المختلفة. أنا شخصيًا لا أنصح بذلك أبدًا. هذا التكوين يخلق نقطة فشل واحدة لجميع المنتديات، وهذا ليس كيف أحب أن أعمل: “اجعلها بسيطة وسخيفة” (KISS). لكنني أحب مبدأ KISS في إدارة الأنظمة، لأنني ارتكبت أخطاءً بأصابعي السميكة أكثر من مرة على مر العقود :)، لذا لا أحب أن أفسد أكثر مما يجب عندما أرتكب خطأً (وهو ما نفعله جميعًا بين الحين والآخر).

لذلك، إذا كنت تواجه صعوبة في هذا؛ فقط قم بتشغيل موقع واحد يعمل بحاويتين، حاوية التطبيق وحاوية البيانات، خلف وكيل عكسي.

ثم قم بتكرار ذلك عدد المرات التي تريدها، مع حاوية تطبيق وحاوية بيانات لكل موقع. يجب أن تكون أسماء جميع الحاويات فريدة، ويجب أن تتبع تسمية سهلة التذكر مثل الأمثلة أعلاه (المزارع وسيارات السباق).

لستُ أقصد أن أبدو مكررًا أو وعظيًا، لكن إعداد العديد من مواقع discourse خلف وكيل عكسي بهذه الطريقة أمر تافه تقريبًا.

أتمنى أن تساعد هذه الشرح الإضافي، ولو بشكل بسيط.

باختصار، بالنسبة لي “تعدد المواقع” يعني ببساطة تنفيذ حل “حاويتين” خلف وكيل عكسي، عدة مرات، عدد المرات التي تريدها! :slight_smile: موقع واحد أو عشرة، التكوين متشابه في الأساس، فقط أسماء الحاويات مختلفة، وهناك تسمية “سهلة الفهم” للحاويات (مثل المثالين أعلاه). سيقوم Docker بمشاركة المكتبات والطبقات فوقية بشكل مناسب بين الصور، لذا “لا حاجة للقيام بأي شيء هنا” لأن “هذا ما يفعله Docker” (يقوم بإعداد جميع المكتبات المشتركة، وبناء شبكة Docker، إلخ) تلقائيًا، مما يجعل هذا الإجراء “فعالًا” نظرًا لكيفية مشاركة Docker للمكتبات بين الصور وما إلى ذلك.

ربما يجب أن نطلق على هذا الإعداد اسمًا غير “الموقع المتعدد” (الذي يفهمه ذهني على أنه يشارك حاوية البيانات، كما هو موضح في موضوع الدليل الذي أغلقه سام في وقت سابق من العام الماضي).
موقع متوازي؟ :وجه_مجنون: لا أعرف…
إذا لم أكن مخطئًا، وبما أن لديك ملف .yml لكل زوج من حاويات البيانات/الويب، فيمكنك تحديد مجموعات إضافات مختلفة و SMTP لكل نطاق؟