How to use Apache as a front end in a self-hosted installation

Colin Fletcher Public Seen by 80

I have a home server that I use to host a variety of low-traffic apps and sites, and they're all behind an Apache front end. So when I wanted to install a Loomio instance as well, I wanted to host it behind Apache too.

The supported way to do a self-hosted installation assumes that it has full use of the server, including the standard web ports, and installs a docker image of Nginx to handle the front end. It makes a ton of sense to do it this way, and I suggest it if you have the choice.

Sidebar: Actually, if you're thinking about self-hosting on something like a $5 per month vps for financial reasons, then you're probably some sort of volunteer organization, and what really makes sense is to check out the special pricing page for volunteer organization hosting.

Anyway, with a little mucking about I managed to get Loomio running behind Apache and alongside my other sites. I'm collecting some notes here in the hopes that other people will find them useful. I'm also happy to field questions and suggestions in this thread for as long as I maintain my instance this way. But please keep in mind that this way is not for beginners, and that I am not an expert.

Finally, if anyone can get reply-by-email functionality working I would be grateful for any tips, and will add them here.


Update 2021-03-16: There's a better way to do this now: check out this thread, where there is a script that you can run (or just follow): https://www.loomio.org/d/2mIUgOZf/help-installing-or-if-possible-is-there-any-automated-script-for-installing-like-the-one-gaspari-made-for-ubuntu-16-/19

The standard instructions are here: https://github.com/loomio/loomio-deploy

This github issue offers suggestions for how to get Loomio to work on a shared server. Note particularly that the letsencrypt and nginx sections in the docker-compose.yml have to be removed, since those functions will be managed by Apache.

I had no existing smtp server running, so I was able to let the mailin container listen on port 25 directly.

Creating and configuring a new VirtualHost with letsencrypt is normal. Certbot syntax, since I always forget:

sudo certbot run --apache -d loomio.example.com

Apache virtualhost config file, with annotations. This is what took me the longest time to configure. If you notice security problems or egregiously suboptimal settings, please let me know.

Required modules

sudo a2enmod filter proxy substitute headers


<VirtualHost *:80>

        Define FQDN loomio.example.com
        ServerName ${FQDN}

        # Letsencrypt modified this file simply to redirect to https
        RewriteEngine on
        RewriteCond %{SERVER_NAME} =${FQDN}
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]



<IfModule mod_ssl.c>
<VirtualHost *:443>

   Define FQDN loomio.example.com
   ServerName ${FQDN}

   SSLEngine On
   SSLCertificateFile /etc/letsencrypt/live/${FQDN}/fullchain.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/${FQDN}/privkey.pem
   Include /etc/letsencrypt/options-ssl-apache.conf

# The loomio code is running without encryption, because the apache
# front end is providing that.  So the code listening for websockets
# doesn't like that the Origin header begins with "https://".  Looking
# through the source, if FORCE_SSL is off it just wants whatever the value
# of CANONICAL_NAME is in the env file.

   RequestHeader edit Origin "https://" ""

# Tell apache where the loomio backend is running.

   ProxyRequests off
   ProxyPass        "/cable" "ws://localhost:3000/cable"
   ProxyPass        "/" "http://localhost:3000/"

   <Location />
      ProxyPassReverse /

# This is another artifact of Loomio thinking that it's running unencrypted, when
# in reality the end user sees encrypted connections.  If http PUTs are tried from
# clicking within a document served over https the browser will refuse to connect
# with a 'mixed content error' (visible in the browser console).  This problem
# was detected for me when attachments to comments would stall at 0% uploaded.
# This code changes any links it detects in the pages loomio is serving from
# http:// to https://.

      AddOutputFilterByType SUBSTITUTE text/html application/javascript text/css application/json text/plain
      Substitute "s|http://${FQDN}|https://${FQDN}|niq"

# Tell Loomio not to compress its response.  This means that we don't have
# to decompress it before performing the http -> https substitution.  I'm not
# sure how to tell apache to compress before finally sending to the client; let
# me know if you've found a way

      RequestHeader    unset  Accept-Encoding


   <Location /cable>
      ProxyPassReverse /

   LogLevel warn
   ErrorLog ${APACHE_LOG_DIR}/loomio-error.log
   CustomLog ${APACHE_LOG_DIR}/loomio-access.log combined



Colin Fletcher Mon 9 Mar 2020

Just updated to Loomio 2.1.0, and suddenly the websocket stopped connecting. Putting the "/cable" ProxyPass above the "/" ProxyPass allowed the connection through again.

If anyone can explain why that was necessary, and if so why it worked before, I would listen intently.

Regardless, I've updated the config above to reflect the change.


Colin Fletcher Mon 15 Mar

Ok, for anyone who ends up here, I'd check out this thread for the best and most up-to-date way to host Loomio behind Apache:



Rob Guthrie Mon 15 Mar

Only just saw this now. What a great piece of work! Thanks so much for taking the time to share this.


Colin Fletcher Tue 16 Mar

You're welcome! It was nice to be able to contribute something -- I love the project.