VPS Tutorial

This tutorial is about setting up and managing a Virtual Private Server (VPS) for hosting websites and email. It is aimed at people who are considering moving from shared web hosting to VPS or cloud hosting (or even a dedicated server) in order to improve the speed and reliability of their sites, or moving from managed to unmanaged hosting to save cost. By managing the server yourself with the aid of an open-source control panel such as Virtualmin you can save a lot of money while avoiding most of the restrictions of shared hosting.

The same instructions can be used to set up a test server that runs in a window on your own local computer (Mac, Windows or Linux) using VirtualBox or VMWare, or on a spare PC or laptop.

Managing your own VPS has some big advantages:

  • Web pages typically load faster and more reliably than on shared hosting, even under heavy load.
  • You have complete control – install any software package you want and any number of websites or email accounts.
  • Secure shell (SSH) access allows fast secure file transfers, remote backups and command-line control.
  • Full isolation from other users greatly reduces your vulnerability to being hacked, or your IP address being blacklisted.
  • Encrypted SSL (https) connections can be used with free, self-renewing certificates.
  • You can give private accounts to friends or customers.
  • You avoid expensive management fees and control panel licenses.
  • You can resolve problems quickly and access log files without waiting for a support ticket to be answered.
  • It's easier to move everything to an upgraded server or backup server if necessary.
  • You gain a lot of knowledge about how web servers work.

Some disadvantage are:

  • A VPS is typically more expensive than “free” or “shared” hosting.
  • Some technical ability is needed, and time to learn server management skills.
  • Some regular effort is needed to monitor and maintain the server to keep it secure and reliable.

Getting started

Before you can load websites onto a VPS you will need:

  • An account with a web hosting service that gives you administrative access to a VPS with sufficient resources to run your web sites. This typically involves paying a monthly fee - it's best to avoid long-term contracts until you've confirmed that the server satisfies your needs. Some guidelines for choosing a good host are below. You will be given at least one unique IP address for the server and an administrator username and password that allow you to install an operating system and reboot the server. Such accounts can usually be created in minutes but may take longer if payment has to be verified.
  • Administrative access to a domain name for each web site. This typically involves paying a small yearly fee to a domain registrar. They will give you a username and password that allow you to change the Domain Name System (DNS) settings for your domain. It can take 24 hours or more for these new settings to completely propagate around the global domain name system. In the meantime you can access your VPS directly by IP address. Be careful about buying your domain name from the same company that hosts your sites, because that makes it much harder to move to a new host if there's an account dispute or the hosting company goes bust.
  • A suitable operating system installed on the server - some guidelines for choosing one are below. Usually the hosting service will install a standard operating system for you - if not, you may have to load the OS from an "iso" file. You would normally load the "server" (not "desktop") edition of an operating system in this situation.
  • If the server is remote (no screen or keyboard access) you will need to install client programs such as PuTTY and WinSCP on Windows or Filezilla on a Mac to send commands and files to your VPS over a secure shell (SSH) connection. You can usually also enter commands from a console window at the hosting company website, which is useful if you lock yourself out of the SSH connection.
If it helps, my current VPS host is TransIP in Amsterdam and uses the KVM hypervisor, my domain registrars are Namecheap and Gandi.net, my nameservers are at Cloudflare and my operating system is Ubuntu 20.04 LTS - but you should choose your own depending on your requirements.

Choosing a hosting company

When choosing a hosting company look for reliability, good network connectivity and good support as well as cost. You're unlikely to get these from a PC under your desk. Redundant network connectivity and power supplies are very desirable, also good physical security and some sort of backup system. It’s hard to find objective reviews but www.webhostingtalk.com is a good place to start.

Here are some suggested things to check when moving to a new VPS hosting company:

  • How much RAM and disk space is offered? Life will be easier if you have at least 2 GB of RAM and 20 GB of disk space.
  • Are there any restrictions on the amount of data traffic allowed per month? If so, try to find out how much your sites typically used in the past.
  • What hypervisor do they use to run VPS instances? "Native" or "bare metal" hypervisors such as Xen or KVM are preferable to "hosted" hypervisors like OpenVZ or Virtuozzo because they allow access to kernel-level commands like "ipset" that may be needed to block denial of service or spam attacks.  They also have better isolation from other users.
  • Do they offer IPv6 connectivity? It's not essential yet but is likely to be soon.
  • Do they have a good reputation for fast and helpful support? Try searching for reports of past problems from other users.
  • Is there a trial period or monthly billing option? If possible, monitor the reliabililty and responsiveness of a new host for a few weeks using free services like uptime doctor. If page load times are more than 2 seconds or downtime is more than a few minutes a month you're unlikely to be happy with the hosting.
  • Do they offer automated off-site backups? If not, what are your backup plans? How hard is it to restore a full or partial backup?
  • Does the data centre have good environmental credentials? Hosting uses a lot of electricity.

Location typically doesn’t matter much – sites will load a little faster if the server is in a country close to your main users and payment and support may be a little easier if the server is in a timezone close to you (the administrator), but other factors such as price and reliability are often more important than location. Local legislation about privacy, libel, censorship, copyright and taxation may also be relevant. I have used hosts in the UK, continental Europe, the US and Australia without problems.

Choosing an operating system and control panel

I prefer so-called LAMP hosting (Linux, Apache, MySQL, PHP) because it’s open-source (cheap, patchable, secure) and compatible with popular content management systems. Any of these Webmin supported systems are reasonably complete and secure. Windows hosting is typically more expensive and not described here (or supported by Virtualmin) but may be necessary for sites that are scripted using Microsoft ASP. (Alternative databases and http servers such as PostgreSQLMariaDBnginx and litespeed are outside the scope of this tutorial but well worth considering in some situations.)

For configuring and managing the server, I recommend open-source Virtualmin rather than a licensed control panel such as cPanel or Plesk because it's full-featured, it's the cheapest way to set up multiple sites and you retain full control of the server - you can still edit config files by hand, whereas other control panels often override them. The rest of this tutorial assumes you are using Virtualmin.

For managing the content of individual sites, I recommend using a well-supported Content Management System (CMS) such as WordPressDrupal or Joomla. Even very basic sites need to be updated regularly and a content management system makes this much easier, as well as giving you access to themes and plugins that add useful functions such as search forms, contact forms with spam protection, image galleries, event calendars, online shops and so on. Proprietary systems or “website builders” generally have more limited features and can be very difficult to move to a new host or add new features.


