Running other websites on the same machine as Discourse

(John) #264

is anyone using discourse with ssl enabled in the app.yml? I noticed that eventually the ssl enable setting will cause discourse to become unusuable. Commenting out:

#  - "templates/web.ssl.template.yml"
#  - "templates/web.letsencrypt.ssl.template.yml"

was the only way to get it to work well but I would perfer encryption on both the reverse proxy and discourse.

(Duong Dang) #265

Thank you so much, this is the first time I using Discourse for my forum.

(Jay Pfaffman) #266

If the reverse proxy is on the same machine there is no reason for https on Discourse.

#267

Thanks so much. :slight_smile:

(Skygunner) #268

Setup reverse proxy like this, running nginx outside the container, would the outside nginx talk to discourse backend directly or go through the inside nginx? I mean is there any performance penalty?
I ask because I might need to custom the nginx setting a bit in the future.

Cheers,

(Sam Saffron) #269

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

4 Likes
(Skygunner) #270

That’s cool mate, thank you for the quick reply

2 Likes
(Rohit D) #271

Using this superb tutorial, I was able to successfully set up and run a website on Nginx installed outside the Discourse container in the same droplet on DigitalOcean.

However, after I did that… upon loading the Discourse forum in the browser, the padlock security indicator got replaced by an ‘info’ symbol with description:

“Your connection to this site is not fully secure: Attackers might be able to see the images you’re looking at on this site and trick you by modifying them…”

Could you please advise how I can correct this.

(Jay Pfaffman) #272

You need to install and configure certbot for your external NGINX.

(Rohit D) #273

Thank you for your response.

I have set up Certbot and configured the external Nginx to use the certificates for my website by following this guide and it works perfectly including the automatic certificate renewal, but is it possible to get Certbot to do the same for my Discourse instance too through the external Nginx?

(Jay Pfaffman) #274

Did you run certbot again after you added the discourse reverse proxy?

And have it add the new subdomain?

(Rohit D) #275

I had created a custom server block file for the external Nginx website and pointed Certbot to the block file with a different domain name. I am not using any subdomain for either the Nginx site or the Discourse one.

Ran Certbot again and it has installed new certificates for both the domain names. Problem solved. Thanks a lot.

By the way, there is a typo in this guide in the following line. Remove the extra colon ( : ) at the end.

proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;

Corrected version:

proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock;
2 Likes
(Claus Strasburger) #276

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
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;

}
7 Likes
#277

Hi,

I’m using jwilder/nginx-proxy + JrCs/docker-letsencrypt-nginx-proxy-companion and it’s almost working.

I added env variables to the app.yml:

# Nginx Reverse proxy / let's encrypt config
VIRTUAL_HOST: "my.domain.fr"
LETSENCRYPT_HOST: "my.domain.fr"
LETSENCRYPT_EMAIL: "my@email.com"
VIRTUAL_PORT: 3001

I can access the forum through https but I get a warning message in the url bar:

Parts of this page are not secure (such as images).

And effectively my images a referenced as non https: “http://my.domain.fr/uploads/default/optimized/…”.

Did you have this error? Is it a discourse config that I’m missing or should the nginx reverse proxy redirect to https ?

(Jay Pfaffman) #278

Enable the

Force https 

Site setting

#279

You are talking about site_enabled settings? The thing is that I don’t have to write any nginx site setting with my setup (the nginx-proxy docker image I use handle this part), I’m just supposed to expose the port used and subdomain names. It looks like a Discourse problem as images links are generated from the app and shouldn’t be dependent on weather I’ using a proxy or not

EDIT: Ok @pfaffman, thanks a lot :slight_smile: I googled a bit and found what you meant:

Now working great!

1 Like
#280

Ok I guess it was a cache problem but the favicon was still loaded from http. I had to reupload it to make it go through https.

#281

@riking So I know I’ve started a Topic elsewhere on the topic of reverse proxying, but this time I figured I should ask here directly; also this time I’m just trying to do Reverse Proxying of HTTP before I touch HTTPS.

Currently I’m getting the default “Welcome to nginx!” when I connect to discourse.myreserveddns.com in a browser. What am I doing wrong? Keep in mind my Discourse and Nginx are on separate VMs. (which is something this guide does not cover how to handle)

