Building on the basic Ubuntu Cloud Server (with Emerging Threats Protection) we will create an all-in-one internet hosting server using the Virtualmin web hosting control panel. Latest Apache2, PHP and OpenSSL
To make sure we stay up-to-date with the latest versions of Apache Web Server, PHP and OpenSSL, we will install PPAs (personal package archive) by Ondřej Surý, who is a Debian developer and an important figure in the DNS community. He maintains many packages for Debian repository, including Apache, BIND, MariaDB, PHP etc. He is also one of the maintainers of the official certbot PPA. So I have trust in his PPAs and use them on my servers.
add-apt-repository ppa:ondrej/apache2
Latest PHP
add-apt-repository ppa:ondrej/php
Reload Package Index
apt update
Download & Install Virtualmin
cd /tmp
wget http://software.virtualmin.com/gpl/scripts/install.sh
chmod +rx /tmp/install.sh
Before running the installation script, decide if you will locally host mail for end users (including IMAP/POP clients). The minimal install will exclude the full mail processing stack (SpamAssassin and ClamAV). This will save about 1GB of system resources. If you will NOT host email, then do a minimal install
/tmp/install.sh --minimal
If you WILL host email, then do the standard full install
/tmp/install.sh
Verify the installation completed successfully. Setup Firewall
I like to locate the MySQL data under the /home directory so everything for Virtualmin is under a single path. This can be helpful if you later need to add disk space my moving /home to a separate drive. Stop the MySQL service
echo "alias /var/lib/mysql/ -> /home/mysql/," >> /etc/apparmor.d/tunables/alias
service apparmor restart
Initialize New Data Directory (don’t worry, we will add a password during the Virtualmin setup later)
mysqld --initialize-insecure
Start MySQL
service mysql start
Create SQL System Maintenance User. (This will include a new longer random password for the maintenance user)
RANDOM1=`< /dev/urandom tr -dc '[:alnum:]' | head -c${1:-64}`
cp /etc/mysql/debian.cnf /etc/mysql/debian.cnf.bak
cat > /etc/mysql/debian.cnf <<EOF
# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host = localhost
user = debian-sys-maint
password = $RANDOM1
socket = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host = localhost
user = debian-sys-maint
password = $RANDOM1
socket = /var/run/mysqld/mysqld.sock
basedir = /usr
EOF
echo "CREATE USER 'debian-sys-maint'@'localhost' IDENTIFIED BY '$RANDOM1';" | mysql -u root
echo "GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost';" | mysql -u root
echo "GRANT PROXY ON ''@'' TO 'debian-sys-maint'@'localhost' WITH GRANT OPTION;" | mysql -u root
Create Random Password for SQL root user
RANDOM1=`< /dev/urandom tr -dc '[:alnum:]' | head -c${1:-32}`
echo "ALTER USER 'root'@'localhost' IDENTIFIED BY '$RANDOM1';" | mysql -u root
echo "
MySQL root password has been set to $RANDOM1
Please record password for use later in the setup
and save in a password manager."
Apache Modifications
Enable mod_rewrite
a2enmod rewrite
service apache2 restart
Customization of HTTP request and response headers
cat > /etc/apache2/conf-available/security.conf <<EOF
ServerTokens Prod
ServerSignature Off
TraceEnable Off
Header unset ETag
FileETag None
Header set X-XSS-Protection "1; mode=block"
Header set X-Content-Type-Options nosniff
EOF
Enable the mod_headers
a2enmod headers
service apache2 restart
Instruct browsers to allow cacheable content to be fetched from the browser’s cache for up to a week
cat > /etc/apache2/mods-available/expires.conf <<EOF
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 week"
</IfModule>
EOF
Enable the mod_expires
a2enmod expires
service apache2 restart
Allow output from your server to be compressed before being sent to the browser
phpenmod bcmath bz2 curl gd igbinary imagick mbstring memcached opcache readline redis xml zip
Virtualmin Post-Installation Wizard
From a web browser, log in to the Virtualmin console at port 10000, using the root user credentials, and complete the Post-Installation Wizard. (https://myserver:10000)
Select System Settings on the left menu, then select the Re-check and refresh configuration button (this may fail if the system was not rebooted after installation of Virtualmin). Disable Unnecessary Services
If you plan to host DNS elsewhere, disable Bind DNS
systemctl mask bind9
If you plan to host email elsewhere, disable Dovecot Mail Server
systemctl mask dovecot
Disable Proftp server (I strongly encourage the use of ssh-based sftp instead of ftp/ftps)
If you are not using the Virtualmin’s mail services, then let’s lock down the Postfix SMTP server so it cannot be an attack target. We cannot disable it completely as it will be needed to send outbound email from your server. We configure it so connections are only accepted from the server itself.
The default SSL/TLS configuration for Apache lacks good security. These changes will apply Best Industry Practices and pass compliance checking for PCI, HIPAA, and NIST standards. Create New Apache SSL Config File
VirtualHost1=""
VirtualHost2=""
ServerName="ServerName"
ServerAlias="ServerAlias"
AliasFlag=0
for i in `hostname -I`
do
VirtualHost1="$VirtualHost1 $i:80"
VirtualHost2="$VirtualHost2 $i:443"
if [ $AliasFlag = 0 ] ; then
ServerName="$ServerName $i"
AliasFlag=1
else
ServerAlias="$ServerAlias $i"
AliasFlag=2
fi
done
if [ $AliasFlag = 1 ] ; then
ServerAlias=""
fi
cat > /etc/apache2/sites-available/000-default.conf << EOF
<VirtualHost $VirtualHost1>
$ServerName
$ServerAlias
DocumentRoot /var/www/html/
RedirectMatch 400 /(.*)\$
ErrorLog /var/log/apache2/default_error_log
CustomLog /var/log/apache2/default_access_log combined
</VirtualHost>
<VirtualHost $VirtualHost2>
$ServerName
$ServerAlias
DocumentRoot /var/www/html/
RedirectMatch 400 /(.*)\$
ErrorLog /var/log/apache2/default_error_log
CustomLog /var/log/apache2/default_access_log combined
SSLEngine on
SSLCertificateFile /etc/ssl/snakeoil.pem
SSLCertificateKeyFile /etc/ssl/snakeoil.key
SSLCACertificateFile /etc/ssl/snakeoil.pem
</VirtualHost>
EOF
a2ensite 000-default
service apache2 restart
Finished – Reboot
reboot
NOTE: After adding a new SSL enabled virtual server in Virtualmin, execute these commands to make sure the new server stays compliant and doesn’t override the SSL Protocol and SSL Ciphersuite that is defined by Apache SSL Config File.
sed -i '/SSLProtocol/D' /etc/apache2/sites-available/*
sed -i '/SSLCipherSuite/D' /etc/apache2/sites-available/*