Step-by-Step Guide: Set Up a Webserver on Linode with Security Best Practices

Prerequisites #

Make sure you have completed the guide Set Up a Linode Compute Instance with Best Practices. This guide builds on that setup to configure a secure web server.

Step 1: Harden SSH #

Read: workflow.

Step 2: Install UFW #

Install:

bash
sudo apt install ufw -y

Start:

bash
sudo ufw enable

Auto start at boot:

bash
sudo systemctl enable ufw

Verify installation:

bash
sudo ufw status

Step 3: Configure UFW #

Set default rules:

Pro tip: Deny all traffic by default to create a secure baseline. Then allow only what is needed.

bash
sudo ufw default deny incoming
sudo ufw default deny outgoing

Allow services:

Always specify the protocol (tcp or udp) unless you have a reason to allow both.

bash
sudo ufw allow 80/tcp              # HTTP
sudo ufw allow 443/tcp             # HTTPS
sudo ufw limit <custom_port>/tcp   # SSH (Limit connections to prevent brute-force attacks)

Enable UFW:

bash
sudo ufw enable

Verify:

bash
sudo ufw status

Output:

  • Status: active
  • Default: deny (incoming), deny (outgoing), disabled (routed)
To Action From
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
*****/tcp LIMIT Anywhere
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
*****/tcp (v6) LIMIT Anywhere (v6)

Step 4 : Set Up Automatic OS Updates #

Install

bash
sudo apt install unattended-upgrades -y

Enable:

Security updates for both OS and installed packages are enabled by default.

bash
sudo dpkg-reconfigure unattended-upgrades

During setup, you’ll be prompted to allow automatic updates.

  • Select: Yes
  • This enables unattended upgrades, automatically creating the required configuration files and scheduling security updates.

Configure

Create backup:

bash
sudo cp /etc/apt/apt.conf.d/50unattended-upgrades /etc/apt/apt.conf.d/50unattended-upgrades.bak

Open:

bash
sudo vim /etc/apt/apt.conf.d/50unattended-upgrades

Modify:

Remove the // characters to enable a setting.

/etc/apt/apt.conf.d/50unattended-upgrades
# Include security and regular updates only
Unattended-Upgrade::Allowed-Origins {
  "${distro_id}:${distro_codename}"; 
  "${distro_id}:${distro_codename}-security";
  ...
};

# Automatic removal of unused dependencies
Unattended-Upgrade::Remove-Unused-Dependencies "true";

# Automatic reboot at 4:00 AM
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

# Send email notifications (optional) 
Unattended-Upgrade::Mail "[email protected]";

Create backup:

bash
sudo cp /etc/apt/apt.conf.d/20auto-upgrades /etc/apt/apt.conf.d/20auto-upgrades.bak

Open:

bash
sudo vim /etc/apt/apt.conf.d/20auto-upgrades

Modify:

/etc/apt/apt.conf.d/20auto-upgrades
# Check for updates every day
APT::Periodic::Update-Package-Lists "1";

# Download available updates every day
APT::Periodic::Download-Upgradeable-Packages "1";

# Install security updates every day
APT::Periodic::Unattended-Upgrade "1";

# Remove unused packages after upgrading every 7 days
APT::Periodic::AutocleanInterval "7";

Reload config:

Required after making changes.

bash
sudo systemctl restart unattended-upgrades