`/var/discourse/containers/'app.yml on the Discourse VM

## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

templates:
  - "templates/cron.template.yml"
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/sshd.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"  # <-- Added
## Uncomment these two lines if you wish to add Lets Encrypt (https)
# - "templates/web.ssl.template.yml"
# - "templates/web.letsencrypt.ssl.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
# expose:
# - "80:80"   # http
# - "443:443" # https
# - "8443:443" # fwd host port 443 to container port 443 (https)
# - "2222:22" # required as per "Allowing SSL / HTTPS for your Discourse Docker setup"

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Set db_shared_buffers to a max of 25% of the total memory.
  ## will be set automatically by bootstrap based on detected RAM, or you can override
  db_shared_buffers: "768MB"

  ## can improve sorting performance, but adds memory usage per-connection
  #db_work_mem: "40MB"

  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override
  UNICORN_WORKERS: 4

  ## TODO: The domain name this Discourse instance will respond to
  ## Required. Discourse will not work with a bare IP number.
  DISCOURSE_HOSTNAME: discourse.myreserveddns.com

  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## 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: 'admin@myreserveddns.com,postmaster@myreserveddns.com'

  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS, username, and password are required
  # WARNING the char '#' in SMTP password can cause problems!
  DISCOURSE_SMTP_ADDRESS: smtp.sparkpostmail.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: SMTP_Injection
  DISCOURSE_SMTP_PASSWORD: "XXXXX" # Not putting the actual password here!
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)

  ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
  #LETSENCRYPT_ACCOUNT_EMAIL: admin@myreserveddns.com

  ## The http or https CDN address for this Discourse instance (configured to pull)
  ## see https://meta.discourse.org/t/14857 for details
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
        ##- git clone https://github.com/discourse/discourse-chat-integration.git
        ##- git clone https://github.com/discourse/discourse-slack-integration.git

## Any custom commands to run after building
run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  - exec: rails r "SiteSetting.notification_email='postmaster@myreserveddns.com'"
  - exec: echo "End of custom commands"

/etc/nginx/sites-available/discourse.conf on the Nginx VM:

server {
# The IP that you forwarded in your router (nginx proxy)
 listen 192.168.0.101:80; listen [::]:80; # Nginx's Private IP

# Make site accessible from http://localhost/
 server_name discourse.myreserveddns.com;

# The internal IP of the VM that hosts your Apache config
 set $upstream 192.168.0.104; # Discourse's Private IP

 location / {

 #proxy_redirect http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
 proxy_pass http://discourse.myreserveddns.com; # Put in place of the line above
 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;

 }
}

So I commented out proxy_redirect http://unix:/var/discourse/shared/standalone/nginx.http.sock:; because it was giving me an error in Nginx:

nginx: [emerg] invalid parameter "http://unix:/var/discourse/shared/standalone/nginx.http.sock:" in /etc/nginx/sites-enabled/http.discourse.myreserveddns.com.conf:14

I’m sure the issue is related to the fact that /var/discourse/shared/standalone/nginx.http.sock doesn’t actually exist in the Nginx VM. Any recommendation on how to modify the proxy_redirect line?

(Vincent) #282

Try as follows:

proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;

And remove the proxy_pass directive you added.

#283

Thank you for the suggestion @_vincent. I suppose it should have been obvious that I was supposed to put proxy_pass instead of proxy_redirect in the conf file.

Well, I just edited the discourse.conf file on the Nginx VM: Here’s what it looks like now:

server {
# The IP that you forwarded in your router (nginx proxy)
 listen 192.168.0.101:80; listen [::]:80;

# Make site accessible from http://localhost/
 server_name discourse.myreserveddns.com;

# The internal IP of the VM that hosts your Apache config
 set $upstream 192.168.0.104;

 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 $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Real-IP $remote_addr;

 }
}

I saved the file and ran systemctl restart nginx.service, and even restarted the Discourse ./launcher in the Discourse VM. Unfortunately going to discourse.myreserveddns.com in a web browser still takes me to the “Welcome to nginx!” page.

Any other suggestions of what I should try next?