User Tools

Site Tools


computing:apachesurvival

This is an old revision of the document!



  • apachesurvival
  • Jonathan Haack
  • Haack's Networking
  • netcmnd@jonathanhaack.com

apachesurvival


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 site1.com and site2.com, and this can be scaled to as many as you like and/or your host will serve properly:

sudo apt install apache2 php7.3 mariadb-server
sudo mkdir -p /var/www/site1.com/public_html
sudo mkdir -p /var/www/site2.com/public_html
sudo chown -R $USER:$USER /var/www/site1.com/public_html 
sudo chown -R $USER:$USER /var/www/site2.com/public_html
sudo chmod 755 /var/www

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

sudo nano /var/www/site1.com/public_html/index.html

Give it some simple html:

<html>
  <head>
    <title>site1</title>
  </head>
  <body>
    <h1>site1</h1>
  </body>
</html>

Same for the second website, open the file:

sudo nano /var/www/site2.com/public_html/index.html

Give it some simple html to distinguish it:

<html>
  <head>
    <title>site2</title>
  </head>
  <body>
    <h1>site2</h1>
  </body>
</html>

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/site1.com.conf
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/site2.com.conf

Open the first virtual host conf for the first website:

sudo nano /etc/apache2/sites-available/site1.com.conf

Adjust to something like this:

<VirtualHost *:80>
      ServerAdmin name@site1.com
      ServerName site1.com
      ServerAlias www.site1.com
      DocumentRoot /var/www/site1.com/public_html
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Repeat the steps above for the second virtual host site2.com.conf. 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 site1.com.conf
sudo a2ensite site2.com.conf
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:

xxx.xxx.xxx.xxx site1.com
xxx.xxx.xxx.xxx www.site1.com
xxx.xxx.xxx.xxx site2.com
xxx.xxx.xxx.xxx www.site2.com

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 site1.com and site2.com 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 https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
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/site1.com-ssl.conf
sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/site2.com-ssl.conf

Open the first TLS virtual host configuration file:

sudo nano /etc/apache2/sites-available/site1.com-ssl.conf

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

<IfModule mod_ssl.c>
      <VirtualHost _default_:443>
              ServerAdmin name@site1.com
              ServerName site1.com
              DocumentRoot /var/www/site1.com/public_html
              </Directory>
              BrowserMatch "MSIE [2-6]" \
                             nokeepalive ssl-unclean-shutdown \
                             downgrade-1.0 force-response-1.0
      </VirtualHost>
</IfModule>

Repeat the steps above for the site2.com-ssl.conf 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 site1.com virtual host (non TLS) conf file:

sudo nano /etc/apache2/sites-available/site1.com.conf

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

      Redirect permanent "/" "https://site1.com/
      

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 site1.com-ssl.conf
sudo a2ensite site2.com-ssl.conf

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 site1.com --pre-hook "systemctl stop apache2" --post-hook "systemctl start apache2"

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

sudo systemctl restart apache2

You can optionally verify them with ACME:

https://www.ssllabs.com/ssltest/analyze.html?d=site1.com&latest
https://www.ssllabs.com/ssltest/analyze.html?d=site2.com&latest

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 apache-restart.sh:

sudo touch /usr/local/bin/apache-restart.sh
sudo chmod 750 /usr/local/bin/apache-restart.sh
sudo chown $USER:$USER /usr/local/bin/apache-restart.sh
sudo nano /usr/local/bin/apache-restart.sh

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

#!/bin/bash
#functions
RESTART="/bin/systemctl restart apache2.service"
SERVICE="apache2.service"
LOGFILE="/home/username/Desktop/apache-restart.log"
if
    systemctl status apache2.service | grep dead
then
    echo "Sir, apache2 failed at $(date), so I restarted it for you." >> $LOGFILE
else
    echo "Ms., apache2 was running as of $(date)" >> $LOGFILE #or leave the else empty if you prefer
fi

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 {
      daily
      rotate 10
      delaycompress
      compress
      notifempty
      missingok
      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/apache-restart.sh >> /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 2019/07/27 00:15

computing/apachesurvival.1570243474.txt.gz · Last modified: 2019/10/05 02:44 by oemb1905