Setup Multisite Configuration with Let's Encrypt and no Reverse Proxy

These instructions should be considered beta and for those familiar with a standard setup

But right now (2023.02.11) these instructions do not work!!

I developed this howto a couple weeks ago but need someone to test and see if this works for someone else. Please reply if you try and let me know whether it works and if anything is unclear.

And on with the show. . .

This howto documents broadly how to set up a multisite setup with 2 additional hosts (3 total).

It assumes that you have a working Discourse official Standard Installation or 2-container installation (Move from standalone container to separate web and data containers).

Domain name for primary site

subdomain for the 2nd site

Suddomain for the 3rd site

Database password (same as DISCOURSE_DB_PASSWORD) or discourse in app.yml

For the sake of simplicity, this is for a main site called =domain=, with two additional sites =two=.=domain= and =three=.=domain=. You can use whatever names you want, but for the sake of this template, not having a different short name (for the database name and title for the sub-forum) and full hostname is a bit easier.

add in hooks after the plugins in app.yml or web_only.yml

  before_bundle_exec:
    - file:
        path: $home/config/multisite.yml
        contents: |
         =two=:
           adapter: postgresql
           database: =two=
           pool: 25
           timeout: 5000
           host: data
           password: NThmZTNjZjZhOTczNmVj
           host_names:
             - =two=.=domain=
         =three=:
           adapter: postgresql
           database: =three=
           pool: 25
           timeout: 5000
           host: data
           password: NThmZTNjZjZhOTczNmVj
           host_names:
             - =three=.=domain=

  after_db_migrate:
    - exec: cd /var/www/discourse && sudo -E -u discourse bundle exec rake multisite:migrate

  after_ssl:
   # tell letsencrypt what additional certs to get
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d =two=.=domain= -d =three=.=domain=  --keylength"
   # do not redirect all hosts back to the main domain name
    - replace:
        filename: "/etc/nginx/conf.d/discourse.conf"
        from: /if \(\$http_host[^\}]*\}/m
        to: ""
    - replace:
        filename: "/etc/nginx/conf.d/discourse.conf"
        from: /return 301.*$/
        to: "return 301 https://$host$request_uri;"

Add to the after_postgres section in app.yml or data.yml

  - exec: sudo -u postgres createdb =two= || exit 0
    - exec:
        stdin: |
          grant all privileges on database =two= to discourse;
        cmd: sudo -u postgres psql =two=
        raise_on_fail: false

    - exec: /bin/bash -c 'sudo -u postgres psql =two= <<< "alter schema public owner to discourse;"'
    - exec: /bin/bash -c 'sudo -u postgres psql =two= <<< "create extension if not exists hstore;"'
    - exec: /bin/bash -c 'sudo -u postgres psql =two= <<< "create extension if not exists pg_trgm;"'
    - exec: sudo -u postgres createdb =three= || exit 0
    - exec:
        stdin: |
          grant all privileges on database =three= to discourse;
        cmd: sudo -u postgres psql =three=
        raise_on_fail: false
    - exec: /bin/bash -c 'sudo -u postgres psql =three= <<< "alter schema public owner to discourse;"'
    - exec: /bin/bash -c 'sudo -u postgres psql =three= <<< "create extension if not exists hstore;"'
    - exec: /bin/bash -c 'sudo -u postgres psql =three= <<< "create extension if not exists pg_trgm;"'

After that,

./launcher rebuild app

or

./launcher rebuild data
./launcher rebuild web_only
9 Likes

I just tried it out, in fact I tried it twice because I couldn’t believe it just worked without any problems the first time already :smile: All I did was copying, adjusting the domains and password and then pasting into the respective files of a fresh installation with 2 containers. :ok_hand:

Regards feedback whether anything is unclear, I only had to mull a bit over this paragraph:

It seems to suggest a 2-container setup is necessary to follow along, but then it isn’t. And I didn’t understand why it links to post 48 of the topic, rather than the initial post.

1 Like

Thanks! I’ll take a look. Those both seem like the kind of careless things I was hoping you’d let me know about!

EDIT: Thanks! I’d carelessly copied my current location in the 2-container topic, so I fixed that, and changed the language to say that it’ll work with any working installation.

Thanks!

2 Likes

Hi
I started with a standard Discourse install (at DigitalOcean), then setup nginx (using these instructions) because I wanted a couple of Drupal sites on the same droplet
If I want to have another instance of Discourse should I follow the above?

Or would this guide be better?

Thanks!
/Sifaan

These instructions are for not using a reverse proxy. I’d recommend that you follow Multisite configuration with Docker. The instructions that you linked might work, but I’d recommend that you first follow what’s here.

1 Like

Thanks; I notice that with that both sites would use the same SMTP config :frowning:
is there a way to bypass that?
or would the other guide be better (looks like it might require some work to put the existing site on the docker network)

alternately, is it possible to install another codebase, say /var/discourse2 ?
(it will cost me ~500MB but worth it if it saves me the brain damage)

Yes.

Don’t use multisite.

Yes, but you just need to create a 2-container installation and then have a web_only2.yml. (I think that you can have 2 app.yml-style files, but then you’re needlessly running two postgres instances). I think, though, that you do need two redis instances.

