Run Multi-Sites on the Same Server as Discourse

Run Multi-Sites on the Same Server as Discourse

0. Before you proceed

This article assumes that you installed Discourse via the Official Simple 30 Minute Basic Install on GitHub
If you want to run other websites on the same machine as Discourse, you need to set up an extra NGINX or HAProxy proxy in front of the Docker container.
This guide assumes you already have Discourse working - if you don’t, it may be hard to tell whether or not the configuration is working.

1. Install nginx outside the container

First, make sure the container is not running:

cd /var/discourse
./launcher stop app

Then install Nginx:

sudo apt install nginx

2. Change the container definition

This is where we change how Discourse actually gets set up. We don’t want the container listening on ports - instead, we’ll tell it to listen on a special file.
Change your /var/discourse/containers/app.yml to look like this:

#base templates used; can cut down to include less functionality per container templates:
  #- "templates/cron.template.yml" # cron is now included in base image
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/sshd.template.yml"
  - "templates/web.template.yml"
  #- "templates/web.ssl.template.yml" # remove - https will be handled by outer nginx
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"  # <-- Added
#which ports to expose?
#expose: comment out entire section

3. Create an NGINX ‘site’ for the outer nginx

For an HTTPS site, put this in /etc/nginx/sites-enabled/discourse.conf, making sure to change the server_name.
For obtaining and configuring Cloudflare 1-year certificates, please refer to my previous post USE CLOUDFLARE CERTIFICATE WITH NGINX + V2RAY + WEBSOCKET +TLS + CDN

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 302 https://$server_name$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;

  ssl_certificate       /your/path/yourdomain_cert.pem; #certificate format varies, like .cer, .crt, etc
  ssl_certificate_key   /your/path/yourdomain_key.pem; #private key format varies, like .key, etc
#ssl_dhparam          /your/path/dhparams.pem; #optional
#Authenticated Origin Pull is optional. Please refer to https://developers.cloudflare.com/ssl/origin/authenticated-origin-pull/
#ssl_client_certificate  /etc/ssl/origin-pull-ca.pem;
#ssl_verify_client on;
  ssl_session_timeout 1d;
  ssl_session_cache shared:MozSSL:10m;
  ssl_session_tickets off;

  ssl_protocols         TLSv1.2 TLSv1.3;
  ssl_ciphers           ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers off;

  server_name           example.com www.example.com;
    add_header Content-Security-Policy upgrade-insecure-requests; #Important: Some users experience warning of “not fully secure” on major browsers. This is because of mixed content issues. Please add this line to ensure HTTPS enabling.
    location /nameofpath {
    if ($http_upgrade != "websocket") {
        return 404;
    }
    proxy_redirect off;
    proxy_pass http://127.0.0.1:12345; #Set your own port
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  location / {
    proxy_redirect off;
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:; 
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Make sure that the default site is either disabled or has the correct server_name set.
Then, in a shell:
Make sure that Discourse isn't running

/var/discourse/launcher stop app || true

test configuration

sudo nginx -t

Important: If nginx -t comes back with an error, correct the config before reloading!

sudo systemctl restart nginx

4. Ready to go

Rebuild the container to apply changes

/var/discourse/launcher rebuild app

Copyright statement: Unless otherwise stated, all articles on this blog adopt the CC BY-NC-SA 4.0 license agreement. For non-commercial reprints and citations, please indicate the author: Henry, and original article URL. For commercial reprints, please contact the author for authorization.