Last Modified: 8/12/2021
Introduction
This page describes how Alexis Huxley installed and configured his front-end Apache web server. Important points the configuration described are:
- each web service (e.g. Subversion, personal web pages, Jira) is contained in its own Apache virtual host, not simply in a different Apache <Location>; this presents fewer client-side password-caching problems for services that do not specify their realm correctly (e.g. OpenProject)
- for most web services the corresponding virtual hosts proxies to a back-end webserver that runs on a different machine
- for a few web services (e.g. Subversion) the corresponding virtual host runs on the front-end webserver itself
Basic installation
- Run:
apt -y install apache2
- Create a ‘combined2’ logging format, which we will refer to below, by running:
echo 'LogFormat "%h (%a) %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined2' > /etc/apache2/conf-available/combined2.conf a2enconf combined2 systemctl reload apache2
- Edit /etc/logrotate.d/apache2 and set:
/var/log/apache2/*.log /var/log/apache2/*/*.log { ... rotate 10000 ...
- Enable https (albeit without a proper certicate yet) by running:
a2enmod ssl headers proxy proxy_http proxy_html rewrite xml2enc systemctl restart apache2 nmap localhost
and verify that ports 80 and 443 are open.
- Create a basic template configuration file for http by editing /etc/apache2/sites-available/WEBSITENAME.conf to contain only:
<VirtualHost *:80> ServerName WEBSITENAME ServerAdmin webmaster@dont-use-this-address ServerSignature off CustomLog ${APACHE_LOG_DIR}/WEBSITENAME/WEBSITENAME-access.log combined2 ErrorLog ${APACHE_LOG_DIR}/WEBSITENAME/WEBSITENAME-error.log LogLevel warn RedirectMatch permanent /(.*) https://WEBSITENAME/$1 </VirtualHost>
- Create a basic template configuration file for https by editing /etc/apache2/sites-available/WEBSITENAME-ssl.conf to contain only:
<VirtualHost *:443> ServerName WEBSITENAME ServerAdmin webmaster@dont-use-this-address ServerSignature off CustomLog ${APACHE_LOG_DIR}/WEBSITENAME/WEBSITENAME-access.log combined2 ErrorLog ${APACHE_LOG_DIR}/WEBSITENAME/WEBSITENAME-error.log LogLevel warn SSLEngine on # Use a self-signed certificate until we have # a LetsEncrypt certificate. 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/WEBSITENAME/fullchain.pem #SSLCertificateKeyFile /etc/letsencrypt/live/WEBSITENAME/privkey.pem </VirtualHost>
- Make the current document root into a document root template by running:
mv /var/www/html /var/www/WEBSITENAME
- Remove the factory default http and https sites; we’ll make our own shortly:
a2dissite 000-default a2dissite default-ssl systemctl reload apache2
Front-end served websites: empty default vhost
Nothing should access the default vhost since all services that might be accessed are in non-default vhosts. However, I have seen that some programs (particularly on Android) get this wrong. Therefore we set up a default vhost simply in order to stop bad clients going to vhosts that are providing real services.
- Set some environment variables; special consideration needs to be made for this website as its name must be alphabetically ahead of all others:
WEBSITENAME=<name-of-website> # e.g. WEBSITENAME=aaa.pasta.freemyip.com
- Clone the template components and create the log directory by running:
cp -ar /var/www/WEBSITENAME /var/www/$WEBSITENAME sed "s/WEBSITENAME/$WEBSITENAME/g" \ < /etc/apache2/sites-available/WEBSITENAME.conf \ > /etc/apache2/sites-available/$WEBSITENAME.conf sed "s/WEBSITENAME/$WEBSITENAME/g" \ < /etc/apache2/sites-available/WEBSITENAME-ssl.conf \ > /etc/apache2/sites-available/$WEBSITENAME-ssl.conf mkdir /var/log/apache2/$WEBSITENAME chown www-data:www-data /var/log/apache2/$WEBSITENAME
- Because no client should not be specifying a ‘Host:’ HTTP header, then the default host should never be visited (except by hackers). Therefore we can simply block all accesses or use it as a honey trap, etc. I investigated using mod_security, which allows the connection to be dropped. but it log requests as if mod_security was not enabled (e.g. 403 when no DocumentRoot or Location stanzas provided), which is not what I wanted. Sending a 410 status to the client seems the most lightweight action. So add this to the config:
<Location /> Redirect 410 </Location>
- Enable the required modules and the website with:
a2ensite $WEBSITENAME a2ensite $WEBSITENAME-ssl systemctl reload apache2
- Configure HTTPS access as described at Setting up Lets Encrypt (revision 2.1).
- To test visit http://<server-ip-address>/.
Front-end served websites: Subversion
Proxied websites: Checkmk, I2P, Iplayer, WordPress, …
- Set some environment variables:
WEBSITENAME=<name-of-website> # e.g. ... WEBSITENAME=checkmk.pasta.freemyip.com WEBSITENAME=i2p.pasta.freemyip.com WEBSITENAME=radio.iplayer.pasta.freemyip.com WEBSITENAME=tv.iplayer.pasta.freemyip.com WEBSITENAME=iplayer.pasta.freemyip.com WEBSITENAME=jira.pasta.freemyip.com WEBSITENAME=judithhabgood.freemyip.com WEBSITENAME=suzanneramsay.freemyip.com WEBSITENAME=www.pasta.freemyip.com WEBSITENAME=nzb.pasta.freemyip.com WEBSITENAME=nextcloud.pasta.freemyip.com WEBSITENAME=openproject.pasta.freemyip.com WEBSITENAME=home.pasta.freemyip.com WEBSITENAME=repo.pasta.freemyip.com WEBSITENAME=jupyterhub.pasta.freemyip.com
- Clone the template components and create the log directory by running:
cp -ar /var/www/WEBSITENAME /var/www/$WEBSITENAME sed "s/WEBSITENAME/$WEBSITENAME/g" \ < /etc/apache2/sites-available/WEBSITENAME.conf \ > /etc/apache2/sites-available/$WEBSITENAME.conf sed "s/WEBSITENAME/$WEBSITENAME/g" \ < /etc/apache2/sites-available/WEBSITENAME-ssl.conf \ > /etc/apache2/sites-available/$WEBSITENAME-ssl.conf mkdir /var/log/apache2/$WEBSITENAME chown www-data:www-data /var/log/apache2/$WEBSITENAME
- Configure as follows:
- If the backend server is running CheckMK then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off ProxyPass / http://chifferi.pasta.net:5000/ ProxyPassReverse / http://chifferi.pasta.net:5000/
- If the backend server is running I2P then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /> ProxyPass http://rombi.pasta.net:7657/ ProxyPassReverse http://rombi.pasta.net:7657/ AuthType Basic AuthName "I2P Service" AuthBasicProvider file AuthUserFile /etc/apache2/i2p.htpasswd Require valid-user </Location>
and if you want to user LDAP for authentication then replace
AuthType ... valid-user
with:AuthType Basic AuthName "Subversion Service" AuthBasicProvider ldap AuthLDAPUrl ldap://ziti.pasta.net/ou=Users,dc=pasta,dc=net?uid Require valid-user
- If the backend server is running get_iplayer (radio mode) then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /> ProxyPass http://farfalle.pasta.net:1935/ ProxyPassReverse http://farfalle.pasta.net:1935/ AuthType Digest AuthName "iPlayer Service" AuthBasicProvider file AuthUserFile /etc/apache2/iplayer.htdigest Require valid-user </Location>
and if you want to user LDAP for authentication then replace
AuthType ... valid-user
with:AuthType Basic AuthName "iPlayer Service" AuthBasicProvider ldap AuthLDAPUrl ldap://ziti.pasta.net/ou=Users,dc=pasta,dc=net?uid Require valid-user
- If the backend server is running get_iplayer (TV mode) then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /> ProxyPass http://localhost:1935/ ProxyPassReverse http://localhost:1935/ AuthType Digest AuthName "iPlayer Service" AuthBasicProvider file AuthUserFile /etc/apache2/iplayer.htdigest Require valid-user </Location>
and if you want to user LDAP for authentication then replace
AuthType ... valid-user
with:AuthType Basic AuthName "iPlayer Service" AuthBasicProvider ldap AuthLDAPUrl ldap://ziti.pasta.net/ou=Users,dc=pasta,dc=net?uid Require valid-user
- If the backend server is running Jira then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off ProxyPass / http://girandole.pasta.net:8080/ ProxyPassReverse / http://girandole.pasta.net:8080/ ProxyPreserveHost On
- If the backend server is running WordPress then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off ProxyPass / https://vermicelli-judithhabgoodfreemyipcom.pasta.net/ ProxyPassReverse / https://vermicelli-judithhabgoodfreemyipcom.pasta.net/ RewriteEngine On RewriteRule ^/$ https://vermicelli-judithhabgoodfreemyipcom.pasta.net/index.php [P]
or:
SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off ProxyPass / https://vermicelli-suzanneramsayfreemyipcom.pasta.net/ ProxyPassReverse / https://vermicelli-suzanneramsayfreemyipcom.pasta.net/ RewriteEngine On RewriteRule ^/$ https://vermicelli-suzanneramsayfreemyipcom.pasta.net/index.php [P]
or:
SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off ProxyPass / https://vermicelli-wwwpastafreemyipcom.pasta.net/ ProxyPassReverse / https://vermicelli-wwwpastafreemyipcom.pasta.net/ RewriteEngine On RewriteRule ^/$ https://vermicelli-wwwpastafreemyipcom.pasta.net/index.php [P]
- If the backend server is running mailman then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine on SSLProxyCheckPeerCN off SSLProxyCheckPeerName off ProxyPass / https://marille.pasta.net/ ProxyPassReverse / https://marille.pasta.net/
- If the backend server is running Sabnzbd then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /sabnzbd/> ProxyPass http://bigoli.pasta.net:8080/sabnzbd/ ProxyPassReverse http://bigoli.pasta.net:8080/sabnzbd/ AuthType Digest AuthName "iPlayer Service" AuthBasicProvider file AuthUserFile /etc/apache2/iplayer.htdigest Require valid-user </Location>
and if you want to user LDAP for authentication then replace
AuthType ... valid-user
with:AuthType Basic AuthName "Sabnzbd Service" AuthBasicProvider ldap AuthLDAPUrl ldap://ziti.pasta.net/ou=Users,dc=pasta,dc=net?uid Require valid-user
- If the backend server is running Nextcloud then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine on SSLProxyCheckPeerCN off SSLProxyCheckPeerName off ProxyPass / https://nuvole.pasta.net/ ProxyPassReverse / https://nuvole.pasta.net/
- If the backend server is running OpenProject then add /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine on SSLProxyCheckPeerCN off ProxyPreserveHost On ProxyPass / https://paccheri.pasta.net/ ProxyPassReverse / https://paccheri.pasta.net/
(‘ProxyPreserveHost’ is needed because otherwise a complaint regarding a mismatch is displayed in OpenProject’s web interface.)
- If the backend server is hosting personal web pages then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /> ProxyPass http://tortelli.pasta.net/ ProxyPassReverse http://tortelli.pasta.net/ </Location>
- If the backend server is hosting software repositories then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
SSLProxyEngine off <Location /> ProxyPass http://tortelli.pasta.net/ ProxyPassReverse http://tortelli.pasta.net/ </Location>
- If the backend server is running JupyterHub then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
# Enable HTTP/2, if available Protocols h2 http/1.1 # HTTP Strict Transport Security (mod_headers is required) (63072000 seconds) Header always set Strict-Transport-Security "max-age=63072000" # Use RewriteEngine to handle WebSocket connection upgrades RewriteEngine On RewriteCond %{HTTP:Connection} Upgrade [NC] RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteRule /(.*) ws://pansoti.pasta.net:8000/$1 [P,L] SSLProxyEngine off <Location "/"> # preserve Host header to avoid cross-origin problems ProxyPreserveHost on # proxy to JupyterHub ProxyPass http://pansoti.pasta.net:8000/ ProxyPassReverse http://pansoti.pasta.net:8000/ RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME} </Location>
- If the backend server is running CheckMK then add to /etc/apache2/sites-available/$WEBSITENAME-ssl.conf:
- Enable the website with:
a2ensite $WEBSITENAME a2ensite $WEBSITENAME-ssl
- Repeat the above steps for all websites to be served.
- Run:
systemctl reload apache2
- If the firewall and/or DNS needs to be adjusted to direct traffic to the new front-end webserver, then adjust now.
- Configure HTTPS access for each website as described at Setting up Lets Encrypt (revision 2.1).
Enabling selective website redirection
Do not complete this section unless the section you came from instructed you do to so.
If there is not a masquerader/firewall between the web browser and the frontend webserver then use this simple method:
- Add an entry to a client’s /etc/hosts file to say that the IP address of frontend host has the name of the website, e.g.:
1.2.3.4 home.pasta.freemyip.com
If there is a masquerader/firewall between the web browser and the frontend webserver then use this more complicated method:
- Make sure that the client host (where the browser will run) has ssh access (client-side user and server-side user are both irrelevant) to the webserver.
- If public key authentication is in use then make sure that the entry in authorized_keys on the server does not specify any restrictions (e.g.
no-port-forwarding,no-X11-forwarding,no-pty
) on the beginning of the key line. - On the host running the web browser run something like:
ssh -gfND 4445 <new-web-server>
- On the new web server add an entry to /etc/hosts something like:
127.0.0.1 <new-web-server>
- In the web browser configure the proxy to be localhost:4445 and type SOCKS v5.
Fancy indexes
I believe this section is now not to be run on the front end webserver at all, so the multiple references to ‘$WEBSITENAME’ is inappropriate!!! They should be /var/www/html.
Do not complete this section unless the section you came from instructed you do to so.
- Run:
cd /var/www/$WEBSITENAME git clone https://github.com/Vestride/fancy-index rm -fr fancy-index/{.git,test} mv /etc/apache2/mods-available/autoindex.conf /etc/apache2/mods-available/autoindex.conf.orig ln -sr fancy-index/.htaccess /etc/apache2/mods-available/autoindex.conf
- Edit /var/www/$WEBSITENAME/fancy-index/script.js and change:
const parts = path.split('/'); path = parts[parts.length - 1]; titleText = titleize(path).replace(/-|_/g, ' ');
to:
const parts = path.split('/'); titleText = path; path = parts[parts.length - 1]; // titleText = titleize(path).replace(/-|_/g, ' ');
- Edit /var/www/$WEBSITENAME/fancy-index/style.css and change:
font-size: 0.875rem;
to:
/* font-size: 0.875rem; */ font-size: 1.500rem;
See also
- Computing
- Configuring Jira services
- Configuring I2P services
- Configuring mail services
- Configuring WordPress services
- Configuring get-iplayer
- Configuring Icinga services
- http://httpd.apache.org/
- https://certbot.eff.org/#ubuntuxenial-apache
- https://github.com/Vestride/fancy-index
- Alexis Huxley
-
Apache Authentication And Authorization Using LDAP on linux.com