Configuring a reverse proxy (revision 1)

Introduction

Setting environment variables

Run this on both the front-end webserver and the back-end webserver prior to running the commands below.

  1. The page that led you here should have told you to set some environment variables. Verify they are all set as follows:
    for VAR in HTTP_REDIRECTS_TO_HTTPS FRONTENDVHOST_RUNS_CERTBOT FRONTENDHOST FRONTENDVHOST FRONTENDVPROT FRONTENDVPORT BACKENDHOST BACKENDVHOST BACKENDVPROT BACKENDVPORT; do
        eval "echo \"$VAR=\$$VAR\""
    done
    
  2. THIS STEP SHOULD BE MOVED TO THE WORDPRESS PAGE: Pay particular attention to the value for BACKENDVHOST: if the backend runs a product-specific webserver (e.g. OpenProject, SabNZB) then this variable is probably the same as $BACKENDHOST. However, if the backend runs Apache then it will be a specific vhost so that that Apache process shows the correct website! My convention in these cases is to append the undotted fully-qualified website name to the hostname, e.g.:
    BACKENDVHOST=${BACKENDHOST%%.*}-${FRONTENDVHOST//./}.${BACKENDHOST#*.}

Configure DNS

This section was not applicable for XMPP (not XMPP/BOSH) with reverse proxy plus certbot because that configuration passes most traffic (XMPP) to the XMPP server, which means local XMPP clients need to interpret $FRONTENDVHOST to be the backend host. It could be that this is webserver-to-webserver specific. It was also not required for XMPP/BOSH, where there was no neccessity to send traffic through the frond-end proxy since the backend also has a valid certificate.

  1. Ensure that DNS can resolve the following hosts:
    • $FRONTENDVHOST should resolve to $FRONTENDHOST
    • $BACKENDVHOST should resolve to $BACKENDHOST (but this does not necessarily mean that the two variables have the same value! See above!)

Front-end webserver prologue

  1. Define a ‘combined2’ log format by running:
    cat > /etc/apache2/conf-available/combined2.conf <<EOF
    LogFormat "%h (%a) %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined2
    EOF
    a2enconf combined2

    (This step has probably already been done, but as the ‘combined2’ logging format is referenced in the next section it is consistent to explain how to do it here also … and it does no harm to rerun it.)

  2. To ensure that even hosts on the local network have their IPs logged instead of the frontend webserver’s run:
    FRONTENDIPADDR=$(host $HOSTNAME | egrep -o '[0-9.]{2,}')
    cat > /etc/apache2/conf-available/remoteip.conf <<EOF
    RemoteIPHeader X-Forwarded-For
    RemoteIPInternalProxy $FRONTENDIPADDR
    EOF
    a2enmod remoteip
    a2enconf remoteip
    systemctl reload apache2

    (Again this is safe to rerun.)

Configuring the front-end http webserver to redirect to the front-end https webserver

  1. Run:
    echo $HTTP_REDIRECTS_TO_HTTPS

    and if that displays false then skip the rest of this section!

  2. Create a simple vhost to redirect http to https by creating file /etc/apache2/sites-available/$FRONTENDVHOST.conf as follows:
    mkdir -p /var/log/apache2/$FRONTENDVHOST
    cat > /etc/apache2/sites-available/$FRONTENDVHOST.conf <<EOF
    <VirtualHost *:80>
        ServerName $FRONTENDVHOST
        CustomLog /var/log/apache2/$FRONTENDVHOST/$FRONTENDVHOST-access.log combined2
        ErrorLog /var/log/apache2/$FRONTENDVHOST/$FRONTENDVHOST-error.log
        RedirectMatch permanent /(.*) https://$FRONTENDVHOST/\$1
        LogLevel warn
        ServerSignature Off
    </VirtualHost>
    EOF
    a2ensite $FRONTENDVHOST
    systemctl reload apache2
  3. Test it by accessing http://$FRONTENDVHOST/ as in this example:
    damson$ wget --quiet --server-response http://$FRONTENDVHOST/ 
    HTTP/1.1 301 Moved Permanently
    Date: Tue, 24 Sep 2024 13:19:26 GMT
    Server: Apache/2.4.62 (Debian)
    Location: https://mattermost.pasta.freemyip.com/
    Content-Length: 246
    Keep-Alive: timeout=5, max=100
    Connection: Keep-Alive
    Content-Type: text/html; charset=iso-8859-1
    damson$

Configuring the front-end http(s) webserver with proxying and snake-oil certificate

  1. Create /etc/apache2/sites-available/$FRONTENDVHOST$SUFFIX.conf as follows:
    mkdir -p /var/log/apache2/$FRONTENDVHOST
    { [ $FRONTENDVPROT = https ] && SUFFIX=-ssl; } || SUFFIX=
    {
        cat <<EOF
    <VirtualHost *:$FRONTENDVPORT>
        ServerName $FRONTENDVHOST
        CustomLog /var/log/apache2/$FRONTENDVHOST/$FRONTENDVHOST-access.log combined2
        ErrorLog /var/log/apache2/$FRONTENDVHOST/$FRONTENDVHOST-error.log
        LogLevel warn
        ServerSignature Off
    EOF
        if [ $FRONTENDVPROT = https ]; then
            cat <<EOF
        SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
    
        # Keep this commented out until we have a LetsEncrypt certificate.
        #Include /etc/letsencrypt/options-ssl-apache.conf
        #SSLCertificateFile /etc/letsencrypt/live/$FRONTENDVHOST/fullchain.pem
        #SSLCertificateKeyFile /etc/letsencrypt/live/$FRONTENDVHOST/privkey.pem
    EOF
        fi
        if [ $BACKENDVPROT = https ]; then
            cat <<EOF
        SSLProxyEngine on
        SSLProxyVerify none
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLProxyCheckPeerExpire off
    EOF
        fi
        cat <<EOF
        ProxyPass        / $BACKENDVPROT://$BACKENDVHOST:$BACKENDVPORT/
        ProxyPassReverse / $BACKENDVPROT://$BACKENDVHOST:$BACKENDVPORT/
    EOF
        cat <<EOF
    </VirtualHost>
    EOF
    } > /etc/apache2/sites-available/$FRONTENDVHOST$SUFFIX.conf 
    a2ensite $FRONTENDVHOST$SUFFIX
    systemctl reload apache2
  2. Run:
    echo $FRONTENDVPROT://$FRONTENDVHOST/

    and then run the displayed command from a remote (on the internet) machine and check the output corresponds to one of the following:

    1. XMPP jabber server with proxied access to cron-based certbot, which, most of the time is not listening:
      damson# wget --no-verbose --server-response http://jabber.pasta.freemyip.com/
        HTTP/1.1 503 Service Unavailable
        Date: Wed, 09 Oct 2024 07:21:52 GMT
        Server: Apache/2.4.62 (Debian)
        Content-Length: 299
        Connection: close
        Content-Type: text/html; charset=iso-8859-1
      http://jabber.pasta.freemyip.com/:
      2024-10-09 19:21:52 ERROR 503: Service Unavailable.
      damson# 
      
    2. HTTPS front-end proxing to HTTP ot HTTPS backend with self-signed certificate:
      damson$ wget --no-verbose --server-response https://jabber.pasta.freemyip.com/
      ERROR: The certificate of ‘jabber.pasta.freemyip.com’ is not trusted.
      ERROR: The certificate of ‘jabber.pasta.freemyip.com’ doesn't have a known issuer.
      The certificate's owner does not match hostname ‘jabber.pasta.freemyip.com’
      damson$

Getting a valid certificate

  1. Run:
    echo $FRONTENDVHOST_RUNS_CERTBOT

    and if that displays false then skip the rest of this section!

  2. Run:
    certbot -d $FRONTENDVHOST
  3. Edit /etc/apache2/sites-available/$FRONTENDVHOST-ssl.conf, comment out the snakeoil stuff and uncomment the letsencrypt stuff.
  4. Run:
    systemctl reload apache2

      See also

      1. Computing