Apache proxy with certificate

Geplaatst op ma 27 december 2021 in Linux

Howto configure Apache as webproxy with SSL certificate support

This howto tries to explain how to configure Apache as webproxy with SSL certificate support for a backend system.

Think of a service that's provided by a docker or podman container, such as Nextcloud, Grafana, Kibana, Drupal and the like that must be accessible via https with the certificate provided and regularly renewed by letsencrypt.

Apache as webserver proxy

In the configuration example below, apache is configured as webproxy, with the directory .well-known excluded from the proxy. This directory is therefor not forwarded by the proxy to the backend system. This is needed for the letsencrypt script certbot that is uses this directory to obtain the certificate.

/etc/apache2/vhosts.d # cat db.example.com.conf

<VirtualHost 192.168.1.2:80>

  ServerName "db.example.com"
  DocumentRoot "/srv/www/vhosts/db.example.com"

  ProxyPreserveHost On
  ProxyPassReverse  "/" "http://192.168.1.2:3000/"

  # ProxyPass exclusions
  # Exclusions must come before the general ProxyPass directives.
  # The exclusions lijken alleen niet te werken :(
  # - https://httpd.apache.org/docs/2.4/mod/mod_proxy.html
  #
  # - https://bendellar.com/apache-as-reverse-proxy-for-letsencrypt-free-https-certificates/

  # /.well-known needed for let's encrypt certificates
  # Additional directory configuration required as well.  See directory tag Directory
  # a bit further down in this configuration.
  ProxyPass         "/.well-known" "!"

  # https://stackoverflow.com/questions/70167902/how-can-i-send-proxy-protocol-with-apache-proxypass
  # ProxyPassMatch    "^/.well-known" "!"

  ProxyPass         "/" "http://192.168.1.2:3000/"

  <Directory "/srv/www/vhosts/db.example.com/.well-known">
    Require all granted

    # Default: FollowSymLinks
    Options None

  </Directory>

</VirtualHost>

The directory and ip address information is very likely to be adjusted for your setup.

Test the web proxy setup

To test the web proxy setup, put an index.html file in the /.well-known directory.

<html>
 <head>
  <title>Hello World</title>
 </head>
 <body>
  <div style="text-align: center; color: blue;">
   <p>Hello World!!</p>
   <p>Accompanying text during the James Webb Space Telescope at X-mas day 25 December 2021:</p>
   <p>From a tropical rainforest to the edge of time itself, James Webb begins a voyage back to the birth of the universe.</p>
  </div>
 </body>
</html>

Visit http://fqdn that provides the service ( provided by for example a docker or podman container ) with /.well-known added to it. This should result in the following webpage:

Hello World
index.html served by the proxy web server

When the web proxy works as expected continue with the next step.

Request the certificate

This step is going to request the certificate for the backend system. The request command is executed at the system that provides the web server proxy. In the given example the required configuration to serve https traffic is automatically added.
At Certbot instructions you can lookup te instructions for your system, or how to execute the command in such a way that configuration must be added manually.

# certbot --apache
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Zope interface certbot.interfaces.IAuthenticator is deprecated, use ABC certbot.interface.Authenticator instead.
Could not find ssl_module; not disabling session tickets.

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: db.example.com
2: nextcloud.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Requesting a certificate for db.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/db.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/db.example.com/privkey.pem
This certificate expires on 2022-03-27.
These files will be updated when the certificate renews.

Deploying certificate
Congratulations! You have successfully enabled HTTPS on https://db.example.com

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

After this the backend service is accessible via https.

A configuration file /etc/apache2/vhosts.d/db.example.com-le-ssl.conf was added and the apache configuratin file /etc/apache2/vhosts.d/db.example.com has been modified to redirect http traffic (port 80) to the https port (443).

Finishing touches: renew certificate and cleanup old certificates

To have the certificate renewed in time, add the certbot renew command to the crontab. For details look up other website that explain in detail how to do this.

As Letsencrypt renews a certificate about every 2 - 3 months, the directory /etc/letsencrypt that stores the key, csr, certificate chain and the certificate clutter the /etc/letsencrypt directory. This directory can be kept tidy with the find command shown in the crontab example.

crontab -e

Add the following lines to the crontab, to renew the certificate(s) and cleanup old certificate related files.

# Certificate renewal
19 05 * * * /usr/bin/find /etc/letsencrypt/{archive,csr,keys} -type f -mtime +100 -exec rm {} +
19 06 * * * /usr/bin/certbot renew --max-log-backups 0

See Also