Accessing a Pi-Hole behind an Apache reverse proxy

Update 2019-09-15: Finally got around to looking into this and it turns out all I had to change was “ProxyPreserveHost Off” to “ProxyPreserveHost  On” to get things working. I’ve updated the original post to reflect the changes. I also didn’t note in my original host that I purposely restricted access to the apache virtual host to 10.0.0.0/24 and 192.168.0.0/24 (my internal networks). You’ll want to update the “Allow from” lines to reflect your internal networks OR remove the “<Location /></Location>” all together to make it accessible from anywhere (not recommended).

Update 2019-08-19: I just recently found out that this proxy configuration only allows read-only access to the Pi-Hole UI. I was attempting to white-list a domain and it was failing when accessing my Pi-Hole via the proxy. I had to go directly to the box’s FQDN to white-list a domain. I will leave this post for reference and update it when I figure out a fix to this problem.

Update 2019-09-29: My first Lets Encrypt certificate came due for auto-renewal and failed because of my original configuration. I’ve updated the apache configuration below so Lets Encrypt can access the non-SSL /.well-known directory to automatically renew certificates.

Original Post

Today I got tired of accessing my Pi-Hole over HTTP, having to remember to put /admin/ in the URL and having to load up a browse that wasn’t Vivaldi or Firefox because they don’t have an easy way to ignore Strict-Transport-Security for my domain.

I checked out some documentation about adding SSL to the Pi-Hole directly but have concerns that future updates will wipe out all the custom configuration to lighttpd. According to this you also have to be careful when enabling SSL on your Pi-Hole as it could interfere with blocking.

I already have an Apache webserver running so configuring it to reverse-proxy seemed like an easier task, plus if for some reason I wanted to access my Pi-Hole from the general internet (without VPN) it would be simple to enable that.

Here is the reverse proxy configuration I used with a restriction to my two internal networks and a redirect from HTTP to HTTPS:

<VirtualHost *:80>
       ServerName pihole.mydomain.com
       DocumentRoot /var/www/html
       CustomLog logs/pihole.mydomain.com.log combined
       ErrorLog logs/pihole.mydomain.com-error.log

	<Location /.well-known>
		Order allow,deny
		Allow from all
	</Location>

	<Location />
		Order deny,allow
		Deny from all
		Allow from 127.0.0.1
		Allow from 192.168.0.0/24
		Allow from 10.0.0.0/24
	</Location>

       RewriteEngine On
       RewriteRule ^(.well-known)($|/) - [L]
       RewriteCond %{SERVER_PORT} 80
       RewriteRule ^(.*)$ https://pihole.mydomain.com/ [R,L]
</VirtualHost>

<VirtualHost *:443>
        ServerName pihole.mydomain.com
        DocumentRoot /var/www/html
        CustomLog logs/pihole.mydomain.com.log combined
        ErrorLog logs/pihole.mydomain.com-error.log

	<Location />
		Order deny,allow
		Deny from all
		Allow from 127.0.0.1
		Allow from 192.168.0.0/24
		Allow from 10.0.0.0/24
	</Location>

        RewriteEngine On
        RewriteRule ^/$ /admin [R]

        # The below line is not required so I have commented it out but left it in place
        # in case I am wrong. I no longer use Apache so I can't test. If this config doesn't
        # work uncomment the below line.
        # ProxyRequests On
        ProxyPass /  http://pihole-internal-hostname.mydomain.com/
        ProxyPassReverse / http://pihole-internal-hostname.mydomain.com/
        ProxyPreserveHost On

        SSLEngine on
        SSLHonorCipherOrder off
        Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

        SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

        SSLCertificateFile /etc/letsencrypt/live/pihole.mydomain.com/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/pihole.mydomain.com/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/pihole.mydomain.com/chain.pem
</VirtualHost>

I am aware that my SSL configuration is not the best. I’m waiting for CentOS 8 to come out before migrating off my existing CentOS 6 server.

To find the best SSL configuration for your OS and Web Server I recommend checking out Mozilla’s SSL Configuration Generator: https://ssl-config.mozilla.org/

Script to install Oyster Protocol (PRL) Hooknode

Update – 2018-02-19: There were a few bugs in the first version of this script. If you ran any version of it previous to v1.3 you’ll want to wipe your CentOS machine and re-run the script from scratch. You can check the script version number by looking at it in a text editor.

 

