# Run other websites on the same machine as Discourse

**URL:** https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247
**Category:** Self-Hosting
**Tags:** how-to, advanced-setup
**Created:** [July 5, 2014, 8:36pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247 "2014-07-05T20:36:15Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [July 5, 2014, 8:36pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/1 "2014-07-05T20:36:15Z")

</div>

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.

### NOTE: This is for advanced admins

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.

You cannot use `./discourse-setup` to set up Discourse if another server is using port 80 or 443. You will need to copy and edit `samples/standalone.yml` with your favorite text editor.

## Install nginx outside the container

First, make sure the container is not running:

```
cd /var/discourse
./launcher stop app

```

Then install nginx and certbot:

```
sudo apt-get update && sudo apt-get install nginx certbot python3-certbot-nginx

```

## 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.

You need to edit `/var/discourse/containers/app.yml` to disable ssl and add template to create nginx sock. It should look like this:

```yml
# base templates used; can cut down to include less functionality per container templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  # - "templates/web.ssl.template.yml" # remove - https will be handled by outer nginx
  # - "templates/web.letsencrypt.ssl.template.yml" # remove -- https will be handled by outer nginx
  - "templates/web.socketed.template.yml" # <-- Added

```

Be sure to remove or comment out the exposed ports by putting a `#` in front.

```plaintext
# which ports to expose?
# expose: comment out entire section by putting a # in front of each line
# - "80:80" # http
# - "443:443" # https

```

Now you can

```plaintext
/var/discourse/launcher rebuild app

```

to rebuild Discourse to make its data available to the socket.

If you are using some other reverse proxy that cannot use a web socket, you can instead expose a different port in the section above like `- 8080:80`.

## Create an NGINX ‘site’ for the outer nginx

Create a site file for Discourse:

```plaintext
cd /etc/nginx/sites-available
cp default discourse.example.com
cd ../sites-enabled
ln -s ../sites-available/discourse.example.com

```

Next edit that file by commenting out these lines:

```plaintext
        #listen 80 default_server;
        #listen [::]:80 default_server;

```

and editing the `server_name` and `location` stanza like this:

```nginx
    server_name discourse.example.com; # <-- change this

location / {
                proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
                proxy_set_header Host $http_host;
                proxy_http_version 1.1;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Real-IP $remote_addr;

}

```

If you’re using a two-container installation the socket line will be:

```
                proxy_pass http://unix:/var/discourse/shared/web-only/nginx.http.sock:;

```

Then, in a shell:

```bash
certbot --nginx

```

And follow the instructions. If you don’t understand the prompts, you probably shouldn’t be doing this, but can check the `certbot` docs for help.

@pfaffman thinks that `certbot` will do this for you, but if you make changes to the nginx config you will need to

```plaintext
sudo service nginx reload

```

## Create your other sites

You’re done with the Discourse section!

Make other NGINX “sites”, then link and enable them, as in the last step above.

## Tips

- `sudo netstat -tulpn` : This will tell you what ports are being used
- `/var/log/nginx/error.log` : Is the location of the nginx log on ubuntu. This will tell you what the error is when you get a 502 Bad Gateway error.

> Last edited by @supermathie 2026-06-29T18:01:43Z
> 
> > **Check document**
> >
> > Perform check on document:

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [March 11, 2018, 9:51am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/182 "2018-03-11T09:51:13Z")

</div>

The guide in the first post is great and, on the whole, still works just fine ☀

There are three things worth noting:

1. I initially missed some of the `app.yml` changes. There are **3 things** you need to change in your app.yml. If you miss any of these things it won’t work:

2. As others mentioned, I had to change the ssl cert and key names in the `discourse.conf`:

3. Turns out my site didn’t have a `dhparams.pem` key (dh stands for Diffie Hellman, there’s some good explanations of what this is [here](https://security.stackexchange.com/questions/45963/diffie-hellman-key-exchange-in-plain-english)). You can generate this yourself:

Some other things you may find useful:

- `sudo netstat -tulpn`: This will tell you what ports are being used

- `/var/log/nginx/error.log`: Is the location of the nginx log on ubuntu. This will tell you what the error is when you get a 502 Bad Gateway error.

- You may finish a `./launcher rebuild app`, excitedly go to your domain to see if it worked and be greeted with a depressing 502 Bad Gateway error. Before giving up in frustration, try restarting nginx one more time:

Now my [sandbox](https://discourse.angusmcleod.com.au/) is using nginx outside the container (although I haven’t added the extra website yet).

---

<div class="post-metadata">

### Author: ![raphael\_jolivet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/raphael_jolivet/32/115344_2.png) [@raphael\_jolivet](https://meta.discourse.org/u/raphael_jolivet)
#### Post date: [May 23, 2018, 1:10pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/244 "2018-05-23T13:10:32Z")

</div>

Hi,

I am just doing a fresh install of Discourse.  
I am very surprised that :

- The setup script does not simply allow to setup on a different port, disabling SSL support, and then it’s up to us to do reverse proxy as we want (Apache, Nging) : It seems such a common setup, it would save hundreds of hours of life to humanity
- I am even more surprised that the setup redirects us to an outdated forum topic, in which we need to dig for the proper information, instead of a proper documentation page, kept up to date.

Thanks guys anyway for your work, but I think there is room for improvement here.  
Cheers

---

<div class="post-metadata">

### Author: ![mottosso](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mottosso/32/142771_2.png) [@mottosso](https://meta.discourse.org/u/mottosso)
#### Post date: [June 7, 2018, 1:13pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/257 "2018-06-07T13:13:45Z")

</div>

Just wanted to share how I accomplished this, it was a little easier than I first thought.

From an already running machine, with Caddy acting as a reverse proxy for a number of existing Docker containers already.

1. Clone discourse as per the official instructions
2. Copy `/var/discourse/samples/standalone.yml` → `/var/discourse/containers/app.yml`
3. Fill in SMTP settings and website address
4. Comment out `443:443` from the `expose:` section
5. Replace `80:80` → `3001:80`, 3001 being the port I’m serving via Caddy
6. Run `./launcher rebuild app`
7. Done

Whop!

---

<div class="post-metadata">

### Author: ![riking](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/riking/32/170938_2.png) [@riking](https://meta.discourse.org/u/riking)
#### Post date: [September 5, 2018, 5:39pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/259 "2018-09-05T17:39:09Z")

</div>

@TheBestPessimist I swapped the order of the HTTP/HTTPS sections, it works better than adding a “don’t do this!” notice 🙂

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [April 15, 2019, 1:01am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/269 "2019-04-15T01:01:34Z")

</div>

I would recommend just doing double NGINX, it is far more complex to set it up direct and has virtually no performance cost. Getting it right would be very hard cause we serve some files direct and have a layer of caching that is tricky to configure.

Note, customizing NGINX is easy with mixin templates have a look at the various example templates here: [discourse\_docker/templates at master · discourse/discourse\_docker · GitHub](https://github.com/discourse/discourse_docker/tree/master/templates)

---

<div class="post-metadata">

### Author: ![cfstras](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/cfstras/32/103104_2.png) [@cfstras](https://meta.discourse.org/u/cfstras)
#### Post date: [April 21, 2019, 4:50pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/276 "2019-04-21T16:50:03Z")

</div>

PSA: If you want to allow uploads larger than 1MB to your site, you’ll also have to set `client_max_body_size 100M` in _any_ nginx config that sits in front of your site.

For reference, here’s the full nginx config I use:

> **nginx config for other sites on same host**
>
> ```plaintext
> server {
> if ($host = discourse.mysite.org) {
> return 301 https://$host$request_uri;
> } # managed by Certbot
> 
> if ($host = backupname.mysite.org) {
> return 301 https://$host$request_uri;
> } # managed by Certbot
> 
> listen 80; listen [::]:80;
> server_name discourse.mysite.org;
> server_name backupname.mysite.org;
> 
> location / {
> proxy_pass http://unix:/var/discourse/shared/mysite/nginx.http.sock:;
> proxy_set_header Host $http_host;
> proxy_http_version 1.1;
> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
> proxy_set_header X-Forwarded-Proto $scheme;
> proxy_set_header X-Real-IP $remote_addr;
> }
> }
> 
> # nginx 1.14.1 | intermediate profile | OpenSSL 1.1.0f | link
> 
> server {
> listen 443 ssl http2; listen [::]:443 ssl http2;
> server_name discourse.mysite.org;
> server_name backupname.mysite.org;
> 
> # from discourse examples
> http2_idle_timeout 5m; # up from 3m default
> client_max_body_size 50M; # allow 50M uploads
> 
> location / {
> proxy_pass http://unix:/var/discourse/shared/mysite/nginx.http.sock:;
> proxy_set_header Host $http_host;
> proxy_http_version 1.1;
> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
> proxy_set_header X-Forwarded-Proto https;
> proxy_set_header X-Real-IP $remote_addr;
> }
> ssl_certificate /etc/letsencrypt/live/backupname.mysite.org/fullchain.pem; # managed by Certbot
> ssl_certificate_key /etc/letsencrypt/live/backupname.mysite.org/privkey.pem; # managed by Certbot
> 
> ###### https://mozilla.github.io/server-side-tls/ssl-config-generator/ ####
> 
> ssl_session_timeout 1d;
> ssl_session_cache shared:SSL:50m;
> ssl_session_tickets off;
> 
> # modern configuration. tweak to your needs.
> ssl_protocols TLSv1.2;
> ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
> ssl_prefer_server_ciphers on;
> 
> # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
> add_header Strict-Transport-Security max-age=15768000;
> 
> # OCSP Stapling ---
> # fetch OCSP records from URL in ssl_certificate and cache them
> ssl_stapling on;
> ssl_stapling_verify on;
> 
> ## verify chain of trust of OCSP response using Root CA and Intermediate certs
> ssl_trusted_certificate /etc/letsencrypt/live/backupname.mysite.org/chain.pem;
> 
> resolver 1.1.1.1;
> 
> }
> 
> ```

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [October 18, 2021, 1:48pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/396 "2021-10-18T13:48:27Z")

</div>

16 posts were split to a new topic: [Using Nginx Proxy Manager to manage multiple sites with Discourse](https://meta.discourse.org/t/using-nginx-proxy-manager-to-manage-multiple-sites-with-discourse/206344)

---

<div class="post-metadata">

### Author: ![Godmar\_Back](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/godmar_back/32/206246_2.png) [@Godmar\_Back](https://meta.discourse.org/u/Godmar_Back)
#### Post date: [August 21, 2021, 1:24am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/401 "2021-08-21T01:24:40Z")

</div>

[angus’s](https://meta.discourse.org/t/running-other-websites-on-the-same-machine-as-discourse/17247/182) instructions still work; I have a question, though: will LetsEncrypt still work automatically with this after 3 months when it’s time to renew the certificates? (I assume/hope the answer is yes since the host nginx reads them directly from `/var/discourse/shared/standalone`?)

---

<div class="post-metadata">

### Author: ![Blechpirat](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blechpirat/32/221370_2.png) [@Blechpirat](https://meta.discourse.org/u/Blechpirat)
#### Post date: [August 25, 2021, 10:34am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/402 "2021-08-25T10:34:33Z")

</div>

@Godmar_Back I ran into this problem right now, and my certificate was NOT renewed.

@angus - since we use the letsencrypt certs created by discourse, but commented out the relevant parts in app.yml, I guess the update script is no longer being started. Did you find a solution for that?

---

<div class="post-metadata">

### Author: ![Blechpirat](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blechpirat/32/221370_2.png) [@Blechpirat](https://meta.discourse.org/u/Blechpirat)
#### Post date: [August 25, 2021, 10:53am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/403 "2021-08-25T10:53:27Z")

</div>

I tried entering the app and

```plaintext
 "/shared/letsencrypt"/acme.sh --cron --home "/shared/letsencrypt" --force

```

which kind of showed me at least a problem.

```plaintext
my.site.com:Verify error:Fetching https://my.seite.com/.well-known/acme-challenge/XXXXXXXedited-out-XXXXXXXXXXXXXXXXXXXX: Error getting validation data
[Mi 25. Aug 10:41:37 UTC 2021] Please check log file for more details: /shared/letsencrypt/acme.sh.log

```

Acme.sh.log pretty much repeats the error message. But it also tells me that all config files are empty.

On the otherhand acme.sh updated itself, so I assume it has not been started in the background for a while, probably since I changed to the outer nginx.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [August 25, 2021, 11:44am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/404 "2021-08-25T11:44:29Z")

</div>

> [@Blechpirat](#):
>
> ommented out the relevant parts in app.yml, I guess the update script is no longer being started.

You’ll need to handle those outside the container. Follow whatever guide is for let’s encrypt and nginx.

---

<div class="post-metadata">

### Author: ![Simon\_Manning](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon_manning/32/198596_2.png) [@Simon\_Manning](https://meta.discourse.org/u/Simon_Manning)
#### Post date: [September 6, 2021, 12:52am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/411 "2021-09-06T00:52:43Z")

</div>

As it’s past the period you can edit it yourself, you could flag it. You can flag a post, including your own, by clicking the ellipsis followed by the flag icon at the bottom of the post.

In this case you would choose to flag it as “Something Else” and explain that your email reply included the content from the previous post.

---

<div class="post-metadata">

### Author: ![herrdu](https://avatars.discourse-cdn.com/v4/letter/h/ba9def/32.png) [@herrdu](https://meta.discourse.org/u/herrdu)
#### Post date: [September 8, 2021, 3:12am UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/412 "2021-09-08T03:12:40Z")

</div>

[https://meta.discourse.org/t/upload-problem-with-https-or-http2-and-s3/202799/3](https://meta.discourse.org/t/upload-problem-with-https-or-http2-and-s3/202799/3)

---

<div class="post-metadata">

### Author: ![Nope](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nope/32/238556_2.png) [@Nope](https://meta.discourse.org/u/Nope)
#### Post date: [October 31, 2021, 7:30pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/419 "2021-10-31T19:30:28Z")

</div>

I’ve just got my new install of discourse on my new server, and after restoring the backup, now I get an issue with SSL.

It says that “parts of this page are not secure, such as images” and after a quick google search I seen that it means the images and fonts etc are not being served over https. However everything appears that it is.

I just copied the NGINX config, and it wasn’t there before I restored the backup.

Any ideas?

[https://parentofsociety.com](https://parentofsociety.com)

---

<div class="post-metadata">

### Author: ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)
#### Post date: [October 31, 2021, 7:53pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/420 "2021-10-31T19:53:34Z")

</div>

You could check your `force_https` is enabled in your admin settings. There have been a few issues with that recently.

---

<div class="post-metadata">

### Author: ![cmdntd](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/cmdntd/32/192008_2.png) [@cmdntd](https://meta.discourse.org/u/cmdntd)
#### Post date: [December 20, 2021, 6:05pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/421 "2021-12-20T18:05:09Z")

</div>

> [@riking](#):
>
> You cannot use `./discourse-setup` to set up Discourse if another server is using port 80 or 443. You will need to copy and edit `samples/standalone.yml` with your favorite text editor.

If I had Discourse docker on server, but it was using port in 980 and 9443 (reserve proxy)  
Could I use `./discourse-setup` to set up another Discourse? (Pull another folder of discourse)  
It seems more simple by this way, isn’t it?

---

<div class="post-metadata">

### Author: ![Stephen](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/stephen/32/95011_2.png) [@Stephen](https://meta.discourse.org/u/Stephen)
#### Post date: [December 20, 2021, 6:06pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/422 "2021-12-20T18:06:00Z")

</div>

Why would you do that over running multi-site?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [December 20, 2021, 6:28pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/423 "2021-12-20T18:28:23Z")

</div>

> [@cmdntd](#):
>
> Could I use `./discourse-setup` to set up another Discourse? (Pull another folder of discourse)

You can create `appy.yml` but you can’t use `discourse-setup`. Copy the other one and edit it.

> [@Stephen](#):
>
> Why would you do that over running multi-site?

It is sort of more complicated and requires all sites to use same mail and plugins. For most people it’s easier to just run another server, I think.

---

<div class="post-metadata">

### Author: ![cmdntd](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/cmdntd/32/192008_2.png) [@cmdntd](https://meta.discourse.org/u/cmdntd)
#### Post date: [December 20, 2021, 6:42pm UTC](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247/424 "2021-12-20T18:42:45Z")

</div>

> [@pfaffman](#):
>
> It is sort of more complicated and requires all sites to use same mail and plugins. For most people it’s easier to just run another server, I think.

Yes, exactly  
And the single one will be supported more by discourse team

> [@pfaffman](#):
>
> You can create `appy.yml` but you can’t use `discourse-setup` . Copy the other one and edit it.

Could you explain how to do it?

1. I had app.yml  
Could I copy **other discourse folder** , and **app02.yml**?

2. Could I run `./discourse-setup` when I copied **discourse02 folder** and **app02.yml**?  
How could I config it here?  
I want to be sure that two of container not conflict each other.

3. My current container named “ **app** ”.  
Could I changed its name by rename app.yml?

[Next page](https://meta.discourse.org/t/run-other-websites-on-the-same-machine-as-discourse/17247.md?page=2)