If you are installing the operating system from scratch, you may be asked to select some configuration options. If in doubt, accept the default values. For example, when installing Ubuntu 20.04 LTS you be asked to choose the following:

  • Keyboard layout, language and country - choose the best ones for you, the administrator.
  • Network connection - keep the automatically assigned (DHCP) one for now, with no proxy. If you're creating a new virtual machine you will probably need to select "Bridged" mode (rather than NAT) first in the network settings for the virtual machine.
  • Archive mirror - use the default.
  • Guided storage configuration - typically you would accept the defaults, to use the entire virtual disk (which will be wiped).
  • Profile setup - pick a simple, memorable username, server name and password for now. Usernames are conventionally lowercase because that's faster to type. I strongly recommend changing your password later to something long, random and unique before the server goes live. In addition, I enable two-factor authentication or use an SSH key instead of a password on all administrator accounts, including Virtualmin or alternative control panel accounts. Do NOT use "root" as your username or give the root user a password because that's a significant reliability and security risk (Ubuntu won't allow it anyway). Once logged in as an administrator (a member of the "sudo" group) you can easily use the command "sudo -i" to change to root when necessary.
  • Install OpenSSH server - yes.
  • Featured server snaps - none needed (Virtualmin will install LAMP and other files it needs).

Initial security patches

For security reasons, the first thing you should do after starting the server for the first time is login at the console using the administrator username and password (as configured above or given to you by the hosting company) and install the latest operating system patches. On Ubuntu and other Debian-based systems you can do this with the following commands:

sudo apt update
sudo apt full-upgrade

The "sudo" part is necessary when you are logged in as an administrator rather than a superuser like "root". It will prompt you for the administrator's password the first time.

Checking timezone and locale

Check that your server has an appropriate timezone set. It is usually most convenient to set it to the zone in which the main administrator is located, since it avoids the need to translate timestamps in log files. You can check the current timezone and list possible settings with these commands:

timedatectl list-timezones

Then change the setting with a command like this:

sudo timedatectl set-timezone Europe/London

Check that your server has an appropriate locale set (used for date formats and password checks):


If it’s not set correctly, you can find and install an appropriate language pack and set the locale with the following commands (using British English as an example):

sudo apt search language-pack
sudo apt install language-pack-en
sudo update-locale LANG=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8
sudo reboot

Installing the Virtualmin control panel

To download and install Virtualmin, follow their instructions or simply run the two commands below, which will take a few minutes to complete. You might be asked to change the hostname to a "fully qualified" name - that means a subdomain of a domain you own, for example server.mydomain.com. It's a good idea (but not required) to set up the DNS records for this subdomain before running the webmin installation script - see below.

wget https://software.virtualmin.com/gpl/scripts/install.sh
sudo /bin/sh install.sh

To connect to the Virtualmin web interface and complete the installation, point your browser to port 10000, using https for a secure connection. The address to use is shown when the installation script completes. For example, if the IP address of your server is, the address to visit would be, or if you've already assigned a hostname and DNS records it would be something like https://server.mydomain.com:10000.

You will get a warning about an untrusted certificate if you're connecting to the IP address version, which you can ignore for now. Login with same administrator username and password you used above.

You will be taken through a post-installation wizard. The default answers are mainly fine but select Skip check for resolvability beside "Primary Nameserver" and Only store hashed passwords for the "Password storage mode".

Visit Virtualmin > System Settings > Features and Plugins to deselect any features you won't use. Personally I deselect the following modules to save memory usage:

  • BIND DNS domain - if you only have one VPS it's better to use a pair of free nameservers from Cloudflare.
  • Webalizer reporting and Awstats reporting - uses a lot of resources. I use Matomo or Google analytics.
  • PostgreSQL database - I only use MySQL (or MariaDB) because most scripts require that.
  • ProFTPd virtual FTP - I use secure file transfers (SCP or SFTP) via SSH instead, for security, speed and reliability.
  • DAV login - I also find this slow and insecure compared with SSH.
  • Spam filtering and Virus filtering - ineffective and hogs memory, I use Amavis instead.

If you have the ability to take a "snapshot" backup of your entire server now is a good time to make one, because this is a good place to return to if you mess things up.

Connecting to the Secure Shell

Assuming you now have a remote server running a freshly-installed Linux operating system but nothing else and you are configuring it from a local Windows PC, the best way to manage it is by connecting to the secure shell (SSH) using PuTTY for the command line and WinSCP for file transfers. This is generally much faster and more convenient than the recovery console we were using above or the Webmin file manager. Install and run PuTTY on your Windows PC and put the IP address of your VPS (which your hosting company will tell you) where it says "Host Name (or IP address)", leave the Port set to 22 and select Connection type: SSH then click the Open button.

The first time you connect to your new server you will see a warning that the server's host key is not cached. Click “Yes” to save the key and connect. Enter your admin username and password when prompted.

Regenerate host keys (if necessary)

If your operating system has been installed from a standard hosting company image, the root SSH keys may be the same as every other VPS they host, which is a significant security risk. If in doubt, you can regenerate the keys at any time with the following commands (which won't interrupt an existing SSH session):

sudo /bin/rm -v /etc/ssh/ssh_host_*
sudo dpkg-reconfigure openssh-server

Check IP addresses

You can check your IP addresses at Webmin > Networking > Network Configuration > Network Interfaces. Select the main interface (probably ens3), set the IPv4 Address and IPv6 Address to "Static configuration" and enter the main IP address and Netmask values that your hosting company has assigned to this VPS. (This ensures the server uses the correct IP address if it boots when the DHCP server is down.) Don't forget the netmask has to be wide enough to include the gateway address - probably for IPv4 and /48 for IPv6. You can also enter an IPv6 address range and netmask here if you have one - it's normal to be allocated a /64 group of IPv6 addresses. 

Then return to Network Configuration and select Routing and Gateways. Enter the gateway address(es) that your hosting company gave you here. Check these carefully - you may lock yourself out if you get these settings wrong or miss this step.

In the Hostname and DNS Client tab you should change the hostname to the fully-qualified name (Webmin shortens it to just the first part) and if you are not running BIND locally, change the DNS servers to point to the ones at your VPS host, or external ones at Cloudflare ( or Google (

Note: There is currently a bug in Webmin that leaves a spurious line saying "dhcp6: true" in file /etc/01-netcfg.yaml after you click "Apply Configuration". This line must be removed, otherwise you will lose all network connectivity when you reboot the server (if you have an IPv6 address).

Note: The Webmin install.sh script omits the package "net-tools" which is needed to correctly display the information in Network Configuration > Routing and Gateways > Active configuration. You can install it with the following command:

sudo apt install net-tools

Check hostname

Check your hostname under Webmin > Networking > Network Configuration > Hostname and DNS Client - Webmin might shorten this, you want the complete "fully qualified" name. Some hosting companies overwrite this information every time a VPS is rebooted - you may need to contact them to get it changed. Do NOT accept a generic name provided by the hosting company if you will be sending email from the server because spam filters will block it and you can't easily generate SSL certificates for it.

Your hosting provider should allow you to set the "Reverse DNS" settings (or "PTR" record) for each IP address they have assigned you. Spam filters often check that this is set correctly for outgoing mail, so it's worth configuring.

Install SSL certificates

You can install free SSL certificates from LetsEncrypt for your VPS and all the websites it hosts. Go to Virtualmin > Create Virtual Server and create a new site with the same name as the hostname of your VPS (if the installation script hasn't already created it). You will have to create DNS records (A and AAAA) that point to your VPS address if they (or equivalent wildcard records) don't already exist. The name of these DNS records will be just the subdomain part, so if your server hostname is server.mydomain.com the DNS records would be called just "server".

Check under Virtualmin > Server Configuration > Change IP Address that the IPv6 address (if any) is set because by default it won't be and LetsEncrypt validation will fail (you can change this behaviour in Virtualmin > System Settings > Virtualmin Configuration > Networking Settings).

Now go to Virtualmin > Server Configuration > Manage SSL Certificate > Let's Encrypt and click Request Certificate. Four new buttons will appear to allow you to copy this certificate to Webmin, Usermin, Postfix and Dovecot - click each of them in turn. Your server now has free certificates installed, and they will update automatically every 2 months.

Additional security

The default settings that we have installed so far provide a reasonable level of security, as long as you choose hard-to-guess unique passwords and install security patches quickly (preferably automatically). Nevertheless, your VPS will be attacked constantly by hackers and spammers so you should remove as many vulnerabilities as possible and check your log files regularly.

Use authentication keys for SSH login

Authentication keys are much more secure than passwords, and by default on Ubuntu this is the only way to log in as the root user and the only way to perform unattended backups so it's worth learning to use them.

First, generate a public/private key pair using PuTTYgen on Windows or ssh-keygen on Linux. The default options (2048 bit RSA key, no password) are fine. Copy the private key to a non-public location on the machine that the administrator or backup process will use to login by SSH, or to a USB stick.

Then copy the public key from the top window in PuTTYgen and paste it to a new file on your VPS at /root/.ssh/authorized_keys. You can use commands such as the following to create the file with necessary permissions in the admin user's home folder: 

cd ~
mkdir .ssh
chmod 0700 .ssh
cd .ssh
sudo nano authorized_keys [paste your public key on one line and save]
chmod 0600 authorized_keys

Don't disclose the private key to anyone! To use PuTTY to connect to your server, enter the address of the private id_rsa key file in the Connection > SSH > Auth configuration screen in PuTTY. If it's working you should NOT be prompted for a password when you try to connect, though you will get a warning about being an unrecognised host the first time.

Once you are sure you can login successfully without a password, you can go to Webmin > Servers > SSH server > Authentication and set "Allow authentication by password?" to "No".

Note that some administrators change the port the SSH server listens on from 22 to something higher, to reduce hacking attempts and associated log file entries. I no longer do this because it's only a temporary solution that doesn't improve security - whichever port you use will be found eventually by port scanners. I do however recommend setting up fail2ban to reduce server load.

Note that if you don't like the advertising in the "message of the day" you can remove it by editing /etc/default/motd-news and setting "ENABLED=0". I also delete /etc/update-motd.d/10-help-text.

Restrict Virtualmin logins

The Virtualmin interface is another way a hacker could get root access to your server. I strongly advise enabling two-factor authentication for any superuser or a user who is a member of the "sudo" group. You can enable this at Webmin > Webmin Configuration > Two-Factor Authentication. I find it easiest to select Google Authenticator as the provider but to actually use Authy to do the authentication (because it saves messing around with API keys and because you can recover your account if you lose your phone).

You will need to install Perl module Authen::OATH, which is easy to do in Ubuntu:

sudo apt install libauthen-oath-perl

You can enforce strong passwords in Webmin > Webmin users > Password restrictions - I recommend setting a minimum length of 10 characters at least.

You can also restrict access to certain Webmin modules depending on the user, and it's useful in any case to remove unwanted modules to de-clutter the Webmin menus. I suggest creating a group with a name like "Administrators" and adding yourself to that group. Then in Administrators > Available Webmin modules deactivate almost everything in the "Hardware" and "Cluster" groups and everything that appears in Un-used Modules in the menu bar at the left. I move the "System Time" module to the "System" menu by going to Webmin > Webmin Configuration > Reassign Modules. While you're there, visit the "Time server sync" tab in System Time and configure a time server name (I use uk.pool.ntp.org) and enable Synchronize on schedule. This is important, because if the server time drifts too far out, two-factor authentication won't work.

Disable unnecessary services

The proftpd and named services are probably not necessary and can be disabled to save memory by going to Webmin > Bootup and Shutdown and clicking Start at bootime > No > Save and then Stop Now. You can also disable the ftp ports 20 and 21 in Webmin > Networking > Firewalld. (Do NOT disable DNS port 53 for either TCP or UDP because although it might appear to work, responses to outgoing queries can be blocked if they're too large.)

Mitigate cookie hijacks

In your global PHP configuration at Webmin > Others > PHP Configuration you can set the list of PHP configuration files by clicking the settings cogwheel at the top left and changing the list to the versions you use (the defaults are wrong). For example:

/etc/php/7.4/fpm/php.ini=Configuration for php-fpm
/etc/php/7.4/cli/php.ini=Configuration for command-line scripts

These days most sites will run best in php-fpm mode, so that may be the only one of interest. To mitigate cookie hijacks add these settings to the end of that file:

session.cookie_httponly = 1
session.cookie_secure = 1

To make sites run in php-fpm mode go to Virtualmin > Server Configuration > Website Options > PHP script execution mode. To make this setting the default for new sites go to Vitualmin > System Settings > Server Templates > Default settings > PHP options. Repeat for settings for sub-servers. 

Restrict obsolete cipher suites - PCI DSS, HIPAA and NIST compliance

In your Apache global configuration (Webmin > Servers > Apache Webserver > Global Configuration > Edit Config Files > /etc/apache2/apache2.conf) restrict the use of obsolete and insecure SSL ciphers. You can get the latest values from the Mozilla SSL Configuration Generator. They can be checked with the ImmuniWeb and Qualys SSL Labs server tests and should be enough to get you an A+ rating.

SSLHonorCipherOrder on
SSLSessionTickets off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

# enable HTTP/2, if available
Protocols h2 http/1.1

# HTTP Strict Transport Security (mod_headers is required)
Header always set Strict-Transport-Security "max-age=63072000"

Similarly, at Webmin > Webmin Configuration > SSL Encryption check that all SSL protocols below TLSv1.2 are rejected and "Only strong PCI-compliant ciphers" are selected and similarly at Webmin > Usermin Configuration > SSL Encryption

Be careful about restricting email connections to Postfix (/etc/postfix/main.cf) or Dovecot (/etc/dovecot/dovecot.conf) too much because there are many old email systems out there that can't cope with newer ciphers and you could lose messages. You should nevertheless make sure that email login passwords won't be visible in plain text. For outgoing mail go to  Webmin > Servers > Postfix Mail Server > SMTP Authentication and Encryption and check Require SASL SMTP authentication? and Disallow SASL authentication over insecure connections?. For incoming mail go to Webmin > Servers > Dovecot IMAP/POP3 Server > SSL Configuration and check Disallow plaintext authentication in non-SSL mode?.

Enabling a firewall and fail2ban

A firewall is not as useful as you might think, because most services on a VPS have to be publicly accessible all the time and unnecessary services should be disabled anyway. Nevertheless, a firewall helps to protect against some types of denial of service (DoS) attack. Firewalld is set up and enabled by default by Webmin and needs no further configuration - it works for IPv6 as well as IPv4.

Fail2ban works with firewalld to automatically block the IP address of persistent offenders. It can't do much to protect against "brute force" password attacks (because botnets will simply change their IP address to bypass it) but it is nevertheless useful for reducing server load. It can be configured at Webmin > Networking > Fail2ban Intrusion Detector. The default settings tend to do more harm than good though so they need some tweaks.

Note that there's currently a bug in Webmin that prevents fail2ban starting automatically after a reboot. Enter the following command to fix that:

sudo systemctl enable fail2ban

First, I suggest going to Filter Action Jails and disabling all the postfix and dovecot jails, because in my experience users often mistype passwords in their email clients, and if they share an internet connection with other users they can end up blocking email for the whole building. The default ssh and webmin-auth jails can remain.

Next, I recommend adding a custom apache-404 filter and jail as described here and wordpress filters and jails as described in the WP Fail2Ban Redux plugin. 

Finally, fail2ban will be almost completely ineffective unless the expiry times are increased from 10 minutes to something like 20 days (which is roughly the maximum that can be achieved with a 32-bit integer). In file /etc/fail2ban/fail2ban.conf set dbpurgeage = 20d. 

In /etc/fail2ban/jail.conf I set these settings:

bantime  = 20d
findtime  = 20d
maxretry = 9

enabled = true
filter = wordpress-hard
logpath = /var/log/auth.log
port = http,https

enabled = true
filter = wordpress-soft
logpath = /var/log/auth.log
port = http,https

enabled = true
port = http,https
filter = apache-404
maxretry = 100
logpath = /var/log/virtualmin/*_access_log

Additional packages

You will sometimes need to install extra packages that are required by the specific programs you install. Often the installation program for a content management system will do a configuration check and inform you about missing packages or configuration settings that need to be changed. Some examples that I have found useful (install from the command line or from Webmin > Software Packages > Package from APT):

Needed by Virtualmin:

sudo apt install net-tools ispell ibritish opendkim
sudo apt install libauthen-libwrap-perl libauthen-oath-perl  libxml-simple-perl  
sudo apt install liblwp-protocol-https-perl libdigest-hmac-perl

Generally useful:

sudo apt install php-gd php-uploadprogress php-zip logwatch automysqlbackup rkhunter

Needed by Wordpress (e.g. for WooCommerce)

sudo apt install php-curl php-soap php-bcmath php-imagick

Also the "wp" command line utility (useful for running cron jobs) can be installed and tested using these commands:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --info

Apache modules can be enabled and disabled in Webmin > Servers > Apache Webserver > Configure Apache Modules. I suggest enabling the following modules, which are often used in ".htaccess" files to provide "friendly" URLs and control page cache timeouts. If you see the server's default Apache page instead of your website these missing modules might be the cause.

  • headers
  • expires

Don't forget to click "Apply Changes" at the top right afterwards.

Installing web sites

Web sites can be created by going to Virtualmin > Create Virtual Server and entering the domain name you will use and an administrator password. The default settings are usually OK and come from Virtualmin > System Settings > Server Templates.

You may wish to enable IPv6 for new sites, otherwise LetsEncrypt SSL certificate signing will fail if the site has AAAA DNS records - you can fix this default behaviour in Virtualmin > System Settings > Virtualmin Configuration > Networking Settings.

You can also create "Sub-servers" and "Alias" servers. Alias servers are useful if for example you have both a ".com" and a ".co.uk" domain - website visitors and mail users can use either domain and will see the same website or reach the same mailbox. Sub-servers are useful if one administrator is managing several different sites - if they all have the same owner then there's no need to log in and out to move between them. 

It's possible for many sites to share the main IP address of the server, you don't need multiple IP addresses any more (because all modern browsers support "SNI").

To forward administrative email messages to an external address go to Virtualmin > Edit Virtual Server > Configurable Settings > Contact email.

The default limits for memory, upload size and execution times for PHP are quite restrictive and you will probably want to increase them. You change change the default settings at Webmin > Others > PHP Configuration > /etc/php/7.4/fpm/php.ini > Manage > Resource Limits. I increase the "Maximum file upload size" and "Maximum HTTP POST size" to 100M and the maximum memory to 256M. Individual sites may need even higher limits, which can be set at Virtualmin > Services > PHP-FPM Configuration.

Securing Web Sites

It's very risky to transmit passwords in plain text when logging in to a web site or a mailbox - especially on a public network such as an open Wifi connection. To minimise the chances of users doing this accidentally, I enforce encrypted connections for passwords everywhere.

You can enable SSL (secure sockets layer) connections for one site on your server simply by going to Virtualmin > Edit Virtual Server > Enabled features and checking the box "SSL website enabled?". This will immediately allow encrypted connections to this site with a URL that begins "https" rather than "http".

However, the automatically-generated certificate is "self-signed" which means users will get browser warning that the connection can't be trusted (because there might be a man-in-the-middle intercepting the encrypted traffic). The solution is to install a free LetsEncrypt certificate by going to Virtualmin > Server Configuration > SSL Certificate > Let's Encrypt > Request Certificate. If you've done everything correctly your web site will now load with no warnings.

Now that all modern browsers support Server Name Indication (in particular, Internet Explorer on Windows XP is officially obsolete) it's no longer necessary to have a separate IP address for each site that uses an SSL certificate. 

You can make sites even more secure (and improve your search engine ranking) by redirecting insecure connections to the secure version automatically. In Virtualmin > Server Configuration > Website Options select "Yes" for Redirect all requests to SSL site? To make this the default for new sites, set it in Virtualmin > System Settings > Virtualmin Configuration > SSL Settings.

Configuring DNS settings

You will need to change the Domain Name System (DNS) settings for each new site that is added to your VPS. Each DNS change can take 24 hours or more to propagate around the worldwide DNS network. If you're impatient you can access the site in "preview" mode at Virtualmin > Services > Preview Website or you can access the site directly by IP address (by entering an address like in your web browser) or you can modify the "hosts" file on your computer (on Windows this is usually located at C:\Windows\System32\drivers\etc\hosts, on a Mac it's at /etc/hosts and you need to be an administrator in both cases).

I recommend using Cloudflare for your DNS settings rather than the nameservers provided by your domain registrar or a nameserver set up on your own VPS, for two reaons:

  1. You are supposed to have at least two nameservers (in different locations) for redundancy and Cloudflare provides this, plus quick resolution;
  2. You can quickly switch on Cloudflare's worldwide content delivery network of proxy servers if you get hit with DDoS (distributed denial of service) attack or a big spike in visitors.

You start by creating a Cloudflare account and clicking the blue "+ Add a Site" button. Enter your domain name (without the www) and wait a few seconds for Cloudflare to copy any existing DNS records from the old nameservers. Then select a plan (the free one is usually enough) and follow the instructions at your domain registrar to change your nameservers ("NS" records) to point to Cloudflare. For example, at Namecheap you would go to Domain List > Manage > Advanced DNS > Personal DNS Server and enter the two values copied from Cloudflare > [select domain] > DNS > Cloudflare Nameservers.

For a site at www.mydomain.com hosted at IPv4 address and IPv6 address 2001:db8::1 on a server called server.hostdomain.com the essential records you would need to set up in Cloudflare > DNS (each with TTL = "Auto" and Proxy status = "DNS only") would look this these:

Type Name Contents
A mydomain.com
A www
A *
AAAA mydomain.com 2001:db8::1
AAAA www 2001:db8::1
AAAA * 2001:db8::1
MX mydomain.com server.hostdomain.com
TXT mydomain.com v=spf1 ip4: ip6:2001:db8::1 ~all
TXT 2020._domainkey v=DKIM1; k=rsa; t=s; p=[value pasted from Server Configuration > Domainkey Options > DKIM DNS records without the line breaks or quotes]

Third party services (like Google Webmasters) sometimes ask you to validate your domain by adding additional CNAME or TXT records - if so, just add them the same way following their instructions.

  • Even if you don't plan to use email for your domain, you are recommended to enable at least the "webmaster@", "postmaster@", "hostmaster@" and "abuse@" incoming addresses for every domain so you can be notified about problems that might cause your site to fail. 
  • Note that you should normally have only one MX record and it should normally point to the mail server by hostname rather than by IP address.
  • See this FAQ about common mistakes that can delay or prevent delivery when setting up Sender Policy Framework (SPF) records.
  • To set up Domain-based Message Authentication, Reporting, and Conformance (DMARC) you need to be able to process the reports somehow and a free account from Postmark is an easy way to do that with a weekly summary. It's also an easy way to generate the DNS record you need. This will be a TXT record with a name like _dmarc.server1 and containing a string like this:

v=DMARC1; p=none; pct=100; rua=mailto:[special key]@dmarc.postmarkapp.com; sp=none; aspf=r;

Once DNS settings have propagated, files in the public_html folder will automatically be displayed to the world. By default, the file for the home page should be named index.html or index.php. A MySQL database is created for each site by default and can be managed at Virtualmin > Edit Databases. You can also install the useful database management tool phpMyAdmin on one of your sites from Virtualmin > Install Scripts.

Adding PHP Versions

PHP versions have a support life of only two years, whereas Ubuntu "Long Term Support" releases are supported for ten years. This isn't necessarily a problem because Canonical backports PHP security patches from later PHP versions to keep the older version working for the lifetime of the Ubuntu LTS release. Nevertheless it's good to keep up with the latest PHP versions because they are often faster and contain new features that modern applications may require.

Virtualmin supports running multiple PHP versions, but make sure you have a backup of the entire server before trying this, because I've found it's easy to mess up the PHP installation and bring all your sites down.

You have to enable an external repository (not managed by Ubuntu) by executing these commands:

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo add-apt-repository ppa:ondrej/apache2
sudo apt update
sudo apt full-upgrade

You can then install packages for specific versions, for example:

sudo apt install php7.4-fpm
a2enconf php7.4-fpm
systemctl restart apache2

Check that your sites are still working. Then go to Virtualmin > System Settings > Re-Check Configuration to make Virtualmin recognise the new available PHP versions. You can now select the version used by each site at Virtualmin > Server Configuration > PHP Versions.

It's also possible to select different PHP "execution modes" for each site at Virtualmin > Server Configuration > Website Options - I recommend FPM because it's significantly faster and uses less memory. I've found that the default settings set by Virtualmin sometimes result in excessive memory usage, which can be avoided by adding the following settings to Virtualmin > Services > PHP-FPM Configuration, which limit the lifetime of processes if a site has a memory leak:

pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10s
pm.max_requests = 200

To make the above settings the default for new servers, add them to Virtualmin > System Settings > Server Templates > PHP options > Additional FPM pool options.

Configuring email

Email users can be added at Virtualmin > Edit Users > Add a user to this server. Make sure your users have strong passwords to prevent accounts being hacked. A password policy can be set at Webmin > System > Users and Groups > Password restrictions.

By default, all mail will be stored on your VPS. I generally encourage users to set up free Gmail accounts and forward their mail there, to take advantage of the better spam filtering, searchable archive and easy access from mobiles. Mail forwarding is useful for other reasons as well and can be set up under Virtualmin > Edit User > Mail forwarding settings. It's also possible to set up filters in Usermin (using Procmail) but Procmail forwarding has multiple problems (including discarding messages without warning and looping) and should be avoided.

Make sure you have SPF, DKIM and DMARC records set in your DNS settings as described above, otherwise outgoing mail is very likely to be blocked by spam filters. 

Alternatively, users can configure their Gmail accounts to use POP3 to retrieve mail that is temporarily stored on your VPS. This is sometimes more reliable than forwarding, but the disadvantage is the polling interval can cause incoming mail to be delayed by up to an hour, which is sometimes very annoying. Using POP3 to retrieve mail to a personal PC is even worse - you can easily lose your entire mail archive (because pst files are hard to back up) and you can't access it from a phone. 

If you do store email on the VPS, users can access it at the Usermin address (e.g. https://server.mydomain.com:20000) or you can install a more sophisticated application such as Roundcube or Squirrelmail, which are easily installed with "one click" from Virtualmin > Install Scripts.

Setting up SPF and DKIM

To set up Sender Policy Framework (SPF) to help delivery of outgoing email, all you need to do is add an appropriate TXT record to the DNS settings of each of your hosted domains, as shown in the example above. See this FAQ about common mistakes.

To set up DomainKeys Identified Mail (DKIM), first visit Virtualmin > Email Settings > DomainKeys Identified Mail, choose a simple "selector" (anything you like, typically the current year or the word "default") and accept the other default options. You can list all the domains you want to sign on that page, but to save time it's easier to create a file /etc/dkim-keytable containing this content (change [your selector] to the one you chose above:

default    %:[your selector]:/etc/dkim.key

Then create a file /etc/dkim-signingtable containing this single line:

*    default

Then add these two lines at the bottom of /etc/opendkim.conf:

SigningTable refile:/etc/dkim-signingtable
KeyTable /etc/dkim-keytable

While you're there, I suggest changing the "Canonicalization" setting to relaxed, otherwise mail forwarded by Microsoft servers (in particular) is likely to be altered in transit and rejected.

Canonicalization relaxed/relaxed 

Setting up Sender Rewriting Scheme

If you use forwarding to send mail to a final destination in Virtualmin > Edit Users > Mail forwarding settings you will need to enable Sender Rewriting Scheme (SRS) otherwise SPF tests will fail. 

sudo apt install postsrsd

Add these settings to Webmin > Servers > Postfix Mail Server > Edit Config Files > main.cf:

# PostSRSd settings.
sender_canonical_maps = tcp:localhost:10001
sender_canonical_classes = envelope_sender
recipient_canonical_maps = tcp:localhost:10002
recipient_canonical_classes= envelope_recipient,header_recipient

The above commands will enable SRS for all messages - it's better to restrict this to messages that originate from outside the server, which can be done by modifying setting SRS_EXCLUDE_DOMAINS in file /etc/default/postsrsd to include all the domains hosted on the server. A list of these can easily be obtained using the following command:

virtualmin list-domains --name-only

If everything is set up correctly, you should be able to send a test mail from an address hosted on your server to a Gmail account or Outlook Mail from Webmin > Webmin Configuration > Sending Mail. In Gmail or Thunderbird, you can click the test message when it arrives, then click the message menu (three dots) at the top right then "Show original" and you should see SPF, DKIM and DMARC all showing "PASS". Then send an email from an address that is NOT hosted on your server but is forwarded via your server to a Gmail account. You should see SPF still pass and the "Return-path" or "Envelope from" header showing an encoded address.

The default size limit for emails is 10 MB which is a bit small these days. You can increase it (to say 100 MB) at Webmin > Servers > Postfix Mail Server > General Resource Control.

Autoconfiguration of email clients

Email clients like Microsoft Outlook, Apple Mail, Gmail and Thunderbird will do their best to detect the correct email settings to use, given only your email address and password.

(Note that there is a configuration page in Virtualmin > Email Settings that was supposed to help with this, but it's now ineffective and obsolete.)

The username you use to log in to your mail account should be the same as your email address (this is now the default format in Virtualmin). The mail clients will try to connect to server names like "mail.mydomain.com" for incoming and outgoing mail, so you have to make sure this subdomain resolves correctly in your DNS settings. Postfix now supports "SNI" in versions 3.4 and later (Ubuntu 19.10 and later), which allows this process to work.

Note that the official port for encrypted outgoing mail connections is port 587, but for historic reasons many mail clients still use port 465. The configuration that enables that is in file /etc/postfix/master.cf and appears as "-o smtpd_tls_wrappermode=yes". It is normally enabled, but if it's not working check that it's not commented out, and also check that Webmin > Networking > FirewallD is not blocking service "smtps".

Spam filtering

Virtualmin sets up Clamav virus scanning and Spamassassin spam filtering on incoming email by default. Unfortunately this setup is quite ineffective (doesn't work with forwarded messages, appalling detection rates) and uses lots of memory. One solution is to set up Postscreen and Amavis as described below to catch email spam before it causes server load and before messages are forwarded.

I no longer perform automatic virus scanning on emails because sadly almost all the free or low-cost Linux virus scanners are now useless or withdrawn. Mail clients often incorporate their own virus scanners in any case.


The Postfix postscreen daemon is a useful first step in spam protection - it rejects misbehaving mail clients early, which provides additional protection against mail server overload. It's disabled by default but easily enabled by adding the following lines to Webmin > Servers > Postfix Mail Server > Edit Config Files > main.cf:

# Enable postscreen, see https://www.postfix.org/POSTSCREEN_README.html
postscreen_access_list = permit_mynetworks
postscreen_dnsbl_threshold = 1
postscreen_dnsbl_sites = zen.spamhaus.org bl.spamcop.net b.barracudacentral.org
postscreen_dnsbl_action = enforce
postscreen_greet_action = enforce

# Get rid of "postscreen_cache: unable to get exclusive lock" errors
postscreen_cache_map = memcache:/etc/postfix/postscreen_cache
postscreen_cache_cleanup_interval = 0

Note that I have included tests from some reputable DNS blacklists - these can make a big difference to server load. Barracuda requires you to register your IP addresses (IPv4 only). Note also that I have enabled memcached to avoid a problem with "unable to get exclusive lock" errors in the mail log. Memcache is also useful for caching plugins like W3 Total Cache in WordPress. You can install it with a simple APT command:

sudo apt install memcached php-memcache

(Warning: Centos does not currently secure memcache properly by default but Ubuntu is OK). You will need to create a simple file called /etc/postfix/postscreen_cache containing these contents:

memcache = inet:
key_format = postscreen:%s

Then make these modifications to /etc/postfix/master.cf (same Webmin screen):

# Enable postscreen, see https://www.postfix.org/POSTSCREEN_README.html
# 2. Comment out the "smtp inet ... smtpd" service
# 3. Uncomment the new "smtpd pass ... smtpd" service and duplicate any "-o parameter=value" entries from the smtpd service that was commented out in the previous step
# 4. Uncomment the new "smtp inet ... postscreen" service
# 5. Uncomment the new "tlsproxy unix ... tlsproxy" service
# 6. Uncomment the new "dnsblog unix ... dnsblog" service
#smtp inet n - y - - smtpd -o smtpd_sasl_auth_enable=yes
smtp      inet  n       -       y       -       1       postscreen
smtpd     pass  -       -       y       -       -       smtpd -o smtpd_sasl_auth_enable=yes
dnsblog   unix  -       -       y       -       0       dnsblog
tlsproxy  unix  -       -       y       -       0       tlsproxy

Finally restart postfix, send a few test messages in and out and check the mail log at Webmin > System > System Logs or using this command:

tail -f /var/log/mail.log


Amavis spam filtering is easy to install from standard Ubuntu packages (there is no Webmin module for this):

sudo apt-get install amavisd-new pyzor razor opendkim

It must be enabled by uncommenting these lines in file /etc/amavis/conf.d/15-content_filter_mode

@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

By default, quarantined messages are saved in /var/lib/amavis/virusmails. I prefer to save them in a mailbox where they can be viewed more easily to check that wanted emails aren't being blocked, and then automatically deleted after 30 days. To set this up, go to Webmin > System > Users and Groups > amavis and click the Login to Usermin button. In Mail > Manage Folders click Add A Folder Of Type "Local Mail File" and give it a name such as "Quarantine". Use the Auto-Clearing button to enable automatic deletion.

In file /etc/amavis/conf.d/50-user add the following lines.

$sa_tag_level_deflt         = -999;  # always add spam info headers
$QUARANTINEDIR = '/var/lib/amavis/Maildir/.Quarantine/new'; 
$quarantine_subdir_levels = 0; # disable quarantine dir hashing
$spam_quarantine_method = 'local:spam-%b-%i-%n'; # Don't gzip files

# Prevents {RelayedOpenRelay} warning
@local_domains_maps = 1;

Note that there are currently some bugs in the Webmin "SpamAssassin Mail Filter" module in this situation - the "Spam Classification" options are ineffective and the "Apply Changes" button doesn't work. 

In file /etc/postfix/main.cf add this:

# https://help.ubuntu.com/community/PostfixAmavisNew
content_filter = smtp-amavis:[]:10024

At the end of file /etc/postfix/master.cf add this:

# https://help.ubuntu.com/community/PostfixAmavisNew

smtp-amavis unix    -   -   -   -   2   smtp
    -o smtp_data_done_timeout=1200
    -o smtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20 inet  n    -    -    -    -    smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_milters=
    -o smtpd_restriction_classes=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=reject_unauth_pipelining
    -o smtpd_end_of_data_restrictions=
    -o mynetworks=
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks

Also add the following two lines immediately below the "pickup" transport service:

-o content_filter=
-o receive_override_options=no_header_body_checks

Restart amavis and postfix and check the configuration using these commands:

systemctl restart amavis
systemctl restart postfix

Installing Razor, Pyzor and DCC

The additional spam filtering solutions Razor, Pyzor and DCC (Distributed Checksum Clearinghouse) can together make a big difference to spam filtering. They can be enabled or disabled in file /etc/spamassassin/v310.pre. 

loadplugin Mail::SpamAssassin::Plugin::DCC
loadplugin Mail::SpamAssassin::Plugin::Pyzor
loadplugin Mail::SpamAssassin::Plugin::Razor2

To install Razor:

sudo apt install razor
razor-admin -create
razor-admin -register

To install and test Pyzor:

sudo apt install pyzor
pyzor ping

To install and test DCC:

wget https://www.dcc-servers.net/dcc/source/dcc.tar.Z
tar xfvz dcc.tar.Z
cd dcc-2.3.167
CFLAGS="-O2 -fstack-protector" DCC_CFLAGS="-O2 -fstack-protector" ./configure && make && make install
cdcc info

This text from GTUBE can be pasted into a mail message and sent to one of the accounts on your VPS to test that spam filtering works.


Testing and monitoring

By default, email reports of any system problems will be sent to user "root". You can read them by going to Webmin > System > Users and Groups > root and clicking the "Read Email" button. It's usually more convenient to forward them to an external email address. You can configure this by going to Webmin > Servers > Postfix Mail Server > Mail Aliases, selecting Create a new alias and setting Address to "root" and your email address in "Alias to", "Email address".

You should check log files regularly at Webmin > System > System Logs for the whole system and at Virtualmin > Logs and Reports for individual sites for signs of problems or malicious activity.

There are a number of very useful free services that can be used to monitor your sites:

  • Logwatch - Analyses logs and sends a daily digest to the administrator. Needs installation.
  • Dnssy - checks all your DNS settings
  • F8lure - pings your server once a second to check for network problems or CPU overload, alerts when down
  • Mxtoolbox - alerts when blacklisted, can also "port scan" your firewall and other useful DNS queries
  • Uptime Doctor - checks how fast your pages load once a minute, alerts when down
  • Loadimpact - simulates many simultaneous users
  • Matomo (formerly Piwik) - Similar to Google Analytics but hosted on your own server, shows how your visitors behave
  • SSL Labs server test - Checks SSL installation
  • Postmark - Free application that receives and parses DMARC reports and emails you the results weekly

I suggest enabling these scheduled update and validation checks:

  • Webmin > System > Software Package Updates > Scheduled checking options
  • System Information > Virtualmin Packages > Scheduled checking options
  • Virtualmin > Limits and Validation > Scheduled Validation
  • Webmin > System > Scheduled Cron Jobs - create a job that runs regular virus scans (such as rkhunter or Sophos)
  • Webmin > Others > System and Server Status – Enable Scheduled Monitoring of Postfix, SSH, Webmin, Dovecot, Apache, MySQL, Webmin, Free Memory, Load Average and Disk space

If you want to test your setup at home before paying for commercial hosting, you can easily do so using a virtual machine. VirtualBox is free and easy to use and runs on Windows, MacOS, Linux and Solaris. Create a virtual machine with at least 1 GB of RAM and 20 GB of disk space and set the network mode to “bridged”. Then download the operating system you plan to use as an "iso" file, mount it as a virtual CD, reboot the virtual server and follow the installation prompts.

Installing WordPress

By popular demand, here are some instructions for what is often the final step - installing a Content Management System (WordPress) under Virtualmin.

First, create a virtual server (Virtualmin > Create Virtual Server) for the domain name that your WordPress website will use (let's call it mydomain.com). Specify a long unique administrator password and make sure the option "Setup SSL website too?" is checked under Enabled Features.

If your DNS records are already set up and have had time to propagate, you should be able to browse to www.mydomain.com. You should see the message "Forbidden. You don't have permission to access / on this server." because there are no files there yet.

Next go to Virtualmin > Server Configuration > SSL Certificate > Let's Encrypt and click the "Request Certificate" button. That will replace the self-signed certificate with a proper domain certificate, which avoids browser warnings.

Now open a file manager - I use WinSCP but you can also use Webmin > Others > File Manager. Browse to the folder /home/[your domain]/public_html. It's probably empty. Download the latest version of WordPress from the download page to your PC and then upload it to the public_html folder (File > Upload to current directory) and unzip it (right click > Extract). A folder called "WordPress" should have been created. Open this folder, select all the contents (there's a "Select All" button at the top) and cut and paste them up one level to the public_html folder.

Check the ownership of these files. If you are logged in as a server administrator, they may be owned by root:root instead of something like mydomain:mydomain. If so, go up one level, right-click on public_html, select Properties > Change Ownership and enter the existing values for the public_html folder but with the "Recursive" box checked.

Now if you browse to your site you should see a "Welcome to WordPress" message and some instructions. Click "Let's Go!". The next screen asks for the database name, which you will find in Virtualmin > Edit Databases, and the username and password, which you will find in the Passwords tab by clicking the little key symbol. Click "Submit". If all is well, you can now fill in the site name, admin username and password to complete the installation and log in as an administrator.

To make connections to the site secure, you can go to Settings > General and change WordPress Address (URL) and Site Address (URL) from http:// to https://. 

Tweaking performance and memory usage

I strongly suggest testing your site with a (free) service such as Loadimpact to ensure it can withstand a sudden spike in traffic. If you find problems, here are some parameters to check:

  • Can reduce the number of server processes in the Processes and Limits screen to save RAM
  • In Webmin > Webmin Configuration > Advanced Options you can change the CPU priority for scheduled jobs
  • Enable Postfix Postscreen to reduce spam and server load without damaging performance or risking false positives


Your websites could vanish without warning, even at a large reputable host. It has happened to me more than once. Common causes are denial of service attacks, your site being hacked, the host going out of business, power or network failure, an expired credit card or simple human error. Your hosting provider may be swamped with calls and unresponsive when this happens. If you have a recent off-site backup and control of your domain names you can recover everything within a couple of hours - if not, recovery may be lengthy or impossible. Backups are important!

  • Backup fast-changing MySQL database contents at least daily using an automated script such as AutoMySQLBackup or a control panel backup.
  • Virtualmin can do scheduled backups of all files, database contents, email and settings, locally or remotely. Set it up at Virtualmin > Backup and Restore > Scheduled Backup. Webmin settings can also be saved, see Webmin > Backup Configuration Files > Scheduled backups.
  • A Network Attached Storage (NAS) appliance at your home or office is often the cheapest off-site storage for your webserver, if you have a broadband internet connection. I use a Synology Diskstation. You can also store files on a Windows PC but filename differences can be a problem (zip files are usually OK) and power consumption will be much higher. Restoring from a home connection can be slow due to limited upload bandwidth.
  • Commercial services such as Amazon Glacier or Google Nearline have monthly fees.
  • Your VPS host may offer snapshot backups and you should use those, but remember they are likely to vanish if your hosting provider does.
  • make use of spare space on a cloud service such as OneDrive, Google Drive or Dropbox using the rclone utility or duplicacy.
  • Use rsync and a simple four-line script to make time-machine style backups to a linux box.
  • Keep control of your domain names by using external nameservers (e.g. at Cloudflare) rather than at your hosting provider.

A final word about security

My no. 1 tip for keeping a VPS secure is to keep it constantly updated with security patches (including all WordPress plugins, libraries and so on). Most hacks happen through known vulnerabilities that are easily exploited.

My no. 2 tip is to set up daily off-site backups, including database contents. Human error (accidentally deleting files) is an even bigger threat than hackers and in any case it's impossible to make a VPS 100% secure or reliable so you need to be able to recover quickly. Individual WordPress sites (even on shared hosting) can easily be backed up to a free Google Drive account using UpdraftPlus.

My no. 3 tip is to enforce long unique passwords and limit login attempts on every account that can upload files or modify the server. A typical 8 character "random" password can in some circumstances be cracked in less than 30 seconds but a 10 character password takes months.

My no. 4 tip is to keep an eye on log files using a utility like logcheck or logwatch and set up monitors at Webmin > Others > System and Server Status so you're warned quickly if anything is wrong.


RootSudo - Ubuntu community help

Locale - Ubuntu community help

Virtualmin installation instructions

Postfix Postscreen - How to enable and configure it to prevent spam

Setting Up DKIM And SRS In Postfix

Preventing backscatter (non-delivery records) from forwarded spam

More VPS tutorials

Guide to starting a hosting business

Firstsiteguide Web Hosting Services Explained

The Perfect Server tutorials from HowtoForge, using ISPConfig as a control panel

Mozilla SSL Configuration Generator 

Sender Policy Framework FAQ - Common mistakes

How big is your haystack? - Passwords need to be at least 10 characters


dear sir

dear sir
thank you very match for your effort it was so helpful for me , i hope in the future i will be able to help peaple as you helped me .
thanks again , and god bless you

Hi Mason, thanks for your

Hi Mason, thanks for your comment.

LAMP is installed automatically when you install virtualmin (when you run install.sh), so you don't need to do anything special there.

I'm planning to add a new article about using CMS systems (WordPress, Drupal, Joomla) in the future. I agree more details about that are needed, it's a good suggestion - a few plugins have to be installed to make them useful and secure, and there are lots of choices that people could use help with.

There is an RSS feed for notification of new posts (www.mckerracher.net/rss.xml) but if you want email notifications you would have to register, and I disabled registration because it was all spam. I'll see what I can do now that spam protection has improved.

Hi, great post!!!

Hi, great post!!!

can you please add some details around how to install wordpress and LAMP using virtualmin...

Also it would be nice to have notify/alert on new posts to site :)

Great web page. Just what I

Great web page. Just what I needed. Lots to learn for sure. Thanks. John