User Tools

Site Tools


  • apachesurvival
  • Jonathan Haack
  • Haack's Networking


This tutorial is for users of Debian GNU/Linux using the LAMP stack, wanting TLS encryption, multiple self-hosted websites and will cover:

  • Establish LAMP stack and set-up TLS w/ Let's Encrypt
  • Virtual hosts for more than one website on same server
  • Permissions and Firewall

The tutorial below creates two virtual hosts, for registered domain and, and this can be scaled to as many as you like and/or your host will serve properly:

sudo apt install apache2 php mariadb-server
sudo mkdir -p /var/www/
sudo mkdir -p /var/www/
sudo chown -R $USER:$USER /var/www/ 
sudo chown -R $USER:$USER /var/www/
sudo chmod 755 /var/www

Okay, for the first website, create your index.html:

sudo nano /var/www/

Give it some simple html:


Same for the second website, open the file:

sudo nano /var/www/

Give it some simple html to distinguish it:


Now, copy the default virtual host configuration to a new .conf file for each site:

sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/

Open the first virtual host conf for the first website:

sudo nano /etc/apache2/sites-available/

Adjust to something like this:

<VirtualHost *:80>
      DocumentRoot /var/www/
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined

Repeat the steps above for the second virtual host Ok, now time to enable the virtual hosts with the a2ensite command, and disable the default site since you won't need that any longer:

sudo a2ensite
sudo a2ensite
sudo cp -r /var/www/html /root/html-bak
sudo rm -r /var/www/html
sudo a2dissite 000-default.conf

Now, if you prefer put some local dns entries in /etc/hosts

sudo nano /etc/hosts

Append something like this to the bottom:

Check your configurations up until now and then restart the service and check if it starts:

sudo apache2ctl configtest
sudo systemctl restart apache2.service

Visit and and debug. Once both properly resolve, it is time to set up TLS. If this is a public IP on a VPS, then at a minimum, set up ufw to allow http/https and provide access for you to ssh:

sudo apt install ufw
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

It is always a good idea to first create your own self-signed certificates for each virtual host:

sudo openssl req -x509 -nodes -days 7305 -newkey rsa:2048 -keyout /etc/ssl/private/site1.key -out /etc/ssl/certs/site1.crt
sudo openssl req -x509 -nodes -days 7305 -newkey rsa:2048 -keyout /etc/ssl/private/site1.key -out /etc/ssl/certs/site1.crt

Answer the questions, and pay careful attention to the email parameter because when we switch to Let's Encrypt, it will harvest that email and use it to contact you. You should now configure a diffie-hellman key for secure key exchange:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

You can simply add all of your TLS options to the default-ssl.conf, or you can create a snippet:

sudo nano /etc/apache2/conf-available/ssl-params.conf

Having thus created the snippet, here are some recommended configurations and sources that document them:

# from
# and
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains"
#Nextcloud prefers this rule with the other Header rules below it for X, disabled:
#Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
# Requires Apache >= 2.4
SSLCompression off 
SSLSessionTickets Off
SSLUseStapling on 
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"

Don't forget to enable this configuration:

sudo a2enconf ssl-params

Configure the TLS virtual hosts for each domain previously configured above. If you chose not to do the snippet approach above, then you will start here and skip the snippet portion (and merely add any configurations you need to the ssl virtual hosts directly):

sudo cp /etc/apache2/sites-available/default-ssl.conf /root/default-ssl.conf.bak
sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/
sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/

Open the first TLS virtual host configuration file:

sudo nano /etc/apache2/sites-available/

Uncomment the legacy support at the end and enter the standard configurations at the top:

<IfModule mod_ssl.c>
      <VirtualHost _default_:443>
              DocumentRoot /var/www/
              BrowserMatch "MSIE [2-6]" \
                             nokeepalive ssl-unclean-shutdown \
                             downgrade-1.0 force-response-1.0

Repeat the steps above for the virtual host. If you want to enter some modules, then do so after the “downgrade line” and before the </VirtualHost> line and start with <IfModules> and end with </IfModules>. Now, you can redirect the original sites-enabled to default to TLS (or, skip this, and let Let's Encrypt handle it - but do not do both). Open virtual host (non TLS) conf file:

sudo nano /etc/apache2/sites-available/

At the top, just under the DocumentRoot, enter something like:

Redirect permanent "/" ""

Repeat this for the site2.conf file. Now, check your configuration again and enable headers and mods:

sudo a2enmod ssl
sudo a2enmod headers
sudo a2enconf ssl-params
sudo apache2ctl configtest

You may get a trivial error if you do not have your ServerName set to localhost in the global configuration file located at /etc/apache2/apache2.conf. Once that is done, and if everything looks good, enable the TLS virtual hosts:

sudo a2ensite
sudo a2ensite

Visit both sites using Firefox, and ensure they resovle. Now, set up Let's Encrypt so that you have your TLS certificates managed by a proper authority. I have never been able to get the stock certbot instructions to work, so I found this on a certbot tech support git repo, and have used it every since

sudo apt install certbot letsencrypt python-certbot-apache
sudo certbot --authenticator standalone --installer apache -d --pre-hook "systemctl stop apache2" --post-hook "systemctl start apache2"

Run the second command again, but adjust it for Now, restart the service:

sudo systemctl restart apache2

You can optionally verify them with ACME:

Let's Encrypt expires often, so you likely want a cron job to update everything for you when/if needed:

sudo crontab -e
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log
sudo systemctl restart cron.service
sudo systemctl restart apache2

You can also manually check certificates by:

sudo certbot renew

I have some servers in production that seem to just stop apache for whatever reason, so to limit downtime after all this work, you can create a simple monitoring script called

sudo touch /usr/local/bin/
sudo chmod 750 /usr/local/bin/
sudo chown $USER:$USER /usr/local/bin/
sudo nano /usr/local/bin/

Ok, now that we created the script file and made it executable, paste in the contents below but adjust them to your needs:

RESTART="/bin/systemctl restart apache2.service"
    systemctl status apache2.service | grep dead
    echo "Sir, apache2 failed at $(date), so I restarted it for you." >> $LOGFILE
    echo "Ms., apache2 was running as of $(date)" >> $LOGFILE #or leave the else empty if you prefer

Okay, now let's make sure your log files do not get too large. First create a new entry in the logrotate daemon directory:

sudo nano /etc/logrotate.d/apache-restart

In that file that you just opened, enter some common sense limits for the log file so your computer does not fill up with logs:

/home/user/Desktop/apache-restart.log {
      rotate 10
      size 100000k

Alright, no point in making an apache monitoring script unless it runs automatically, so let's create a cron job:

sudo crontab -e
* * * * * /bin/bash /usr/local/bin/ >> /home/user/Desktop/apache-restart.log
sudo systemctl restart cron

Test it, by stopping the service, and then waiting a minute.

sudo systemctl stop apache2

Check the logfile to verify it is working:

cat /home/user/Desktop/apache-restart.log

Cool! You now have two websites that are TLS encrypted! Now, it is time to put some content on that site, so consider these tutorials:

Also, you probably want to keep this host up to date, and you may have others, so consider reading the tutorial below, which covers how to do remote upgrades easily:

I keep the scripts up to date on my repo, over here:

This tutorial is a designated “Invariant Section” of the “Technotronic” section of Haack's Wiki as described on the Start Page.

oemb1905 2020/01/01 14:56

computing/apachesurvival.txt · Last modified: 2020/03/27 07:24 by oemb1905