Discourse not loading with Apache and proxy redirect

Dear @OrbitStorm,

I took a quick look at your Apache2 virtual hosts configuration for you and your yml file for Discourse and they do not appear to be correctly configured.

Here are some hints:

First of all, when you run Discourse behind a reverse proxy, you do not enable SSL LETSENCRYPT in the Discourse yml configuration (see working example below). Discourse only needs a single port to communicate with the reverse proxy and that is not an SSL encrypted connection.

Second, if you look at your main virtual host configuration, which is the port 443 on the reverse proxy:

<IfModule mod_ssl.c>
<VirtualHost *:443>
	ServerAdmin webmaster@localhost
	ServerName mysite.com
	ServerAlias www.mysite.com
	DocumentRoot /var/www/mysite.com
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

       Include /etc/letsencrypt/options-ssl-apache.conf
       SSLCertificateFile /etc/letsencrypt/live/mysite.com/fullchain.pem
       SSLCertificateKeyFile /etc/letsencrypt/live/mysite.com/privkey.pem
</VirtualHost>
</IfModule>

That configuration above is missing all necessary reverse proxy information (see attached working configurations below).

Here is a working configuration for you, which is basically the same as outlined in the various tutorials on meta (well documented on this site in other posts, so this is basically duplicating other documentation here at meta):

<VirtualHost *:80>
        ServerName discourse.your-great-web-site.com
        ServerAdmin webmaster@localhost
        ProxyPreserveHost On
        ErrorLog ${APACHE_LOG_DIR}/discourse_errors.log
        CustomLog ${APACHE_LOG_DIR}/discourse.log combined
        ModPagespeed Off
        RewriteEngine on
        RewriteCond %{SERVER_NAME} =discourse.your-great-web-site.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Note that in the port 80 configuration, there is the main required directives are the ServerName, RewriteEngine and rewrite rules to redirect to port 443.

Also, if you are running Apache2 mod_pagespeed you should disable as I have not yet got mod_pagespeed working with Discourse (and see no reason to do so either).

Here is the main config, where the “real-work” is done:

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName discourse.your-great-web-site.com
        ServerAdmin webmaster@localhost
        SSLProxyEngine on      # enable this only after let's encrypt is configured and working
  	    RewriteEngine on
  	    ProxyPreserveHost On
  	    ProxyRequests Off
  	    RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
 	    RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}

        #ProxyPass / http://127.0.0.1:8888/           # we do not use port, we use your-great-web-site sockets
        #ProxyPassReverse / http://127.0.0.1:8888/    # we do not use port, we use your-great-web-site sockets
        ProxyPass / your-great-web-site:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/
        ProxyPassReverse  / your-great-web-site:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/

        ErrorLog ${APACHE_LOG_DIR}/discourse_errors_ssl.log
        #CustomLog ${APACHE_LOG_DIR}/discourse_ssl.log combined   #access log disabled for production

        ModPagespeed Off
        SSLCertificateFile /etc/letsencrypt/live/discourse.your-great-web-site.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/discourse.your-great-web-site.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

All our discourse configurations use unix domain sockets, so you will need to change the configuration to match your desired configuration.

The main point to understand (in summary), is that you should disable LETSENCRYPT in your Discourse build (yml) configuration and only expose a single entry point into Discourse, in our case a unix domain socket, in your case a single TCP/IP socket.

Then you reverse proxy to that entry point from the virtual host file for port 443 (not from the port 80 virtual host). The port 80 virtual host simply redirects to 443. Your 443 SSL is all done by LETSENCRYPT in the reverse proxy. There is no SSL required in your Discourse yml file (see working example below).

Here is one of our working yml files (for the configuration above) for you to review:

/var/discourse/containers$ cat socket-only.yml
# IMPORTANT: SET A SECRET PASSWORD in Postgres for the Discourse User
# TODO: change SOME_SECRET in this template

templates:
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
#  - "templates/sshd.template.yml"
## 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

# Use 'links' key to link containers together, aka use Docker --link flag.
links:
  - link:
      name: data
      alias: data

# any extra arguments for Docker?
# docker_args:

params:
  ## Which Git revision should this container use? (default: tests-passed)
  #version: latest
  db_shared_buffers: "4GB"

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: 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: 3
  UNICORN_WORKERS: 8

  ## TODO: The domain name this Discourse instance will respond to
  DISCOURSE_HOSTNAME: 'discourse.your-great-web-site.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: 'tim@discourse.your-great-web-site.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.gmail.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: not_for_reply@discourse.your-great-web-site.com
  DISCOURSE_SMTP_PASSWORD: my_super_secret_cool_password
  #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: me@example.com

  ## TODO: configure connectivity to the databases
  DISCOURSE_DB_SOCKET: ''
  #DISCOURSE_DB_USERNAME: discourse
  DISCOURSE_DB_PASSWORD: another_super_secret_cool_password
  DISCOURSE_DB_HOST: data
  DISCOURSE_REDIS_HOST: data

  DISCOURSE_MAXMIND_LICENSE_KEY: my_max_mind_key
  ## 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

volumes:
  - volume:
      host: /var/discourse/shared/socket-only
      guest: /shared
  - volume:
      host: /var/discourse/shared/socket-only/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-bbcode.git
          - git clone https://github.com/discourse/discourse-sitemap.git
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-whos-online.git
          - git clone https://github.com/unixneo/legacy-info.git

## Remember, this is YAML syntax - you can only have one block with a name
run:
  - exec: echo "Beginning of custom commands"

  ## If you want to configure password login for root, uncomment and change:
  ## Use only one of the following lines:
  #- exec: /usr/sbin/usermod -p 'PASSWORD_HASH' root
  #- exec: /usr/sbin/usermod -p "$(mkpasswd -m sha-256 'RAW_PASSWORD')" root

  ## If you want to authorized additional users, uncomment and change:
  #- exec: ssh-import-id username
  #- exec: ssh-import-id anotherusername

  - exec: echo "End of custom commands"
  #- exec: awk -F\# '{print $1;}' ~/.ssh/authorized_keys | awk 'BEGIN { print "Authorized SSH keys for this container:"; } NF>=2 {print $NF;}'

It’s really easy once you understand the basics; and understanding the basics does help quite a lot :slight_smile:

Please keep in mind that in our Discourse configurations, we do not run a single container (actually, we rarely run in single container mode), so our yml file will not work in a single container (standalone) configuration. I am providing it to you for reference to help you, by showing you what a fully working configuration behind Apache2 looks like.

We run Discourse behind both Apache2 and nginx reverse proxies. In fact, we only use reverse proxies for many reasons. One reason is that we can use the reverse proxy to filter bad bots, etc (a totally different subject).

There is nothing difficult about running Dockerized Discourse (as many sites as you want, one or 100) behind a reverse proxy on a site with Apache2; but it does help to understand the basic concepts.

I hope providing you both the basic concepts and working example configuration files help you move forward and get Discourse up and running.

Best Regards…

1 like