4

I have the following directory structure on my Apache server

/var/www/domain.com/
    index.html
    site-1/
    site-2/
    .
    .
    .
    site-N/

Each site uses the following configuration file, where the variables "port", "site", and "hub" are the only values which change

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        # DOMAIN CONFIGURATION
        Define domain domain.dev
    ServerName ${domain}
    ServerAlias www.${domain}
    DocumentRoot /var/www/${domain}

    &lt;Directory &quot;/var/www/${domain}&quot;&gt;
        AuthType Basic
        AuthName &quot;${domain} Authentication&quot;
        AuthUserFile /etc/apache2/.htpasswd
        Require valid-user
        &lt;Files &quot;manifest.json&quot;&gt;
            Require all granted
        &lt;/Files&gt;
    &lt;/Directory&gt;

    SSLEngine on
    RewriteEngine on
    SSLProxyEngine on
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    SSLCertificateFile /etc/letsencrypt/live/${domain}/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/${domain}/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/${domain}/fullchain.pem

    &lt;FilesMatch &quot;\.(cgi|shtml|phtml|php)$&quot;&gt;
        SSLOptions +StdEnvVars
    &lt;/FilesMatch&gt;

    &lt;Directory /usr/lib/cgi-bin&gt;
        SSLOptions +StdEnvVars
    &lt;/Directory&gt;

    # SITE CONFIGURATION
    Define site site-1
    Define port 5001
    Define protocol https
    Define hub site-1-hub

    ProxyPassMatch &quot;^/${site}/api/(.+)&quot; &quot;${protocol}://localhost:${port}/api/$1&quot;
    ProxyPassReverse &quot;/&quot; &quot;${protocol}://localhost:${port}/&quot;

    ProxyPassMatch &quot;^/${site}/${hub}/(.+)&quot; &quot;${protocol}://localhost:${port}/${hub}/$1&quot;
    ProxyPassReverse &quot;/&quot; &quot;${protocol}://localhost:${port}/${hub}&quot;

    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule &quot;^/${site}/(.+)&quot; &quot;wss://localhost:${port}/$1&quot; [P]
&lt;/VirtualHost&gt;

Is there a way to share, reuse or centralize the "Domain Configuration" and "Site Configuration" sections so I don't have to duplicate configurations across multiple sites under the same domain? If so, I would be able to make a change in one shared configuration that would apply to any domain or site using it.

apache2ctl -S output

        VirtualHost configuration:
    *:80                   localhost (/etc/apache2/sites-enabled/000-default.conf:1)
    ServerRoot: "/etc/apache2"
    Main DocumentRoot: "/var/www/html"
    Main ErrorLog: "/var/log/apache2/error.log"
    Mutex ssl-stapling: using_defaults
    Mutex proxy: using_defaults
    Mutex ssl-cache: using_defaults
    Mutex default: dir="/var/run/apache2/" mechanism=default 
    Mutex watchdog-callback: using_defaults
    Mutex rewrite-map: using_defaults
    Mutex ssl-stapling-refresh: using_defaults
    PidFile: "/var/run/apache2/apache2.pid"
    Define: DUMP_VHOSTS
    Define: DUMP_RUN_CFG
    User: name="www-data" id=33
    Group: name="www-data" id=33

Here is a working implementation of the solution provided by Esa Jokinen (Note: The mod_macro module needs to be enabled by running sudo a2enmod macro at the command line)

/etc/apache2/sites-available/domain.dev.conf contents:

<Macro Domain $domain>
    ServerName $domain
    ServerAlias www.$domain
    DocumentRoot /var/www/$domain
# Basic authentication
&lt;Directory &quot;/var/www/$domain&quot;&gt;
    AuthType Basic
    AuthName &quot;$domain Authentication&quot;
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
    &lt;Files &quot;manifest.json&quot;&gt;
        Require all granted
    &lt;/Files&gt;
&lt;/Directory&gt;

RewriteEngine on

SSLEngine on
SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

