Step-by-Step Guide to Securely Installing Apache2 on Ubuntu
Misconfigured web servers routinely become attack vectors, and Apache2—while robust—requires deliberate hardening at install. Here’s a pragmatic workflow for deploying Apache2 on Ubuntu with security and operational reliability as first-class concerns. Targeting Ubuntu 20.04 LTS and above.
Prerequisites
- Fresh Ubuntu 20.04/22.04 LTS instance
sudo
or root privileges- SSH or console access
No graphical environment necessary or recommended.
1. Update All Packages
Neglecting patch management creates an immediate risk surface. Always begin with:
sudo apt update && sudo apt upgrade -y
Side effect: Upgrades can sometimes restart services—assess impact if in a shared environment.
2. Install Apache2 and Supporting Tools
Install Apache2 plus apache2-utils
. Utilities like htpasswd
are essential for access control.
sudo apt install apache2 apache2-utils -y
Confirm install and note the version in use:
apache2 -v
# Output sample:
# Server version: Apache/2.4.41 (Ubuntu)
If you see command not found
, your $PATH or package install failed; check /usr/sbin
for binaries.
3. Enable and Start the Apache2 Service
Service reliability comes from consistent startup. Enable Apache2 for system boot:
sudo systemctl enable --now apache2
sudo systemctl status apache2
# Look for 'active (running)'
Unexpectedly, some cloud images have Apache2 masked (e.g., cloud-init customizations); if so, unmask:
sudo systemctl unmask apache2
4. Configure UFW Firewall: Minimal Surface
Expose only what is required:
sudo ufw allow 'Apache Full'
sudo ufw reload
sudo ufw status verbose
This rule set opens TCP/80, TCP/443. Reject blanket ufw allow 80,443/tcp
; the profile method adapts if Apache ports are custom-configured.
5. Disable Unneeded Modules
By default, Apache2 is modular—but the enabled set on Ubuntu can be excessive. Each module expands the attack surface.
List modules:
apache2ctl -M
Example: Disable directory indexing, which casually exposes file trees:
sudo a2dismod autoindex
sudo systemctl reload apache2
Common modules to review:
status
(disable unless using server-status, and then restrict by IP)userdir
(rarely needed outside academic labs)
Trade-off: Stripping modules without full review can break applications that rely on them. Stage changes where possible.
6. Suppress Server Version and OS Details
Default Apache2 leaks software and OS versioning in headers and error pages. This is reconnaissance gold for attackers.
Edit /etc/apache2/conf-available/security.conf
:
ServerTokens Prod
ServerSignature Off
Reload:
sudo systemctl reload apache2
Testing:
curl -I http://localhost | grep Server
# Server: Apache
Now only 'Apache' appears—no minor version, no OS hint.
7. Optional: HTTP Basic Auth For Sensitive Paths
For private admin panels or non-public APIs, basic auth can be an expedient first gate.
sudo htpasswd -b -c /etc/apache2/.htpasswd admin securePa55w0rd
sudo mkdir -p /var/www/html/private
echo '
AuthType Basic
AuthName "Restricted"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
' | sudo tee /var/www/html/private/.htaccess
In /etc/apache2/sites-available/000-default.conf
, ensure for the secured path:
<Directory /var/www/html/private>
AllowOverride All
</Directory>
Restart Apache2:
sudo systemctl restart apache2
Test: Visiting /private/
now prompts for credentials. Gotcha: .htaccess processing is disabled by default in many hardened environments; for performance, prefer moving auth directives directly into virtual host configs when feasible.
8. Enforce HTTPS With Let’s Encrypt
Cleartext HTTP is a liability. Use Certbot to automate TLS configuration (no commercial certificates required):
sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
During issuance, Certbot updates Apache config, enabling SSL
and setting up a redirect.
Quick verification:
curl -v https://yourdomain.com 2>&1 | grep "SSL"
# Expect "SSL connection using TLSv1.3"
Certbot schedules auto-renewal (systemctl list-timers | grep certbot
), but a manual test is best:
sudo certbot renew --dry-run
Known issue: Some VPS providers block port 80 or 443 by default; ensure these are open before running.
9. Validate, Scan, and Monitor
Connect to the server in a browser or with curl
; confirm you see the Apache default page or your deployed content.
For a non-obvious verification, test HTTP headers for exposure:
curl -I https://yourdomain.com | grep Server
Security scanning tools:
- Mozilla Observatory (https://observatory.mozilla.org/)
- SSL Labs (https://www.ssllabs.com/ssltest/)
It's easy to overlook: Apache2 emits X-Powered-By
from PHP if mod_php is active—review additional stack components for header exposure.
Recap & Practical Extensions
Apache2 can be safely deployed in under 30 minutes with high confidence against low-effort attacks. The steps above deliberately exclude minor tuning (e.g., KeepAlive
, mpm_event vs. mpm_prefork) and complex scenarios (multi-site vhosts, reverse proxying) for brevity.
Practical tip:
To quickly test config changes before reloading production, use:
apache2ctl configtest
# Example output: "Syntax OK"
What's missing? Logging and alerting—baseline monitoring is not bundled. Serious deployments should forward logs to a SIEM or at least enable logrotate
.
Questions about deploying Apache with WSGI, behind a load balancer, or for multi-tenancy? Those require further layers of configuration not covered here.