I want to install using a reverse proxy for Apache

I wanted to install using Apache’s reverse proxy and tried to install with a custom port, but it didn’t work.
Is there any way to do this?

Checking your domain name . . .
WARNING: Port 443 of computer does not appear to be accessible using hostname:  
DOMAIN-NAME
WARNING: Connection to DOMAIN-NAME (port 80) also fails.

This suggests that DOMAIN-NAME resolves to some IP address that does not reach this 
machine where you are installing discourse.

The first thing to do is confirm that DOMAIN-NAME resolves to the IP address of this server.
You usually do this at the same place you purchased the domain.

If you are sure that the IP address resolves correctly, it could be a firewall issue.
A web search for "open ports YOUR CLOUD SERVICE" might help.

This tool is designed only for the most standard installations. If you cannot resolve
the issue above, you will need to edit containers/app.yml yourself and then type

FAILED
--------------------
Pups::ExecError: /usr/local/bin/ruby -e 'if ENV["DISCOURSE_HOSTNAME"] == "discourse.example.com"; puts "Aborting! Domain is not configured!"; exit 1; end' failed with return #<Process::Status: pid 176 exit 1>
Location of failure: /pups/lib/pups/exec_command.rb:112:in `spawn'
exec failed with the params "/usr/local/bin/ruby -e 'if ENV[\"DISCOURSE_HOSTNAME\"] == \"discourse.example.com\"; puts \"Aborting! Domain is not configured!\"; exit 1; end'"
de0d133ffdd4c51d9a870d09bd16ce8fcc0680130ced1446f0038b4175a46840
** 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.

app.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:
  - "127.0.0.1:8100:80"   # http

params:

You can’t use discourse-setup, but you can search: How to set up Discourse on a server with existing Apache sites

2 Likes

Thank you.
I followed the guide to build the Discource.
However, the reverse proxy in Apache is not working properly.

    ProxyPass /  ws://var/discourse/shared/standalone/nginx.http.sock
    ProxyPassReverse / ws://var/discourse/shared/standalone/nginx.http.sock

Error

 No protocol handler was valid for the URL /favicon.ico (scheme 'ws'). If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule., 

Dear @Teraterayuki

Here is an example set of working Apache2 virtual hosts for a reverse proxy to a unix domain socket in a Discourse container:

Port 80

<VirtualHost *:80>
        ServerName mysite.mydomain.com
        ServerAdmin webmaster@localhost
        ProxyPreserveHost On

        #ProxyPass / http://127.0.0.1:8888/
        #ProxyPassReverse / http://127.0.0.1:8888/

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/community_errors.log
        CustomLog ${APACHE_LOG_DIR}/community.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        ModPagespeed Off
        RewriteEngine on
        RewriteCond %{SERVER_NAME} =mysite.mydomain.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Port 443

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName mysite.mydomain.com
        ServerAdmin webmaster@localhost
        #SSLProxyEngine on   #enable this after Let's encrypt is setup on the reverse proxy
  	    RewriteEngine On
        
        RewriteCond %{HTTP_USER_AGENT}  (Bytespider|Yandex|Wget|seocompany|CCBot|Cincraw) [NC]
        RewriteRule . - [R=403,L]

  	    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/
        #ProxyPassReverse / http://127.0.0.1:8888/
        ProxyPass / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/
        ProxyPassReverse  / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/community_errors_ssl.log
        #CustomLog ${APACHE_LOG_DIR}/community_ssl.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        ModPagespeed Off
        SSLCertificateFile /etc/letsencrypt/live/mysite.mydomain.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/mysite.mydomain.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

@Teraterayuki

Kindly note that in this configuration the proxy is with a unix socket not a web socket (ws)

Note also that in this configuration you do not need to manually add the Let’s Encrypt info. You can start with this:

Port 80 Before Running Certbot

<VirtualHost *:80>
        ServerName mysite.mydomain.com
        ServerAdmin webmaster@localhost
        ProxyPreserveHost On

        #ProxyPass / http://127.0.0.1:8888/
        #ProxyPassReverse / http://127.0.0.1:8888/

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/community_errors.log
        CustomLog ${APACHE_LOG_DIR}/community.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        ModPagespeed Off
     
</VirtualHost>

Port 443 Before Running Certbot

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName mysite.mydomain.com
        ServerAdmin webmaster@localhost
        #SSLProxyEngine on   #enable this after Let's encrypt is setup on the reverse proxy
  	    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/
        #ProxyPassReverse / http://127.0.0.1:8888/
        ProxyPass / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/
        ProxyPassReverse  / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/community_errors_ssl.log
        #CustomLog ${APACHE_LOG_DIR}/community_ssl.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        ModPagespeed Off

</VirtualHost>
</IfModule>

Then, if you run:

certbot -d mysite.mydomain.com

Friendly certbot will take care of appending the required SSL code for you.

After our friend certbot has added it’s conf code and all is working as expected, you can uncomment this line:

#SSLProxyEngine on   #enable this after Let's encrypt is setup on the reverse proxy

and restart apache2 again.

Hope this helps @Teraterayuki

Take care.


Closing Notes:

  1. Kindly note that we do not use haproxy in our apache2 reverse proxy configurations. haproxy adds an unnecessary layer of complexity with almost no tangible benefit (for us), so we run apache2 as a reverse proxy “the easy way”. YMMV if you want to use haproxy; but honestly, we do not use haproxy (on a number of apache2 reverse proxy setups in production) and never have any problems with apache2 as a reverse proxy.
  1. If you are not using mod_pagespeed, comment those lines out. However, if you are running mod_pagespeed, turn off mod_pagespeed per virtual host when reverse proxing to Discourse.

All the best… and hope this helps you in some small way.

6 Likes

I’m done
Thank you!
Here’s what we actually set up!

<VirtualHost *:80>
  ServerName DOMAIN-NAME
    ProxyPreserveHost on
    RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
    RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}
    ProxyPass / unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
    ProxyPassReverse  / unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
</VirtualHost>

3 Likes

Welcome!

See how easy it is?

Setting up Apache2 as a reverse proxy for Discourse is a piece-of-cake as you show with your simple port 80 config without https. Good job :slight_smile:

3 Likes

We also successfully accessed the site via https.
And I’ve set up a reverse proxy apache to redirect to https.
However, the resources seem to be accessed via http and do not appear to be properly displayed.
What can I do?

You should post your working configuration files for your virtual hosts because no one can see them, nor help you, if you not post them :slight_smile:

OBTW: I posted fully working, operational (production) conf virtual host files for the same configuration you are trying to do. If you understand and follow them, you should have no issues at all :wink:

This is how I set it up.
It looks like all the URLs generated by Discource are http.

<VirtualHost *:80>
  ServerName DOMAIN-NAME
  RewriteEngine on
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
  ServerName DOMAIN-NAME
  SSLEngine On
  SSLProtocol all -SSLv2
  SSLCertificateFile /etc/letsencrypt/live/DOMAIN-NAME/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/DOMAIN-NAME/privkey.pem
  ProxyPreserveHost on
  RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
  RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}
  ProxyPass / unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
  ProxyPassReverse  / unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
</VirtualHost>

You should define DISCOURSE_FORCE_HTTPS to true or set that setting in your system settings.

2 Likes

Hi! The discourse-setup script leads here when ports 80/443 are in use, but these instructions do not apply to new installs. How can I do a new install using my own reverse-proxy?

Try this:

./discourse-setup  --skip-connection-test --skip-rebuild

You’ll still need to edit the app.yml by hand after that, but it’ll at least fill in the stuff that it asks for.

And let me know if it helps and then someone can edit that howto accordingly.

1 Like

I had modified the script to use a variable for HTTP_PORT and HTTPS_PORT. However it’s not a clean solution because it will be lost. I think you can go ahead and mention that in the post, it will be helpful for a first install :slight_smile:

You made the changes to the app.yml? When do you think they will be lost?