
August 19, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Shipping a web application without a structured Ubuntu Security Hardening Guide is the most common cause of preventable breaches I see in Nepal’s hosting market. Default Ubuntu 24.04 LTS installations are functional but expose unnecessary attack surfaces through open ports, root login, and permissive file permissions. This guide provides the exact hardening sequence I use for production Laravel and WordPress systems, transforming a fresh VPS into a defensible platform before deploying a single line of application code.
How Do You Configure SSH and UFW for Ubuntu Security Hardening?
SSH and firewall configuration form the perimeter of any secure website and server infrastructure in Nepal. On a fresh Ubuntu 24.04 LTS install, password authentication and root login are often enabled by default, and no firewall rules exist. These defaults must be corrected immediately after initial access.
Hardening SSH Access
Password-based SSH authentication is vulnerable to brute-force attacks regardless of password complexity. Key-based authentication eliminates this vector entirely. Generate an ED25519 key pair on your local machine (not the server) using ssh-keygen -t ed25519 -C "admin@yourdomain.com", then copy the public key to the server with ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip. Verify key-based login works in a new terminal session before modifying the SSH daemon configuration.
Edit /etc/ssh/sshd_config to enforce hardened settings:
<!-- /etc/ssh/sshd_config -->
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers deploy admin
Protocol 2
X11Forwarding no
AllowTcpForwarding no The AllowUsers directive restricts SSH access to named accounts only. Even if an attacker compromises another system account, they cannot authenticate via SSH unless explicitly listed. After editing, validate syntax with sshd -t and reload with systemctl reload sshd. Never restart sshd without testing first — a syntax error locks you out permanently.
Configuring UFW Firewall Rules
UFW (Uncomplicated Firewall) wraps nftables on Ubuntu 24.04. Enable it only after defining allow rules, or you will block your own SSH access:
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
ufw enable For servers running non-standard SSH ports, replace port 22 with your chosen port. Avoid opening database ports (3306, 5432, 6379) to the public internet. Database connections should originate from localhost or a private VPC subnet. If remote database access is required for maintenance, use SSH tunneling instead of exposing the port directly.
What Kernel and Service Settings Are Essential in an Ubuntu Security Hardening Guide?
Network-level hardening extends beyond the firewall into kernel parameters. Default Linux TCP/IP stack settings prioritize compatibility over security, leaving servers vulnerable to SYN floods, IP spoofing, and man-in-the-middle attacks. Apply these sysctl settings in /etc/sysctl.d/99-hardening.conf:
# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
# Enable SYN cookies against SYN flood attacks
net.ipv4.tcp_syncookies = 1
# Disable IPv6 if unused
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1 Apply changes with sysctl --system. The rp_filter setting enables reverse path filtering, which drops packets claiming to originate from addresses that would not route back through the receiving interface — a primary defense against IP spoofing. SYN cookies allow the server to handle connection requests without allocating memory until the three-way handshake completes, mitigating resource exhaustion during SYN flood attacks.
Disabling Unnecessary Services
Every running service is a potential attack surface. Audit active services with systemctl list-units --type=service --state=running. Common candidates for removal on a dedicated web server include:
- cups — Print service, never needed on a headless server
- avahi-daemon — mDNS/Bonjour discovery, exposes hostname on local networks
- rpcbind — NFS/RPC service, frequent target for amplification attacks
- bluetooth — No legitimate use case on production web infrastructure
Disable and mask each unnecessary service: systemctl disable --now cups && systemctl mask cups. Masking prevents accidental re-enablement by package upgrades or dependency resolution.
How Does fail2ban Strengthen Your Ubuntu Security Hardening Guide?
Even with key-only SSH and UFW enabled, attackers probe exposed services continuously. fail2ban monitors log files for malicious patterns and dynamically updates firewall rules to block offending IPs. Install it with apt install fail2ban and create a local jail configuration at /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300 For WordPress sites, create a custom filter at /etc/fail2ban/filter.d/wordpress.conf targeting XML-RPC abuse and login page brute-forcing:
[Definition]
failregex = ^<HOST>.*POST.*(xmlrpc\.php|wp-login\.php).*(403|401|200)
ignoreregex = Enable and start fail2ban with systemctl enable --now fail2ban. Monitor active bans with fail2ban-client status sshd. In my experience managing shared EC2 infrastructure for multiple legal-tech portals, fail2ban typically blocks hundreds of automated probes per week per server. Without it, even hardened SSH configurations generate excessive failed-authentication log noise that obscures genuine threats.
Why Is PHP-FPM Pool Isolation Critical for Multi-Site Ubuntu Security Hardening?
On servers hosting multiple Laravel or WordPress sites, running all applications under a single PHP-FPM pool creates catastrophic cross-site contamination risk. If one site is compromised, the attacker inherits file-system access to every other site sharing that pool. Pool isolation assigns each site its own Unix socket, user account, and open_basedir restriction.
Create a dedicated system user for each site: useradd -r -s /usr/sbin/nologin -d /var/www/site1 site1. Then configure an isolated pool at /etc/php/8.4/fpm/pool.d/site1.conf:
[site1]
user = site1
group = site1
listen = /run/php/php8.4-fpm-site1.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 4
; Security isolation
open_basedir = /var/www/site1:/tmp
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
chdir = /var/www/site1/public
php_admin_value[upload_tmp_dir] = /var/www/site1/tmp
php_admin_value[session.save_path] = /var/www/site1/sessions The open_basedir directive restricts PHP file operations to the site's directory tree and /tmp. Combined with disable_functions, this prevents compromised scripts from executing system commands or traversing outside their designated root. Set ownership correctly: chown -R site1:site1 /var/www/site1 and ensure Nginx references the correct socket in its upstream configuration.
| Isolation Level | Cross-Site Risk | Resource Overhead | Recommended For |
|---|---|---|---|
| Single shared pool | Critical — full filesystem access | Minimal | Never in production |
| Per-site user + open_basedir | Low — contained to site directory | Moderate | Multi-tenant Laravel/WordPress |
| Containerized (Docker/LXC) | Negligible — kernel namespace isolation | Higher | High-security legal-tech / fintech |
For legal-tech portals handling sensitive client documents, I recommend containerization despite higher operational complexity. For standard business sites and eCommerce platforms like those built for Nepal eCommerce projects, per-site PHP-FPM pools with open_basedir provide sufficient isolation without container orchestration overhead.
How Do Automated Updates and File Permissions Complete Ubuntu Security Hardening?
Manual patching fails because humans forget. Ubuntu's unattended-upgrades package automates security patch installation without requiring intervention. Install and configure it:
apt install unattended-upgrades apt-listchanges
dpkg-reconfigure unattended-upgrades Edit /etc/apt/apt.conf.d/50unattended-upgrades to enable automatic reboot during low-traffic windows and restrict upgrades to security repositories only:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true"; File permissions are equally critical. Web-accessible directories should be owned by the site user with 755 permissions for directories and 644 for files. The storage/ and bootstrap/cache/ directories in Laravel require write access: chown -R site1:www-data /var/www/site1/storage && chmod -R 775 /var/www/site1/storage. Never set 777 permissions anywhere — this grants write access to every system user and negates pool isolation entirely.
Ubuntu Security Hardening Guide Implementation Checklist
Security hardening is not a one-time task but a repeatable process applied to every new server. Use this checklist as your deployment baseline:
- Create non-root admin user with sudo privileges and disable root SSH login
- Deploy ED25519 SSH keys and disable password authentication
- Configure UFW with explicit allow rules for SSH, HTTP, and HTTPS only
- Apply sysctl hardening parameters and verify with
sysctl --system - Install and configure fail2ban with jails for SSH, Nginx, and application-specific patterns
- Create isolated PHP-FPM pools with per-site users and open_basedir restrictions
- Set correct file ownership (site user) and permissions (755/644, never 777)
- Enable unattended-upgrades for automatic security patches with scheduled reboots
- Configure log rotation to prevent disk exhaustion from verbose security logging
- Document all changes in version-controlled server configuration repository
This Ubuntu Security Hardening Guide covers the foundation that protects your application layer. Hardening reduces attack surface but does not eliminate risk — combine it with regular audits, offsite backups, and application-level security practices. For teams managing multiple client sites across shared infrastructure, consider reading about CI/CD pipeline setup in Nepal to automate consistent hardening across deployments. If you need hands-on assistance securing your production environment or implementing these measures for a Laravel application in Nepal, reach out directly for a server security assessment tailored to your infrastructure.

