Setting Up a VPS with Ubuntu 16.04 LTS from Scratch

Provisioning a virtual private server (VPS) with Ubuntu 16.04 LTS from scratch means starting with a base installation image, then building out the server environment yourself. This gives you full control over every component, from the operating system to the web server stack. This guide walks through the complete initial setup: creating user accounts, configuring SSH access, setting up a firewall, and installing the LAMP stack.

One important note before proceeding: Ubuntu 16.04 reached end of standard support in April 2021. If you are setting up a new server, Ubuntu 22.04 LTS is the current recommended choice. This guide remains useful if you are maintaining an existing Ubuntu 16.04 deployment, or if your hosting provider still offers it as an option and you need to work with what is available.

Accessing Your VPS for the First Time

After your VPS is provisioned, your hosting provider will typically give you root access through their control panel's VNC console or similar remote console feature. This is your starting point. You log in as root, set up the basics, and then lock root access down.

The first thing to do after logging in as root is change the root password to something strong and unique. Then take a moment to note your server's IP address, as you will need it for SSH configuration later. Most providers show this in their dashboard.

Creating a Non-Root User with Sudo Privileges

Working as root for everyday tasks is a security risk. A single mistake can cause serious damage. Create a regular user account and give it sudo privileges for administrative tasks.

adduser deploy
usermod -aG sudo deploy

This creates a user called deploy and adds them to the sudo group. You can use any username you prefer. The usermod command with the -aG flags appends the user to the specified group without removing them from any other groups.

To allow this user to restart specific services without needing a password (useful for automated deployment scripts), create a sudoers file for that user:

visudo /etc/sudoers.d/90-deploy

Add these lines:

deploy ALL=(ALL) PASSWD: ALL
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart apache2, /usr/bin/systemctl restart mysql

The first line requires a password for sudo commands. The second line allows passwordless restarts of Apache and MySQL, which is useful for deployment scripts without compromising general sudo access.

Configuring SSH for Secure Remote Access

SSH is how you will manage your server day-to-day. The default configuration works, but it is designed for convenience rather than security. A few changes make it significantly harder for automated attacks to succeed.

First, set up SSH key authentication for the deploy user. On your local machine, generate an SSH key pair if you do not already have one:

ssh-keygen -t ed25519 -C "[email protected]"

Copy the public key to your server:

ssh-copy-id deploy@your-server-ip

You will be asked for the deploy user's password. After this, you can log in without a password using your private key.

Now edit the SSH daemon configuration to lock down access:

sudo nano /etc/ssh/sshd_config

Make these changes:

  • PermitRootLogin no: Prevents direct root login over SSH. You can still use sudo from your regular user account.
  • PasswordAuthentication no: Disables password-based login. Only SSH keys are accepted. Make sure your key is working before enabling this.
  • AllowUsers deploy@your-desktop-ip: Restricts SSH access to the deploy user, and only from your specific IP address. Replace your-desktop-ip with your actual IP.

After saving the configuration, reload the SSH daemon:

sudo systemctl reload sshd

Test the new login in a separate terminal before closing your current session. This is critical. If the configuration has an error, you want to catch it while you still have access through the VNC console.

Warning: Never disable password authentication or root login until you have confirmed that SSH key authentication works. A misconfigured sshd_config file can lock you out of your server.

Installing the LAMP Stack on Ubuntu 16.04

The LAMP stack is a common web server configuration: Linux, Apache, MySQL, and PHP. It handles serving web pages, managing databases, and processing dynamic content. Installing it on Ubuntu 16.04 involves updating the package index and then installing each component.

Update the package lists first:

sudo apt update && sudo apt upgrade -y

Then install Apache, MySQL, and PHP along with commonly needed extensions:

sudo apt install -y apache2 mysql-server php7.0 php7.0-mysql php7.0-cli
php7.0-mbstring php7.0-xml php7.0-curl

After installation completes, Apache should be running. You can verify this:

sudo systemctl status apache2

For a complete guide to LAMP stack installation and configuration on Ubuntu 16.04, see the LAMP stack setup guide. That guide covers virtual host configuration, permissions, and Apache module management in more detail than this article.

Securing MySQL

MySQL comes with a script that helps you set up basic security for your database server. Run it:

sudo mysql_secure_installation

The script prompts you through several steps. Set a strong root password, remove anonymous users, disable remote root login, and remove the test database. These steps remove common attack vectors that are enabled by default.

For your applications, create a dedicated database and user rather than using the root account. Log into MySQL:

sudo mysql

Then run:

CREATE DATABASE webapp;
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'strong-password-here';
GRANT ALL PRIVILEGES ON webapp.* TO 'webapp_user'@'localhost';
FLUSH PRIVILEGES;

Replace webapp, webapp_user, and strong-password-here with values appropriate for your project. Using separate database users for each application limits the damage if one application is compromised.

Configuring Apache Virtual Hosts

Virtual hosts let you run multiple websites on a single server. Each domain can have its own document root, configuration, and log files. On Ubuntu 16.04, Apache sites are configured in /etc/apache2/sites-available/.

Create a configuration file for your domain:

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

Add a basic virtual host configuration:

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/yourdomain.com/public_html

    <Directory /var/www/yourdomain.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/yourdomain.com-error.log
    CustomLog ${APACHE_LOG_DIR}/yourdomain.com-access.log combined
</VirtualHost>

Enable the site and the rewrite module:

sudo a2ensite yourdomain.com.conf
sudo a2enmod rewrite
sudo a2dissite 000-default.conf
sudo systemctl restart apache2

Set up the document root with correct ownership and permissions:

sudo mkdir -p /var/www/yourdomain.com/public_html
sudo chown -R www-data:www-data /var/www/yourdomain.com
sudo chmod -R 755 /var/www

Setting Up UFW Firewall on Ubuntu 16.04

UFW (Uncomplicated Firewall) comes pre-installed on Ubuntu 16.04. It provides a straightforward interface for managing iptables rules. A firewall should be one of the first things you configure after setting up SSH access.

The basic approach is to deny all incoming connections by default, then explicitly allow only the traffic you need. Configure UFW before enabling it:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh from your-desktop-ip/32
sudo ufw allow 'Apache Full'
sudo ufw enable

The ufw allow 'Apache Full' command opens both port 80 (HTTP) and port 443 (HTTPS). It also includes rules for WebSocket support, which is useful if you later add real-time features to your sites.

Test the firewall from an external IP that is not in your allowed list. The connection should be refused. If you lock yourself out of SSH, you can access the server through the provider's console and adjust the rules.

Warning: If you enable UFW without first allowing SSH from your IP, you will lock yourself out of the server. Always add the SSH rule before enabling the firewall.

For a more detailed look at UFW configuration options and advanced rules, the UFW firewall configuration guide covers port management, application profiles, and logging.

Hardening Your Ubuntu 16.04 Server

With the LAMP stack installed and connectivity confirmed, the next step is hardening. This means reducing the server's attack surface by disabling unnecessary features and adding protective layers.

Disable Unused Apache Modules

Apache ships with several modules that are not needed for most deployments. These modules can leak information about your server configuration. Disable them:

sudo a2dismod status autoindex cgi

The mod_status, mod_info, and autoindex modules expose server information that is useful to attackers profiling your system.

Suppress Server Signature Information

By default, Apache includes version information in HTTP response headers. Edit /etc/apache2/conf-enabled/security.conf:

ServerTokens Prod
ServerSignature Off

These settings tell Apache to show only that it is Apache (not the version number) and to suppress the server signature on error pages.

Install and Configure Fail2Ban

Fail2Ban monitors log files for failed login attempts and automatically bans IP addresses that show malicious behaviour. It is particularly useful for protecting SSH. Install it:

sudo apt install fail2ban -y

The default SSH protection in Fail2Ban is reasonable, but you can tune it for production servers. Edit /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = ssh
bantime = 3600
maxretry = 3

This bans an IP for one hour after three failed login attempts. For servers exposed to the public internet, this significantly reduces the effectiveness of brute-force attacks. The Fail2Ban setup guide covers custom filters, notification settings, and integration with Cloudflare if you use it.

Enable Automatic Security Updates

Security patches need to be applied promptly, but manually checking for updates on a server is easy to forget. Enable automatic security updates:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

This installs security updates automatically without requiring manual intervention. It does not replace regular maintenance checks, but it closes the window between a security patch being released and it being applied.

Set Up a Basic Web Application Firewall

For additional protection against common web attacks, enable mod_security (an open-source WAF module for Apache) and mod_evasive (which helps mitigate simple denial-of-service attempts):

sudo apt install libapache2-mod-security2 mod-evasive
sudo a2enmod security2 evasive

After installation, configure mod_security with the OWASP Core Rule Set or a similar ruleset for meaningful protection. The default configuration blocks some attacks but is not comprehensive on its own.

Monitoring Your VPS After Setup

Once the server is running, you need ways to monitor its health. Basic monitoring includes checking disk space, memory usage, and service status.

Check disk space:

df -h

Check which directories consume the most space:

du -sh /var/www/*

Set up logrotate for Apache and MySQL logs to prevent the /var/log partition from filling up over time. Ubuntu configures this by default, but verify that it is working and adjust retention periods if your logs are large.

Set up a simple uptime check. You can use a free service like UptimeRobot to monitor whether your server responds on ports 80 and 443. This catches situations where Apache crashes and stays down until you notice.

When to Consider Upgrading to a Newer Ubuntu Version

If you are running Ubuntu 16.04, plan a migration to a supported LTS release. Ubuntu 22.04 LTS is the current recommended version for new servers. The upgrade process involves backing up your data, spinning up a new server with the newer OS, transferring configurations and data, and testing before switching DNS.

Ubuntu 16.04 continues to receive extended security maintenance (ESM) through Ubuntu Advantage, but this requires a paid subscription. For personal projects or small business servers, the cost may not be justified when a supported LTS version is available at no extra cost.

If you need to install WordPress on your new server after upgrading, the WordPress installation guide walks through the full process with LAMP.

Moving Forward with Your VPS Setup

Setting up a VPS from scratch gives you a clean, controlled environment that you understand completely. The steps in this guide create a functional web server with reasonable security defaults. From here, the next steps depend on what you are building.

If you are deploying a PHP application, configure your virtual host properly, set up Composer for dependency management, and test the application in a staging environment before pointing live traffic at it. If you are serving static content, make sure your caching headers are correct and consider a CDN for assets that benefit from edge caching.

Regular maintenance matters. Check your logs periodically, apply updates when they are released, and monitor disk space. A server that is set up well and maintained consistently is more reliable than one that is forgotten after the initial setup.

If you are working through this guide and run into a specific issue, or if you need help planning a migration from Ubuntu 16.04 to a newer release, you can get in touch with details of your setup and what you are trying to achieve.