Saw these scripts in the official Oyster Protocol Github that would automatically build you a Oyster Protocol Hooknode if you have a clean Ubuntu 16.04 installation. I’m more of a fan of CentOS so I thought I’d try porting the script over to CentOS 7.

Disclaimer: This script will likely not result in a super secure installation of CentOS. It will however get you a working deployment of Oyster Protocol (PRL) Hooknode on a blank CentOS 7 VM (or physical system if you prefer) with the firewall still enabled. I do not recommend using this in production with out performing additional hardening yourself or altering the script to perform it for you. The script will configure the system to automatically download and install security updates.

It is generally bad practice to run random scripts from the internet so please review the script before executing it to make sure you are OK with everything it is doing.

I am going to assume you’ve built a VM in your preferred hypervisor (I’m using VMware Workstation) and you have the CentOS Minimal Installation ISO mounted to it’s CDROM so it will boot the CentOS installer. I am also going to assume you have DHCP and DNS working on your network  so the VM will automatically get a IP and be able to access the internet.

I am not going to cover setting up a static IP, public/private DNS configuration, LetsEncrypt SSL, etc. All this script will do is get you a CentOS 7 VM with a Oyster Protocol (PRL) Hooknode running on it.

I’ve built a VM with 2vCPUs, 2GB of RAM and a 40GB HD.

Installing CentOS into the VM

  1. Power on the VM
  2. Choose ‘Install CentOS 7’ and press <ENTER>
  3. Press <ENTER> to start the installation
  4. Click ‘Contiune’ on the language/keyboard selection screen
  5. Click ‘Network & Hostname’
  6. Change the hostname to whatever you’d like your VM to be called and click ‘Apply’
  7. Click the ‘Off’ button in the top right to turn on the network connection
  8. Verify you have an IP address and note it down so you can SSH in post installation, if not you have some fixing to do, if you do click ‘Done’
  9. Click ‘Date & Time’
  10. Pick your timezone
  11. Make sure ‘Network Time’ is set to ‘On’
  12. Click ‘Done’
  13. Click ‘Installation Destination’
  14. Select the VMs disk and click ‘Done’
  15. Click ‘Begin Installation’
  16. Click ‘Root password’, set a password and click ‘Done’
  17. Click ‘User creation’, fill out the boxes for your normal user account, check mark ‘Make this user administrator’ and click ‘Done’
  18. Wait for the installation to complete
  19. Click ‘Reboot’ when it’s done

SSH into your server, disable SELinux, reboot and run the install script

Note: If you didn’t write down the IP of your VM from the OS installation you can login with the root account or your non-root account and run “ip addr show” and you will see the IP of your VM under ‘ens##’ next to ‘inet’

  1. SSH into your VM using your non-root account you created during the installation
  2. Run the following command to disable SELinux and automatically reboot
    sudo su - -c "sed -i -e 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config; shutdown -r now"
  3. SSH back into your VM using your non-root account
  4. Download the installation script by running the following:
    curl https://www.pickysysadmin.ca/static/hk_install_centos7.sh > hk_install_centos7.sh
  5. Verify the the file by running the following command. The output should say “OK”
    echo "76d440b145cdc2915751b40dd98818efb0f8b0ab hk_install_centos7.sh" | sha1sum -c
  6. Inspect the script using vim or some other text editor to make sure you are OK with everything happening in the script. Running scripts randomly from the internet is usually a bad idea.
  7. Run the script and enter your password when prompted
    NOTE: This script will take a while to complete due to a large, download required as part of the installation. Be patient.

    sudo sh hk_install_centos7.sh
  8. Wait for installation to complete

Script to install WordPress and phpMyAdmin on CentOS 7

Update 2019-08-22 – I recieved a request to update this script so that PHP 7.2 is used instead of the stock PHP 5.4 that comes with CentOS 7. I also swapped out MariaDB 10.2 with the latest 10.4. The instructions are nearly identical as before but there is now one extra step with the v1.1 script. Both versions are still available below. Really I should probably take the time to learn Ansible which would be a much more graceful way of doing this. Maybe when CentOS 8 comes out.

 

Saw this request on Reddit and thought it might be a neat challenge.

