Install and use mod_macro on Gentoo Linux

By , last updated August 29, 2019

At the time of writing, there aren’t that many resources online on how to install and use mod_macro in Gentoo Linux. There are some posts about mod_macro for Ubuntu, meaning it isn’t the most known feature of Apache 2.4.

This module allows the systems administrator to define a macro, that can be used many times over to define parameters such as complete virtual hosts.

I discovered mod_macro when doing research on how to implement many SSL and non-SSL virtual hosts with the same Apache server.

mod_macro became a part of Apache from version 2.4.5.

mod_macro is blocking www-servers/apache

If you are getting this blocker, the solution is pretty simple. One does not emerge mod_macro, it has to be configured as a module when building Apache.

[ebuild  N    ~] www-apache/mod_macro-1.2.1::gentoo  17 KiB
[blocks B      ] www-apache/mod_macro ("www-apache/mod_macro" is blocking www-servers/apache-2.4.39)

Total: 1 package (1 new), Size of downloads: 17 KiB
Conflict: 1 block (1 unsatisfied)

 * Error: The above package list contains packages which cannot be
 * installed at the same time on the same system.

Build Apache with mod_macro module

The ebuild for Apache 2.4, uses an environment variable called APACHE2_MODULES to configure what modules to build with Apache.

To add modules, edit /etc/make.conf and if APACHE2_MODULES is already there, add the following line just below.

APACHE2_MODULES="${APACHE2_MODULES} macro"

If APACHE2_MODULES is not present, add this line.

APACHE2_MODULES="macro"

Build Apache

Emerge Apache with emerge.

emerge -av apache

Wait some minutes.

Enable mod_macro

-D MACRO

Open /etc/conf.d/apache2, and add -D MACRO to APACHE2_OPTS.

Reload Apache.

/etc/init.d/apache2 restart

Example use of mod_macro

This is the macros I’ve implmented with mod_macro, for SSL and non-SSL virtual hosts.

Using recommended ciphers from.

<Macro SSLHost $host $email $documentroot $userid>
<VirtualHost *:443>
    ServerName $host
    ServerAlias www.$host
    ServerAdmin $email
    DocumentRoot "$documentroot"

    CustomLog /var/log/apache2/$host-ssl_access_log combined
    ErrorLog /var/log/apache2/$host-ssl_error_log

    <IfModule log_config_module>
        TransferLog /var/log/apache2/$host-ssl_xfer_log
    </IfModule>

    SSLEngine on
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4

    # Disable TLS compression
    SSLCompression          off

    # Necessary for Perfect Forward Secrecy (PFS)
    SSLSessionTickets       off

    SSLHonorCipherOrder On
    SSLCertificateFile      /etc/letsencrypt/live/$host/cert.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/$host/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/$host/fullchain.pem

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>

    <Directory "$documentroot">
        AllowOverride All
        Require all granted
    </Directory>
    <IfModule mpm_itk_module>
        AssignUserId $userid $userid
    </IfModule>
</VirtualHost>
</Macro>

<Macro VHost $host $email $documentroot $userid>
<VirtualHost *:80>
    ServerName $host
    ServerAlias www.$host
    ServerAdmin $email
    DocumentRoot "$documentroot"

    CustomLog /var/log/apache2/$host-access_log combined
    ErrorLog /var/log/apache2/$host-error_log

    <Directory "$documentroot">
        AllowOverride All
        Require all granted
    </Directory>
    <IfModule mpm_itk_module>
        AssignUserId $userid $userid
    </IfModule>
</VirtualHost>
</Macro>

Usage.

Include "/etc/apache2/vhosts.d/sslconfig.include"

Use VHost   example.com joe@example.com "/var/www/example.com/htdocs" examplecom
Use SSLHost example.com joe@example.com "/var/www/example.com/htdocs" examplecom

Use VHost   other.example.com other@example.com "/var/www/other.example.com/htdocs" otherexamplecom
Use SSLHost other.example.com other@example.com "/var/www/other.example.com/htdocs" otherexamplecom

The macro will replicate with the parameters used, making sure the virtual hosts have identical definitions.

In my experience, there are no difference between using quotation mark or not. The only time it’s required is when using special characters or the variable have spaces, say, a folder path.

Bonus: Get and update certificates with certbot

There are multiple tools for getting and maintaining certificates, but I’m using Gentoo Linux, and certbot is one of those tools.

Emerge certbot with emerge -av certbot.

Create a script, which will call certbot for each site your are hosting:

certbot certonly -n -d example.com --webroot --webroot-path /var/www/letsencrypt  -m joe@example.com --agree-tos
certbot certonly -n -d other.example.com --webroot --webroot-path /var/www/letsencrypt  -m joe@example.com --agree-tos

Set it to run weekly with crontab.

crontab -e

Add the following to crontab.

0 0 * * 6 /root/update_certs.sh

This script will run every saturday at 00:00. If you add a post-action hook, it’s possible to automatically restart Apache if there are any changes.

Global alias for .well-known

One of the problems with Apache and SSL certificates, is that it isn’t possible to start a virtual host without an existing certificate. There are two solutions to this problem, start the vhost with a dummy certificate, or use the default site to catch all certificate requests.

To get the second option to work, a global alias must be declared before any other virtual hosts in the Apache configuration.

Add this before any virtual hosts are loaded.

Alias /.well-known/acme-challenge/ /var/www/letsencrypt/.well-known/acme-challenge/

#Bypass Auth
<Directory /var/www/letsencrypt/.well-known/acme-challenge/>
Require all granted
</Directory>

#Redirect before other rewrite rules
RewriteCond %{REQUEST_URI} /\.well\-known/acme\-challenge/
RewriteRule (.*) /.well-known/acme-challenge/$1 [L,QSA]

If the /var/www/letsencrypt/ directory does not exist, create it

mkdir -p /var/www/letsencrypt/

Next: mod_md

The next post will be about mod_md. It implemets the ACME protocal Let’s Encrypt uses in Apache itself. In theory, it will request new certificates for new hosts, and renew certificates when it’s time to renew.