SSLCertificateFile /etc/letsencrypt/live/$domain/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/$domain/fullchain.pem

&lt;FilesMatch &quot;\.(cgi|shtml|phtml|php)$&quot;&gt;
    SSLOptions +StdEnvVars
&lt;/FilesMatch&gt;

&lt;Directory /usr/lib/cgi-bin&gt;
    SSLOptions +StdEnvVars
&lt;/Directory&gt;

</Macro>

<Macro Site $site $port $protocol $hub> ProxyPassMatch "^/$site/api/(.+)" "$protocol://localhost:$port/api/$1" ProxyPassReverse "/" "$protocol://localhost:$port/"

ProxyPassMatch &quot;^/$site/$hub/(.+)&quot; &quot;$protocol://localhost:$port/$hub/$1&quot;
ProxyPassReverse &quot;/&quot; &quot;$protocol://localhost:$port/$hub&quot;

RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule &quot;^/$site/(.+)&quot; &quot;wss://localhost:$port/$1&quot; [P]

</Macro>

<IfModule mod_ssl.c> <VirtualHost *:443> Use Domain domain.dev

    Use Site site-1 5003 https site-1-hub
    Use Site site-2 5004 https site-2-hub
    .
    .
    .
    Use Site site-N 500N https site-N-hub
&lt;/VirtualHost&gt;

</IfModule>

1 Answers1

6

Apache Module mod_macro might be just what you are looking for. You can define a macro:

<Macro MyProxySites $site $port $protocol $hub>
    ProxyPassMatch "^/$site/api/(.+)" "$protocol://localhost:$port/api/$1"
    ProxyPassReverse "/" "$protocol://localhost:$port/"

    ProxyPassMatch "^/$site/$hub/(.+)" "$protocol://localhost:$port/$hub/$1"
    ProxyPassReverse "/" "$protocol://localhost:$port/$hub"

    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule "^/$site/(.+)" "wss://localhost:$port/$1" [P]
</Macro>

And then use it in your configuration several times, e.g.

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        DocumentRoot /var/www/example.com

        # . . .
        Use MyProxySites site-1 5001 https site-1-hub
        Use MyProxySites site-2 5002 https site-2-hub
    </VirtualHost>
    <VirtualHost *:443>
        ServerName example.net
        ServerAlias www.example.net
        DocumentRoot /var/www/example.net

        # . . .
        Use MyProxySites site-3 5003 https site-3-hub
        Use MyProxySites site-4 5004 https site-4-hub
    </VirtualHost>
</IfModule>

From your question it's hard to say your exact goal, but if the domain changes for every site and a domain only has a single proxy, you could build that directly into the macro, too:

<Macro MyProxySites $domain $site $port $protocol $hub>
    <VirtualHost *:443>
        ServerName $domain
        ServerAlias www.$domain
        DocumentRoot /var/www/$domain

        ProxyPassMatch "^/$site/api/(.+)" "$protocol://localhost:$port/api/$1"
        ProxyPassReverse "/" "$protocol://localhost:$port/"

        ProxyPassMatch "^/$site/$hub/(.+)" "$protocol://localhost:$port/$hub/$1"
        ProxyPassReverse "/" "$protocol://localhost:$port/$hub"

        RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
        RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
        RewriteRule "^/$site/(.+)" "wss://localhost:$port/$1" [P]
    </VirtualHost>
</Macro>

Use MyProxySites example.com site-1 5001 https site-1-hub
Use MyProxySites example.net site-2 5002 https site-2-hub
Use MyProxySites example.org site-3 5003 https site-3-hub
Esa Jokinen
  • 49,773
  • 1
    That is a good *working* solution and solves the problem. I just didn't want to keep copying the same config over and over. I was basically asking if there was a way to reuse configurations. I am so new to Apache (web servers in general) that I have trouble formulating a coherent question, that being said; do you have any thoughts on rewording my question so it is more helpful to the community? – Mark Davich Jun 10 '20 at 16:32