Disclaimer: This script will likely not result in a super secure installation of CentOS, Apache, MariaDB or WordPress. It will however get you a working deployment of WordPress on a blank CentOS 7 VM with the firewall and SELinux still enabled. I do not recommend using this in production with out performing additional hardening yourself or altering the script to perform it for you. Also it is generally bad practice to run random scripts from the internet so please review the script before executing it to make sure you are OK with everything it is doing.

I am going to assume you’ve built a VM in your preferred hypervisor (I’m using VMware Workstation) and you have the CentOS Minimal Installation ISO mounted to it’s CDROM so it will boot the CentOS installer. I am also going to assume you have DHCP and DNS working on your network  so the VM will automatically get a IP and be able to access the internet.

I am not going to cover setting up a static IP, public/private DNS configuration, LetsEncrypt SSL, etc. All this script will do is get you a CentOS 7 VM with Apache, MariaDB, phpMyAdmin and WordPress on it.

I’ve built a VM with 2vCPUs, 2GB of RAM and a 20GB HD.

Installing CentOS into the VM

  1. Power on the VM
  2. Choose ‘Install CentOS 7’ and press <ENTER>
  3. Press <ENTER> to start the installation
  4. Click ‘Contiune’ on the language/keyboard selection screen
  5. Click ‘Network & Hostname’
  6. Change the hostname to whatever you’d like your VM to be called and click ‘Apply’
  7. Click the ‘Off’ button in the top right to turn on the network connection
  8. Verify you have an IP address and note it down so you can SSH in post installation, if not you have some fixing to do, if you do click ‘Done’
  9. Click ‘Date & Time’
  10. Pick your timezone
  11. Make sure ‘Network Time’ is set to ‘On’
  12. Click ‘Done’
  13. Click ‘Installation Destination’
  14. Select the VMs disk and click ‘Done’
  15. Click ‘Begin Installation’
  16. Click ‘Root password’, set a password and click ‘Done’
  17. Click ‘User creation’, fill out the boxes for your normal user account, check mark ‘Make this user administrator’ and click ‘Done’
  18. Wait for the installation to complete
  19. Click ‘Reboot’ when it’s done

SSH into your server and run the install script

Note: If you didn’t write down the IP of your VM from the OS installation you can login with the root account or your non-root account and run “ip addr show” and you will see the IP of your VM under ‘ens##’ next to ‘inet’

  1. SSH into your VM using your non-root account you created during the installation
  2. Download one of the two installation scripts by running the following:
    # v1.0 - Original version, installs the default PHP 5.4 that comes with CentOS and MariaDB 10.2
    curl https://www.pickysysadmin.ca/static/installWordpressScript.sh > installWordpressScript.sh
    
    # v1.1 - New as of 2019-08-22, installs PHP 7.2 and MariaDB 10.4
    curl https://www.pickysysadmin.ca/static/installWordpressScript-v1.1.sh > installWordpressScript.sh
    
  3. Verify the the installation script you downloaded by running the following command. The output should say “OK”
    # v1.0
    echo "27c25a27cbaddba4318a68f5d9d3b56de7b5493b installWordpressScript.sh" | sha1sum -c
    
    # v1.1
    echo "792e15a137ffbde0fa008d788bfbca8f21cfe753 installWordpressScript.sh" | sha1sum -c
  4. Inspect the script using vim or some other text editor to make sure you are OK with everything happening in the script. Running scripts randomly from the internet is usually a bad idea.
  5. Run the script
    sudo sh installWordpressScript.sh
  6. Enter your password when prompted and wait
  7. Near the end of the installation ‘mysql_secure_installation’ will be run which you will have to deal with interactively. There does not appear to be a way to have it run automatically
  8. When prompted for the root password just press <ENTER>
  9. (IF USING v1.1) When prompted to “Switch to unix_socket authentication” enter “n”
  10. When asked to set a root password hit <ENTER>
  11. Enter a root password of your choosing for MariaDB and note it down securely
  12. Hit <ENTER> for all of the other questions (this will automatically choose “Y” for you)
  13. Once the script finishes it will output your WordPress database password, note it down somewhere secure
  14. You should now be able to access WordPress via http://<VMs IP>/ and phpMyAdmin via http://<VMs IP>/phpmyadmin
  15. Once you’ve finished the WordPress installation run the following command to reset the SELinux permissions we altered so the installer would work and reboot the VM in case one of the updates that was installed was a kernel update:
    sudo restorecon -v /var/www/html
    sudo shutdown -r now

 

Acknowledgments