3 Likes

Thanks; because I am not too familiar with splitting the data and web container I just created another standalone container following these guidelines (and certificates created by certbot seem to be working). However currently there seems to be an issue with mailgun config - it sends activation emails to gmail but anything mail hosted at my registrar (dreamhost) is failing :frowning:

How much of a extra load would the extra Postgres instance causing?
I looked at your post about splitting and will try it if the savings were significant.

Probably not that much. Just a bit of RAM. I have little idea how much.

1 Like

Recently I’ve been giving this a try, but I’m having trouble with a couple of things in the guide:

  1. I can’t seem to find the Database password (or what it is even used for in the file)
  2. My app.yml file did not originally contain an after_postgres section, so I added one under hooks to match the others (after_ssl, after_db_migrate, etc.). If this is placed in the wrong section, please let me know, I’m completely new to working with this type of stuff.
  3. When I check the syntax of the YAML file on http://www.yamllint.com/ I get (<unknown>): did not find expected key while parsing a block mapping on the line where I put the after_postgres section under the hooks section.

If you could clarify the steps for editing the app.yml file, that would be greatly appreciated.

2 Likes

Maybe you don’t need a password if you’re using a single container setup (an earlier post suggests that).

Adding the section as you suggest should work.

I can’t quite the what might be wrong. I’ll try to take a closer look on a couple of days.

1 Like

I’m thinking to set this up, as my friend and I want to test a few different forums before we decide if we want to invest more in them, possibly having separate hosting and such.

I was thinking to have them on different domains, I understand it may bring a little confusion as people will receive the emails from just the main SMTP address, however, do you know if separate domains would create any other headaches?

Discourse has a single domain for all of their business and standard customers. You can make the notification email address be whatever you want like shortname@whatevermail.com.

2 Likes

I’m really glad to hear this, thank you!

1 Like

Hi, first of all thank you for the tutorial.

Unfortunately, I have an issue running additional discourse in a single server/IP.
First, I followed the documentation to spin up a standalone site and it was successful.
(e.g. test.john.com - a subdomain redirect to the single IP)
Now when I tried to add more discourse (e.g. test.joe.com and test.doe.com - other subdomains from other sites).
I tried to follow your steps but it did not succeed and now im lost.

Few questions:

  1. How will these two more sites be installed? Like copying the /standalone.yml to containers directory and renaming it? And jsut do the regular install? (e.g. ./launcher rebuild joe)
  2. Your instruction states that the changes should be in the app.yml, appending all the code above - which I assume be added in the first successful installed file(test.john.com)?

Other than those in the container directory, I created a config/multisite.yml and this is what my code looks like:

secondsite:
  adapter: postgresql
  database: b_discourse
  username: postgres
  password: postgres
  host: dbhost
  pool: 5
  timeout: 5000
  host_names:
    - test.joe.com
...
...
# and the third site config

Im not sure though if there are other things I needed to configure.

Appreciate any response. Thank you!

No. You add the stuff to the app.yml as described. That will create the mutlisite.yml inside the container. There will be a single instance and it’ll work for all of the domains, given that the DNS for all of them points there. This is not for having multiple Discourse containers, one for each domain name.

Last I checked, those instructions worked as written. Just add the lines to your app.yml and it should work. You don’t need to touch any other files.

1 Like

Single Website-NormaI Setup works perfect. No problem.
But I tried many combinations for multisite. Single app.yml configuration or seperated by web_only.yml, data.yml vs…I tried other tips on Multisite configuration with Docker or Move from standalone container to separate web and data containers.

As for the migration part all combinations always failed… >>>> bundle exec rake multisite:migrate

********************** last part of the process**************************
2023-02-11 17:50:43.853 UTC [61] LOG:  shutting down
162:M 11 Feb 2023 17:50:43.866 # User requested shutdown...
162:M 11 Feb 2023 17:50:43.866 * Saving the final RDB snapshot before exiting.
162:M 11 Feb 2023 17:50:43.881 * DB saved on disk
162:M 11 Feb 2023 17:50:43.882 # Redis is now ready to exit, bye bye...
2023-02-11 17:50:44.007 UTC [57] LOG:  database system is shut down


FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && sudo -E -u discourse bundle exec rake multisite:migrate failed with return #<Process::Status: pid 582 exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.1.0/gems/pups-1.1.1/lib/pups/exec_command.rb:117:in `spawn'
exec failed with the params "cd /var/www/discourse && sudo -E -u discourse bundle exec rake multisite:migrate"
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

I checked what was created and what was not created until the failure.
Subdomains databases are created but migration failed. Subdomains nginx conf or multisite.yml couldn’t be created when I checked overlay2 folders or anywhere.

./laucher bootstrap,destroy,start,stop,rebuild or fresh setup many times …Tried all commands but nothing happened… :slight_smile:

Is this tutorial still valid for v3.1.0.beta 2 or what could I be missing?
Any idea, please ?

1 Like

No. Something about let’s encrypt changed at some point. I’ll have you take a closer look at what all needs you get changed inside the container to handle multiple domains.

1 Like