Thank you to Nick for his SELinux tips: https://techblog.jeppson.org/2016/10/install-wordpress-centos-7/

Thank you to Vivek for his PHP 7.2 on CentOS 7 guide: https://www.cyberciti.biz/faq/how-to-install-php-7-2-on-centos-7-rhel-7/

mod_rewrite rule to redirect root separate from everything else

Took me a bit to get this working and maybe someone else will find this useful.

In our case we have a on-premise service being moved to the cloud. To prevent an outage and not break any links for the first month or so after the migration a new domain has been chosen to.

Example URLs:

  • https://onprem.pickysysadmin.ca
    • This should forward to the root of the new service (https://cloudservice.pickysysadmin.ca/)
  • https://onprem.pickysysadmin.ca/a_bunch_of_stuff/more_stuff
    • This should redirect to the specified location on the old service (https://onprem.pickysysadmin.ca/)

Right now DNS looks like this:

  • onprem.pickysysadmin.ca -> 10.0.0.1
  • cloudservice.pickysysadmin.ca -> 10.0.0.2
  • apache_redirect_server.pickysysadmin.ca -> 10.0.0.3

Because onprem.pickysysadmin.ca is vendor maintained we didn’t want to goof with it to much or we’d just put the rewrite rules on it and save us having to use a third server (apache_redirect_server.pickysysadmin.ca).

Our solution was:

  1. Created a new DNS alias called onprem-old.pickysysadmin.ca and pointed it at 10.0.0.1 (onprem.pickysysadmin.ca)
  2. Alter the Apache vhost configuration on onprem.pickysysadmin.ca so it would respond to onprem-old.pickysysadmin.ca
    ServerAlias onprem-old.pickysysadmin.ca
  3. Configured the following re-write rules on apache_redirect_server.pickysysadmin.ca
    RewriteEngine On
    RewriteCond %{HTTP_HOST} onprem\.pickysysadmin\.ca [NC]
    RewriteRule ^/$ https://cloudservice.pickysysadmin.ca/ [NC,R=301,L]
    RewriteRule ^(.*)$ https://onprem-old.pickysysadmin.ca/$1 [NC,R=301,L]
    
    
    The entire vhost entry looks like this:
    
    <VirtualHost 10.0.0.3:80>
        DocumentRoot www/onprem.pickysysadmin.ca
        ServerName onprem.pickysysadmin.ca
        ErrorLog logs/onprem.pickysysadmin.ca-error_log
        CustomLog logs/onprem.pickysysadmin.ca-access_log common
    
        RewriteEngine On
        RewriteCond %{SERVER_PORT} 80
        RewriteRule ^(.*)$ https://onprem.pickysysadmin.ca$1 [R,L]
    </VirtualHost>
    
    <VirtualHost 10.0.0.3:443>
        DocumentRoot www/onprem.pickysysadmin.ca
        ServerName onprem.pickysysadmin.ca
        ErrorLog logs/onprem.pickysysadmin.ca-error_log
        CustomLog logs/onprem.pickysysadmin.ca-access_log common
    
        RewriteEngine On
        RewriteCond %{HTTP_HOST} onprem\.pickysysadmin\.ca [NC]
        RewriteRule ^/$ https://cloudservice.pickysysadmin.ca/ [NC,R=301,L]
        RewriteRule ^(.*)$ https://onprem-old.pickysysadmin.ca/$1 [NC,R=301,L]
    
        SSLEngine on
        SSLHonorCipherOrder on
        SSLProtocol all -SSLv2 -TLSv1
        SSLCipherSuite ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!EXPORT56:!ADH
        SSLCertificateFile <PATH TO CERT>
        SSLCertificateKeyFile <PATH TO CERT>
        SSLCertificateChainFile <PATH TO CERT>
    </VirtualHost>
  4. On migration day we changed onprem.pickysysadmin.ca to point to 10.0.0.3 (apache_redirect_server.pickysysadmin.ca)

Not overly complicated but it took me a while to figure out how to get the rewrite rules working properly.

VeraCrypt CLI Benchmark Script

I was setting up VeraCrypt on a Raspberry Pi 2 the other day so I could use it as a backup target for my main server and was curious how fast, hahaha just kidding, I mean how slow VeraCrypt would be.

To my disappointment VeraCrypt does not provide a method for running the benchmark built into the GUI via the CLI.

This is the nice benchmark you can run from the GUI:

veracryptBenchmark

So I took some time this weekend and wrote a simple BASH script you can use to benchmark the CLI version of VeraCrypt.

I only tested it with VeraCrupt 1.18a. Chances are if you run it with a previous version you’ll get some really fast times for the new Encryption/Hashes they added in 1.18 because the test won’t actually run.

The benchmark I wrote simply outputs how long it takes to create and encrypt a container of a specific size. It’s not quite as good as the GUI version which outputs the actual speed but it’s at least something. I think this will work on any version of Linux. I tried to use only build-in system utilities and since I wrote it on CentOS 6 means I probably used some of the oldest GNU utilities still commonly used.

During my testing I found that having a container size to small would result in all times being nearly the same with the exception of ripemd160 and streebog. To get better results I recommend using at least a 1GB test file size on modern hardware. Even at 1GB you can see the sample from my main server has each encryption and hash type only varying by 2-45 seconds.

Here is a sample of what the script outputs:

I will admit I don’t fully understand these results. I would have expected much more variety in timing between the different types of encryption under a single hash type. Especially on the Raspberry Pi 2.

The script does a simply container creation benchmark in it’s default state. However if you add <USERNAME RUNNING BENCHMARK> ALL=NOPASSWD: <PATH TO bin/veracrypt>  to your sudo file and change FILLCONTAINER=0  to FILLCONTAINER=1  it will perform file write speed benchmark.

and here is the script itself:

#!/bin/bash
# Simple Veracrypt CLI Benchmark Script
# Tested on Veracrypt: v1.18a
#
# Created by: Eric Schewe
# Created on: 2016-09-03
# Version: 1.1
# Last updated: 2016-06-05 16:38
# Source: http://www.pickysysadmin.ca/
#

#Benchmark size in bytes. Uncomment which ever size you'd like to use.
#If you want to add your own sizes make sure they are multiples of 26214400 (25MB)
#CONTAINERSIZE=104857600 #100MB
#CONTAINERSIZE=209715200 #200MB
#CONTAINERSIZE=524288000 #500MB
CONTAINERSIZE=1048576000 #1GB

#This determines if we are going to write data into the containers we create
#You must temporarily alter your sudo file for this to work by adding this line:
#<USERNAME RUNNING BENCHMARK> ALL=NOPASSWD: <PATH TO bin/veracrypt>
#Be sure to remove this line from your sudo file once your completed benchmarking
FILLCONTAINER=1
FILLFILECOUNT=`expr $CONTAINERSIZE / 26214400 - 1`

#All the hashes currently supported by VeraCrypt
HASH=(sha256 sha512 whirlpool ripemd160 streebog)
#All the encryption methods currently supported by VeraCrupt
ENCRYPTION=(AES Twofish Camellia Kuznyechik Serpent Gost89 AES-Twofish AES-Twofish-Serpent Serpent-AES Serpent-Twofish-AES Twofish-Serpent)
#Get the cpu model of the system running the benchmark
CPUINFO=`cat /proc/cpuinfo |grep -oP "model name.*?:(.*)" | uniq |sed "s/model name.*: //"`
#Hostname of system running the benchmark
HOSTNAME=`hostname`
#Start time in a good format (https://xkcd.com/1179/)
STARTTIME=`date "+%Y-%m-%d - %k:%M:%S"`
#And a Unix Timestamp to calculate elapsed time easily
STARTTIMEUNIX=`date +%s`
#Calculate the megabyte size of the container being created
CONTAINERSIZEMB=`echo "$CONTAINERSIZE / 1024 / 1024" |bc`

#For output
LONGHEADER="-------------------------------------------------------------------------------------------------"
SHORTHEADER="-------------------------------------------------------------------"

#Output the benchmark header based on the type of benchmark we are doing
if [ $FILLCONTAINER -eq 1 ];
then
  echo $LONGHEADER
else
  echo $SHORTHEADER
fi
echo "- Veracrypt Benchmark"
echo "- Started: $STARTTIME"
echo "- Hostname: $HOSTNAME"
echo "- CPU: $CPUINFO"
echo "- Container Size: $CONTAINERSIZEMB megabytes"
if [ $FILLCONTAINER -eq 1 ];
then
  echo $LONGHEADER
  printf "%-10s | %-30s | %-15s | %-15s | %-15s \n" "HASH" "ENCRYPTION" "VOL CREATE TIME " "VOL FILL TIME " "SPEED (MB/sec)"
  echo $LONGHEADER
else
  echo $SHORTHEADER
  printf "%-10s | %-30s | %-1s \n" "HASH" "ENCRYPTION" "TIME"
  echo $SHORTHEADER
fi

#Loop through each HASH
for a in "${HASH[@]}"
do

  #Loop through each ENCRYPTION method for this HASH
  for b in "${ENCRYPTION[@]}"
  do
    #Grab a random 320 character string and re-use it for all encryptions done for the current HASH
    < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-320} > randomString.txt 2>&1
    #Grab a random 64 character password (maximum length VeraCrypt supports)
    RANDOMPASSWORD=`< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-64};echo;`
    #General a container name that shouldn't conflict with anything already in the directory
    CONTANIERNAME=`echo -n $RANDOMPASSWORD | md5sum -t |head -c${1:-24}`".vc"

    #Create a VeraCrypt volume and time it, little grep to get the only time we care about from the output
    VOLUMECREATETIME=`(time veracrypt --create $CONTANIERNAME --size=$CONTAINERSIZE --password $RANDOMPASSWORD --encryption $b --hash $a --filesystem FAT --pim=2048 --random-source=randomString.txt --keyfiles= --volume-type=Normal) 2>&1 |grep -i "real" |sed "s/real//" |sed "s/ //g"`

    if [ $FILLCONTAINER -eq 1 ];
    then
      #Figure out the directory name we are going to mount the volume to and then create it
      DIRNAME=`echo -n $RANDOMPASSWORD | md5sum -t |head -c${1:-24}`
      mkdir $DIRNAME
      #Mount the container to the directory we just created
      veracrypt --mount $CONTANIERNAME --hash $a --password=$RANDOMPASSWORD $DIRNAME --pim=2048 --keyfiles= --protect-hidden=no >/dev/null 2>&1
      #Get the start time for filling up the container
      FILLSTARTTIME=`date +%s`
      #Fill the container with 25MB files
      VOLUMEFILLTIME=`(time (for (( i=1; i<=$FILLFILECOUNT; i++ )); do dd if=/dev/urandom of=$DIRNAME/$i".dat" bs=26214400 count=1 status=none conv=fdatasync; done)) 2>&1 |grep -i "real" |sed "s/real//" |sed "s/ //g"`
      #Get the end time for filling up the container
      FILLENDTIME=`date +%s`
      #Math to calculate elapsed seconds and then how many MB/sec we did
      FILLELAPSED=`echo "$FILLENDTIME - $FILLSTARTTIME" |bc`
      FILLSPEED=`echo "scale=3; $FILLFILECOUNT * 26214400 / $FILLELAPSED / 1024 / 1024" |bc -l`
      #Output the results
      printf "%-10s | %-30s | %-15s | %-8s | %-15s \n" "$a" "$b" "$VOLUMECREATETIME" "$VOLUMEFILLTIME" "$FILLSPEED"
      #Umount the container and clean up before the next container is created
      veracrypt -d $CONTANIERNAME >/dev/null 2>&1
      rm -rf $DIRNAME
    else
      printf "%-10s | %-30s | %-1s \n" "$a" "$b" "$VOLUMECREATETIME"
    fi

    #Cleanup before next volume is created
    rm -f $CONTANIERNAME
    rm -f randomString.txt

  done

  #Output a footer to signify the completion of this HASH
  if [ $FILLCONTAINER -eq 1 ];
  then
    echo $LONGHEADER
  else
    echo $SHORTHEADER
  fi
done

#UNIX timestamp when we're all done. Then do some math and conversions
ENDTIMEUNIX=`date +%s`
ELAPSEDTIME=`expr ${ENDTIMEUNIX} - ${STARTTIMEUNIX}`
ELAPSEDTIME=`date [email protected]$ELAPSEDTIME -u +%H:%M:%S`

#Output summary footer
echo "- Completed on `date "+%Y-%m-%d - %k:%M:%S"`"
echo "- Elapsed Time (HH:MM:SS): $ELAPSEDTIME"

if [ $FILLCONTAINER -eq 1 ];
then
  echo $LONGHEADER
else
  echo $SHORTHEADER
fi

I’m not super confident in the output. Some of the numbers leave me scratching my head. It’s completely possible I’ve got something totally wrong with this script. Please feel free to post comments/revisions.