Introduction

The Apache HTTP Server, or Apache, is one of the most widely used web servers in the world. Since its release in 1995, it has remained popular because it is open source, reliable, and easy to customize. Even in 2025, Apache continues to be a dependable choice for hosting websites and applications on Linux servers such as Ubuntu.

Apache uses a modular design that allows you to enable only the features you need, such as SSL encryption, caching, or URL rewriting. On Ubuntu 24.04, Apache is included with the event MPM as the default processing module, offering improved performance for busy servers.

In this tutorial, you will install Apache on an Ubuntu server, configure the firewall, set up virtual hosts, enable HTTPS with Let's Encrypt, and learn how to manage and troubleshoot the service. This guide follows an HTTPS-first approach, helping you configure SSL early so your Apache server is secure and ready for production use.

Key Takeaways:

  • Default Architecture: Ubuntu 24.04 installs Apache with the event MPM (Multi-Processing Module) by default, offering better performance for high-concurrency environments compared to the older prefork model.
  • Firewall Integration: You must explicitly permit traffic through the firewall; using the 'Apache Full' profile in UFW automatically opens both port 80 (HTTP) and 443 (HTTPS) simultaneously.
  • Virtual Host Strategy: To host multiple domains, avoid using the default /var/www/html root; instead, create dedicated directories for each domain and assign permissions to the non-root user.
  • Configuration Management: Apache separates configuration files (sites-available) from active sites (sites-enabled); use a2ensite to enable a site (creating a symbolic link) and a2dissite to disable it without deleting the file.
  • HTTPS Automation: Security is mandatory, not optional. The python3-certbot-apache plugin automates the acquisition of Let's Encrypt SSL certificates and handles the configuration of HTTPS redirects.
  • Systemd Timers: You do not need to manually renew SSL certificates; Certbot installs a systemd timer that checks for expiration twice daily and renews certificates automatically.
  • Security Hardening: A production-ready server requires disabling directory indexing (to hide file lists) and implementing security headers like X-Content-Type-Options and X-Frame-Options to prevent browser-based attacks.
  • Troubleshooting Protocol: Always verify configuration syntax with sudo apache2ctl configtest before restarting the service to prevent downtime, and check journalctl -u apache2 if the service fails to start.

[info]

Simplify deploying applications to servers with an app platform. Deploy directly from GitHub in minutes.

Prerequisites

apache illustration for: Prerequisites

Before you begin this guide, you should have a regular, non-root user with sudo privileges configured on your server. Additionally, you will need to enable a basic firewall to block non-essential ports. You can learn how to configure a regular user account and set up a firewall for your server by following our Initial server setup guide for Ubuntu.

Once you have created a non-root user with sudo privileges, log in as that user to begin.

Note: This guide has been tested on Ubuntu 24.04 LTS, the latest stable release at the time of writing. The commands and steps will also work on other recent Ubuntu versions, such as 22.04 LTS. However, it is recommended to use the latest stable version to ensure compatibility, security, and access to updated software packages.

Installing Apache

Apache is included in Ubuntu's default package repositories, so you can install it using standard package management tools. Let's start by updating your server's local package index to make sure you're installing the latest available version.

				
					
sudo apt update

				
			

Once the update is complete, install the apache2 package:

				
					
sudo apt install apache2

				
			

When prompted, confirm the installation. The package manager will install Apache along with all required dependencies.

After installation, you can verify that Apache was installed correctly and check the version currently running on your system:

				
					
apache2 -v

				
			

You'll see output similar to this:

				
					
Server version: Apache/2.4.58 (Ubuntu)

Server built: 2025-08-11T11:10:09

				
			

Ubuntu may ship the prefork MPM by default if libapache2-mod-php is installed, because mod_php is not thread safe. To confirm which MPM (Multi-Processing Module) your system is using, run:

				
					
apache2ctl -M | grep mpm

				
			

Expected output:

				
					
mpm_event_module (shared)

				
			

That confirms that Apache is installed and configured with the default event-based processing model.

If you want to switch to the event MPM (recommended when using PHP-FPM instead of mod_php), run:

				
					
sudo a2dismod mpm_prefork

sudo a2enmod mpm_event

sudo systemctl restart apache2

				
			

Note: mpm_event works best with PHP-FPM (php-fpm package). It does not work with mod_php because mod_php requires the prefork MPM.

[info]

Tip: You can extend Apache's functionality by installing additional modules. For example, use sudo apt install apache2-utils for common administrative tools or sudo apt install libapache2-mod-security2 to enable a web application firewall for added security.

Configuring the Firewall for Apache (HTTP and HTTPS)

Before testing Apache, you'll need to adjust your firewall to allow web traffic. If you followed the Initial Server Setup for Ubuntu guide, you should already have UFW (Uncomplicated Firewall) configured to restrict access to only essential services like SSH.

When Apache is installed, it automatically registers a few application profiles with UFW that define which ports to open for different traffic types. To view these profiles, run:

				
					
sudo ufw app list

				
			

You should see output similar to this:

				
					
Available applications:

 Apache

 Apache Full

 Apache Secure

 OpenSSH

				
			

Each profile allows different levels of access:

Profile Ports Opened Description
—————– ———— ———————————-
Apache 80/tcp Allows unencrypted HTTP traffic
Apache Secure 443/tcp Allows encrypted HTTPS traffic
Apache Full 80, 443/tcp Allows both HTTP and HTTPS traffic

Since most websites today use HTTPS by default, it's best to enable the Apache Full profile to allow both HTTP and HTTPS connections:

				
					
sudo ufw allow 'Apache Full'

				
			

Next, verify that the rule was added successfully:

				
					
sudo ufw status

				
			

You should see output similar to this:

				
					
Status: active



To Action From

-- ------ ----

OpenSSH ALLOW Anywhere

Apache Full ALLOW Anywhere

OpenSSH (v6) ALLOW Anywhere (v6)

Apache Full (v6) ALLOW Anywhere (v6)

				
			

This confirms that Apache is now allowed through the firewall for both IPv4 and IPv6 traffic.

Note: If your servers are running on the cloud provider, you can optionally use the cloud provider Cloud Firewalls instead of the UFW firewall. We recommend using only one firewall at a time to avoid conflicting rules that may be difficult to debug.

Checking Apache Status

After installation, Apache starts automatically. Let's verify that it's running and serving web pages correctly.

Check Apache Service Status

Apache on Ubuntu is managed by systemd, which controls how services start, stop, and restart. To check whether Apache is active, run:

				
					
sudo systemctl status apache2

				
			

You should see output similar to this:

				
					
● apache2.service - The Apache HTTP Server

 Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)

 Active: active (running) since Wed 2025-12-03 06:22:48 UTC; 2min 6s ago

 Docs: https://httpd.apache.org/docs/2.4/

 Main PID: 2085 (apache2)

 Tasks: 55 (limit: 4656)

 Memory: 5.3M (peak: 5.5M)

 CPU: 57ms

 CGroup: /system.slice/apache2.service

 ├─2085 /usr/sbin/apache2 -k start

 ├─2087 /usr/sbin/apache2 -k start

 └─2088 /usr/sbin/apache2 -k start

				
			

If you see Active: active (running), Apache is up and running.

If Apache isn't active, you can start it manually with:

				
					
sudo systemctl start apache2

				
			

Test Apache Using Your Server's Public IP

You can confirm Apache is serving web content by visiting your server's public IP address.

First, find your server's IP address:

				
					
hostname -I

				
			

This command will return one or more IP addresses. You can also get your public IPv4 address using:

				
					
curl -4 icanhazip.com

				
			

Copy the IPv4 address and enter it in your browser's address bar:

				
					
http://your_server_ip

				
			

For example:

				
					
http://203.0.113.10

				
			

If Apache is working correctly, you'll see the default Apache welcome page, which confirms your web server is running and serving requests from /var/www/html.

Access Apache via Hostname (Optional)

If you've already configured a domain name for your server, you can also test access using your domain:

				
					
http://your_domain

				
			

Make sure your DNS records are correctly pointed to your server's public IP. DNS changes can take a few minutes to propagate depending on your registrar.

IPv6 Access

Most modern Ubuntu servers, including those on the cloud provider, come with IPv6 enabled by default. To check whether Apache is listening on both IPv4 and IPv6 addresses, run:

				
					
sudo ss -tuln | grep :80

				
			

You should see both of these lines if IPv6 is enabled:

				
					
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* 

LISTEN 0 511 [::]:80 [::]:*

				
			

To test locally over IPv6, open this address in your browser:

				
					
http://[::1]

				
			

Or, if your server has a public IPv6 address, use that address in brackets:

				
					
http://[your_ipv6_address]

				
			

Tip: If you're testing on a remote cloud instance, make sure your provider's networking setup supports both IPv4 and IPv6. On the cloud provider, you can verify this under Networking -> IP Addresses in your control panel.

Managing the Apache Process

Now that Apache is installed and running, it's helpful to know how to control the service. Ubuntu uses systemd to manage background services, including Apache. This means you can use the systemctl command to start, stop, restart, and check the status of the web server.

Starting, Stopping, and Restarting Apache

To stop the web server, run:

				
					
sudo systemctl stop apache2

				
			

To start Apache again, run:

				
					
sudo systemctl start apache2

				
			

If you've made configuration changes and need to apply them, you can restart the service:

				
					
sudo systemctl restart apache2

				
			

Restarting stops and then restarts Apache, which briefly interrupts any active connections. For configuration updates that don't require a full restart, you can instead reload the service to apply changes gracefully:

				
					
sudo systemctl reload apache2

				
			

Reloading tells Apache to re-read its configuration files without closing existing connections. This is useful when you're updating virtual hosts, enabling modules, or changing log settings.

Enable or Disable Apache at Boot

By default, Apache is set to start automatically when your system boots. You can confirm this behavior by checking its enablement status:

				
					
sudo systemctl is-enabled apache2

				
			

To disable Apache from starting automatically on boot:

				
					
sudo systemctl disable apache2

				
			

To enable it again:

				
					
sudo systemctl enable apache2

				
			

This control is useful for testing environments or servers where you only want Apache running on demand.

Checking Apache's Status

At any time, you can view the current status of the Apache service:

				
					
sudo systemctl status apache2

				
			

This command displays whether the service is running, its uptime, and recent log entries. You'll also see the Main PID, which identifies the process Apache is using to serve requests.

For a simple confirmation without full log output, you can use:

				
					
sudo systemctl is-active apache2

				
			

If it returns active, Apache is running as expected.

Viewing Apache Logs

Apache keeps detailed logs that can help you monitor performance and diagnose issues. These logs are stored in /var/log/apache2/ by default:

  • Access logs (/var/log/apache2/access.log): records every request to your server.
  • Error logs (/var/log/apache2/error.log): records warnings, errors, and startup messages.

To view the most recent entries in the error log, use:

				
					
sudo tail -f /var/log/apache2/error.log

				
			

For a broader look at Apache's activity through systemd's journal, use the modern log viewer:

				
					
sudo journalctl -u apache2 --no-pager

				
			

You can also view only the latest events:

				
					
sudo journalctl -u apache2 -n 20

				
			

And to follow logs in real time:

				
					
sudo journalctl -u apache2 -f

				
			

Using journalctl is often the best way to view live logs and service messages in modern Ubuntu systems, since it combines traditional logging with system-level information.

Tip: For production servers, consider setting up log rotation and retention policies using logrotate, which is installed by default on Ubuntu. This prevents log files from growing too large and ensures older logs are archived automatically.

Setting Up Virtual Hosts

When using the Apache web server, you can configure virtual hosts (similar to server blocks in Nginx) to define separate configurations for each website hosted on the same server. Virtual hosts make it easy to serve different domains or subdomains from a single machine, each with its own document root, log files, and configuration options.

In this example, we'll set up a domain called example.com, but you should replace this with your actual domain name. If you're setting up a new domain with the cloud provider, refer to our Networking Documentation for steps on creating DNS records that point to your server.

Creating the Web Root Directory

Apache on Ubuntu includes one default site that serves content from /var/www/html. While this works for a single website, it's better to create a separate directory for each domain you host. This structure keeps files organized and prevents conflicts when managing multiple sites.

Create a new directory for your domain under /var/www:

				
					
sudo mkdir /var/www/example.com

				
			

Assign ownership of the directory to your current user to make it easier to edit web files:

				
					
sudo chown -R $USER:$USER /var/www/example.com

				
			

By default, Ubuntu sets a umask value that assigns secure permissions, but you can verify the correct settings using:

				
					
sudo chmod -R 755 /var/www/example.com

				
			

This gives the owner full read/write/execute access, while allowing others to read and execute files, the standard for web content.

Now, let's create a simple test page that will confirm your virtual host works correctly:

				
					
sudo nano /var/www/example.com/index.html

				
			

Add the following HTML content:

				
					
<html>

 <head>

 <title>Welcome to example.com!</title>

 </head>

 <body>

 <h1>Success! The example.com virtual host is working!</h1>

 <p>This page is being served from /var/www/example.com on Ubuntu 24.04.</p>

 </body>

</html>

				
			

Save and close the file when finished.

Creating the HTTP Virtual Host

Apache's virtual host configuration files are stored in the /etc/apache2/sites-available/ directory. These files define how Apache should respond to incoming HTTP requests for a given domain.

Let's create a new configuration file for your domain:

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

				
			

Insert the following configuration block:

				
					
<VirtualHost *:80>

 ServerAdmin webmaster@example.com

 ServerName example.com

 ServerAlias www.example.com

 DocumentRoot /var/www/example.com



 ErrorLog ${APACHE_LOG_DIR}/example.com-error.log

 CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

</VirtualHost>

				
			

Here's what each directive does:

  • ServerAdmin: The email address Apache should display on error pages.
  • ServerName: The main domain name for this virtual host.
  • ServerAlias: Additional domain names that should point to the same site (for example, www.example.com).
  • DocumentRoot: The directory where your site's files are stored.
  • ErrorLog and CustomLog: Define separate log files for tracking errors and access requests.

Save and close the file. This configuration will handle all requests to http://example.com.

Enabling and Testing Your Sites

Now that your configuration files are ready, you can enable your site using the a2ensite command:

				
					
sudo a2ensite example.com.conf

				
			

To prevent the default site from serving unintended traffic, disable it:

				
					
sudo a2dissite 000-default.conf

				
			

Before applying any changes, always test your Apache configuration for syntax errors:

				
					
sudo apache2ctl configtest

				
			

You should see this output:

				
					
Syntax OK

				
			

If there are no syntax errors, reload Apache to apply the configuration changes:

				
					
sudo systemctl reload apache2

				
			

This command gracefully reloads the service, applying new settings without disconnecting existing users.

You can confirm that both virtual hosts are active by listing the enabled sites:

				
					
sudo apache2ctl -S

				
			

You'll see an output that includes your domain and the associated configuration file paths.

Now, open your browser and visit your site:

				
					
http://example.com

				
			

If everything is set up correctly, you should see the sample page you created earlier.

Installing TLS/SSL with Let's Encrypt

Using HTTPS has become the standard for all modern websites, not only to secure user data but also to improve search rankings and user trust. The easiest way to obtain and manage free SSL/TLS certificates is through Let's Encrypt, a certificate authority that provides automated, no-cost certificates.

Let's Encrypt works together with Certbot, a lightweight command-line tool that handles certificate creation, installation, and renewal automatically.

In this section, you'll install Certbot, generate a certificate for your domain, and verify that automatic renewal is configured correctly.

Installing Certbot and the Apache Plugin

Certbot is included in Ubuntu's default repositories, along with a plugin that integrates directly with Apache.

Update your package index and install both packages:

				
					
sudo apt update

sudo apt install certbot python3-certbot-apache

				
			
  • The certbot package handles certificate requests and renewals.
  • The python3-certbot-apache plugin automates the Apache configuration process for HTTPS.

Once installed, you can verify Certbot's version with:

				
					
certbot --version

				
			

Generating a Let's Encrypt Certificate

With Certbot installed, you can request and install a certificate for your domain in a single step. Replace example.com and www.example.com with your actual domain names:

				
					
sudo certbot --apache -d example.com -d www.example.com

				
			

Certbot will:

  1. Communicate with Let's Encrypt's servers to verify domain ownership.
  1. Generate a valid SSL/TLS certificate.
  1. Automatically update your Apache virtual host to use HTTPS.
  1. Reload Apache to apply the changes.

You'll be asked to provide an email address for renewal notices and agree to the Let's Encrypt Terms of Service. When prompted, you can also choose whether to redirect HTTP traffic to HTTPS. Selecting "Redirect" is recommended, as it enforces secure connections for all visitors.

After the setup completes, Certbot will display a message confirming that the certificate was successfully installed.

You can verify your certificate's expiration date with:

				
					
sudo certbot certificates

				
			

The output should list your domain name and indicate that your certificate is valid for 90 days.

Automatic Certificate Renewal

Let's Encrypt certificates are valid for 90 days, but Certbot includes a built-in systemd timer that automatically renews them before they expire.

You can confirm that the renewal timer is active with:

				
					
sudo systemctl status certbot.timer

				
			

You should see output similar to this:

				
					
● certbot.timer - Run certbot twice daily

 Loaded: loaded (/lib/systemd/system/certbot.timer; enabled)

 Active: active (waiting) since Tue 2025-12-02 15:00:00 UTC; 1h ago

 Trigger: Wed 2025-12-03 00:00:00 UTC; 8h left

				
			

This means that Certbot will automatically check for expiring certificates twice per day and renew them if necessary.

Note: If you installed Certbot via snap/distro packaging, the mechanism may be a systemd timer or a cron job. You can check this with systemctl list-timers.

To manually test the renewal process without making changes, use:

				
					
sudo certbot renew --dry-run

				
			

If you see "Congratulations! Your certificate and chain have been saved successfully.", automatic renewal is working as expected.

Testing Your HTTPS Configuration

After your certificate is installed, open your site in a web browser and verify that it loads securely:

				
					
https://example.com

				
			

You should see the padlock icon in the browser's address bar, indicating that HTTPS is active and the connection is encrypted.

You can also verify the configuration using the command line with:

				
					
curl -I https://example.com

				
			

A valid response should include:

				
					
HTTP/2 200

content-type: text/html

strict-transport-security: max-age=31536000; includeSubDomains

				
			

If you see this response, your site is correctly serving HTTPS traffic.

Getting Familiar with Important Apache Files and Directories

Now that Apache is installed, configured, and serving your site, it's helpful to understand where key files and directories are located. Knowing how Apache's configuration is organized will make it easier to manage multiple sites, enable modules, and troubleshoot issues later.

/var/www/ — Web Root Directories

This is where your website content lives. By default, Apache serves files from /var/www/html, which contains the default Apache landing page you saw after installation.

When hosting multiple sites, it's common to create a dedicated directory for each one, such as:

				
					
/var/www/example.com

/var/www/myblog.com

/var/www/api.example.com

				
			

Each virtual host you configure can point to its own directory inside /var/www. This structure keeps your projects organized and allows you to apply permissions or ownership separately per site.

/etc/apache2/ — Apache Configuration Directory

This directory contains all of Apache's configuration files. Most of your administrative work, including enabling sites, changing ports, or managing modules, happens here.

The key files and subdirectories include:

Location Description
—————————- —————————————————————————————————————————————————————————————————
/etc/apache2/apache2.conf The main configuration file. It loads the other configuration files and sets global options that affect the entire server.
/etc/apache2/ports.conf Defines which ports Apache listens on. By default, Apache listens on port 80 (HTTP) and port 443 (HTTPS) when SSL is enabled.
/etc/apache2/envvars Contains environment variable settings used by Apache, such as the user and group under which it runs (www-data by default).
/etc/apache2/conf-enabled/ Contains symbolic links to active configuration fragments found in /etc/apache2/conf-available/. Used for settings that apply to all sites (for example, security headers or timeout directives).

sites-available/ and sites-enabled/ — Virtual Host Configurations

Apache separates virtual host configurations into two directories:

  • /etc/apache2/sites-available/ contains all virtual host configuration files. These files define how Apache serves each site, including the document root, domain names, and logging directives.
  • /etc/apache2/sites-enabled/ contains symbolic links to the active site configurations found in sites-available/.

To activate a site, use:

				
					
sudo a2ensite example.com.conf

				
			

To deactivate it:

				
					
sudo a2dissite example.com.conf

				
			

This approach makes it easy to manage multiple websites without editing global configuration files. You can quickly enable or disable sites as needed, and Apache will only load configurations that are linked in sites-enabled/.

mods-available/ and mods-enabled/ — Apache Modules

Apache's functionality is modular, meaning most features, such as SSL, rewrite rules, or compression, are implemented as modules that can be loaded dynamically.

  • /etc/apache2/mods-available/ contains configuration (.conf) and load (.load) files for all available modules.
  • /etc/apache2/mods-enabled/ contains symbolic links to the modules that are currently enabled.

You can enable or disable modules using these commands:

				
					
sudo a2enmod module_name

sudo a2dismod module_name

				
			

For example, to enable the rewrite and ssl modules (common for HTTPS sites):

				
					
sudo a2enmod rewrite ssl

				
			

After enabling or disabling modules, reload Apache to apply the changes:

				
					
sudo systemctl reload apache2

				
			

conf-available/ and conf-enabled/ — Configuration Fragments

These directories are similar to the site directories but are used for global configuration snippets that don't belong to a specific virtual host.

For example, a configuration file that sets default security headers or MIME types might live in /etc/apache2/conf-available/, and when enabled, a symbolic link is created in /etc/apache2/conf-enabled/.

You can enable or disable these configuration fragments with:

				
					
sudo a2enconf config_name

sudo a2disconf config_name

				
			

Like site configurations, these fragments are only active when linked in conf-enabled/.

/var/log/apache2/ — Log Files

Apache logs nearly every event, from client requests to errors, in the /var/log/apache2/ directory. Monitoring these logs is one of the best ways to understand how your server is performing and to troubleshoot problems.

The two most common log files are:

File Description
—————————– ——————————————————————————————————————-
/var/log/apache2/access.log Records every request to the web server, including the client IP, requested URL, status code, and user agent.
/var/log/apache2/error.log Captures startup messages, warnings, and errors. Useful for diagnosing configuration issues or site-level problems.

You can view the most recent log entries with:

				
					
sudo tail -f /var/log/apache2/access.log

				
			

or

				
					
sudo tail -f /var/log/apache2/error.log

				
			

For a broader view across all Apache logs, you can use:

				
					
sudo journalctl -u apache2 --no-pager

				
			

This command shows recent service messages collected by systemd, combining traditional logs with service-level events.

Tip: On high-traffic sites, log files can grow quickly. Ubuntu includes logrotate, which automatically compresses and rotates Apache logs to prevent them from filling up disk space. You can view its configuration at /etc/logrotate.d/apache2.

Security Best Practices

Once Apache is installed and serving your websites, the next step is securing your web server. Even a correctly configured Apache installation can expose unnecessary information or become vulnerable if not hardened properly. The following best practices will help protect your system against common attacks, reduce information exposure, and keep your web environment stable and up to date.

Disable Directory Listing

By default, Apache may display the contents of a directory if it does not contain an index file. This can unintentionally expose sensitive information, such as backup files, configuration scripts, or version numbers.

To disable directory listing, open your site's configuration file:

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

				
			

Inside the <Directory> block or the virtual host configuration, ensure the Options directive does not include Indexes. For example:

				
					
&lt;Directory /var/www/example.com&gt;

 Options FollowSymLinks

 AllowOverride All

 Require all granted

&lt;/Directory&gt;

				
			

Save the file and reload Apache to apply your changes:

				
					
sudo systemctl reload apache2

				
			

Now, if a directory does not contain an index.html file, Apache will return a 403 Forbidden error instead of listing its contents.

Restrict File Permissions and Ownership

File and directory permissions should always follow the principle of least privilege.

  • The owner of each web root should be the user who manages the files.
  • The group should typically remain www-data, which is the default user that Apache runs as.

You can set these permissions with the following commands:

				
					
sudo chown -R $USER:www-data /var/www/example.com

sudo find /var/www/example.com -type d -exec chmod 755 {} \;

sudo find /var/www/example.com -type f -exec chmod 644 {} \;

				
			

These commands ensure that directories are readable and executable by everyone but writable only by the owner, while files are readable by everyone and writable only by the owner.

Avoid granting 777 permissions, as they allow any user on the system to modify web files.

Enable Security Headers

Security headers help protect browsers from common web vulnerabilities like cross-site scripting (XSS), clickjacking, and content-type sniffing.

If you have not already done so, enable the headers module:

				
					
sudo a2enmod headers

				
			

Then, open your site's virtual host configuration file:

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

				
			

Inside the <VirtualHost> block, add the following headers:

				
					
Header always set X-Content-Type-Options "nosniff"

Header always set X-Frame-Options "SAMEORIGIN"

Header always set Referrer-Policy "strict-origin-when-cross-origin"

				
			

You can also apply a basic Content Security Policy (CSP) to control which resources the browser can load:

				
					
Header set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self';"

				
			

This policy allows only local scripts and styles to load from the same domain.

Save your changes and reload Apache:

				
					
sudo systemctl reload apache2

				
			

To confirm that the headers are active, you can test your site with curl:

				
					
curl -I https://example.com

				
			

Look for the headers in the response. You can also use securityheaders.com to analyze your configuration.

Harden SSL and TLS Configuration

Apache 2.4.58 on Ubuntu 24.04 supports TLS 1.3 by default, provided your OpenSSL version is 1.1.1 or later (check with openssl version). To ensure strong encryption and compatibility, open the SSL configuration file:

				
					
sudo nano /etc/apache2/mods-available/ssl.conf

				
			

Verify or update the following settings:

				
					
SSLProtocol TLSv1.2 TLSv1.3

SSLCipherSuite HIGH:!aNULL:!MD5:!3DES

SSLHonorCipherOrder on

				
			

These settings disable older, insecure protocols and ciphers.

After saving the file, reload Apache:

				
					
sudo systemctl reload apache2

				
			

For stricter or more compatible configurations (Modern or Old profiles), you can generate templates at: SSL Configuration Generator. You can also test your site's SSL configuration using Qualys SSL Labs to verify that it scores at least an "A" rating.

Disable Unused Apache Modules

Every enabled module increases Apache's attack surface. To reduce potential vulnerabilities, disable any modules that are not required for your site.

List enabled modules with:

				
					
apache2ctl -M

				
			

If you see a module you are not using, disable it with:

				
					
sudo a2dismod module_name

				
			

For example, if your site does not use CGI scripts:

				
					
sudo a2dismod cgi

				
			

After disabling modules, reload Apache:

				
					
sudo systemctl reload apache2

				
			

Keep essential modules such as ssl, rewrite, headers, and mpm_event active, as they are commonly used for secure, high-performance websites.

Keep the System Updated Automatically

Keeping your server updated is one of the most effective ways to prevent vulnerabilities. Security patches are released regularly for both Ubuntu and Apache. To ensure your server always receives updates, enable unattended-upgrades, which installs security updates automatically.

Install the package:

				
					
sudo apt install unattended-upgrades

				
			

Then enable automatic updates:

				
					
sudo dpkg-reconfigure --priority=low unattended-upgrades

				
			

By default, the service runs daily and applies available security updates silently. You can check the status of the timer with:

				
					
systemctl status apt-daily-upgrade.timer

				
			

Logs are stored in /var/log/unattended-upgrades/.

To apply updates manually at any time, run:

				
					
sudo apt update &amp;&amp; sudo apt upgrade

				
			

Additional Recommendations

To further improve security and server reliability:

  • Use strong passwords or SSH keys for administrative access.
  • Restrict SSH access to known IP addresses using UFW or cloud firewalls.
  • Set up fail2ban to automatically block repeated failed login attempts.
  • Regularly back up your /etc/apache2/ and /var/www/ directories.
  • Monitor logs for unusual activity using tools like goaccess or journalctl.

Basic Troubleshooting

Even a correctly configured Apache server can occasionally fail to start, reload, or serve web pages. Common issues usually involve syntax errors, missing permissions, or blocked ports.

1. Check Apache Service Logs

When Apache does not start or reload properly, the first place to look is the service log. Apache integrates with systemd, so logs are managed by the journalctl command.

To view recent log entries:

				
					
sudo journalctl -u apache2 --no-pager

				
			

This displays Apache-related messages, including startup logs, configuration warnings, and module errors.

If you want to see live log updates while restarting or reloading Apache, use:

				
					
sudo journalctl -u apache2 -f

				
			

The log output can reveal valuable details such as:

				
					
AH00526: Syntax error on line 14 of /etc/apache2/sites-enabled/example.com.conf:

Invalid command 'Redirectt'

				
			

or

				
					
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80

				
			

In these cases:

  • The first indicates a typo or syntax issue in a configuration file.
  • The second means Apache cannot bind to port 80, usually because another process is using it or UFW or a cloud firewall is blocking it.

Checking logs is often the quickest way to pinpoint why Apache isn't starting or responding.

2. Test Apache Configuration Syntax

A common mistake is reloading Apache after editing a configuration file without testing it first. Apache includes a built-in syntax checker that scans all configuration files for errors.

Run the following:

				
					
sudo apache2ctl configtest

				
			

If your configuration is valid, you'll see:

				
					
Syntax OK

				
			

If not, the command will show the file and line number containing the issue. For example:

				
					
AH00526: Syntax error on line 25 of /etc/apache2/sites-enabled/example.com.conf:

Invalid command 'ServerNme', perhaps misspelled or defined by a module not included in the server configuration

				
			

This tells you exactly where the problem is located. Once you fix the issue, test again until the syntax passes.

Finally, reload Apache to apply the working configuration:

				
					
sudo systemctl reload apache2

				
			

Tip: Always run configtest before reloading Apache, especially on production servers. It prevents accidental downtime caused by broken configurations.

3. Check Listening Ports and Conflicting Services

If your Apache service starts but your site doesn't load, it may not be listening on the expected ports (80 for HTTP, 443 for HTTPS), or another application could be using those ports.

Check which ports Apache is currently listening on:

				
					
sudo ss -tuln | grep apache

				
			

You should see output similar to:

				
					
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("apache2",pid=1534,fd=4))

LISTEN 0 511 [::]:443 [::]:* users:(("apache2",pid=1535,fd=6))

				
			

This confirms Apache is listening on both HTTP and HTTPS.

If no entries appear, check that your virtual hosts and SSL module are enabled:

				
					
sudo a2enmod ssl

sudo a2ensite example.com.conf

sudo a2ensite example.com-le-ssl.conf

sudo systemctl reload apache2

				
			

If another process is using port 80 or 443, identify it:

				
					
sudo ss -tulpn | grep ':80\|:443'

				
			

This will show which process ID (PID) and program name are bound to the ports. For example:

				
					
nginx 1920 root 6u IPv4 37221 0t0 TCP *:80 (LISTEN)

				
			

If another web server like Nginx or a development process (for example, Node.js) is using the same port, you can either stop that service or reconfigure one of them to use a different port.

4. Fix Common Permission and Ownership Errors

If Apache starts correctly but returns a "403 Forbidden" error or fails to load your site, it often means that file permissions or ownership are incorrect. Apache must be able to read the files under your site's web root, and they must be owned by the right user and group.

To fix ownership and permissions, run:

				
					
sudo chown -R $USER:www-data /var/www/example.com

sudo find /var/www/example.com -type d -exec chmod 755 {} \;

sudo find /var/www/example.com -type f -exec chmod 644 {} \;

				
			

These commands set:

  • The current user as the owner (so you can edit files easily).
  • The www-data group for Apache.
  • Secure permissions for files and directories.

You can confirm the permissions using:

				
					
ls -ld /var/www/example.com

				
			

The output should look like this:

				
					
drwxr-xr-x 3 user www-data 4096 Jan 10 12:34 /var/www/example.com

				
			

If your site uses uploads or caching (like WordPress), you may need to give Apache write access to specific directories:

				
					
sudo chmod 775 /var/www/example.com/wp-content/uploads

				
			

Be cautious not to apply global write access, as it can open serious security risks.

5. Check DNS Configuration and Propagation

If your site works when accessed via its IP address but not through the domain name, it is usually a DNS or propagation issue.

First, check that your domain points to the correct server IP:

				
					
dig example.com +short

				
			

Compare the result with your server's public IP address:

				
					
curl -4 icanhazip.com

				
			

If they don't match, update your DNS records at your registrar or DNS provider.

You can also check global DNS propagation using a tool such as whatsmydns.net.

If you recently updated DNS records, remember that propagation can take several hours depending on the TTL (time-to-live) values configured for your domain.

If you're hosting your DNS on the cloud provider, make sure your A (IPv4) and AAAA (IPv6) records are correctly configured in the Networking -> Domains section of the control panel.

6. Verify Cloud and Local Firewall Rules

Sometimes Apache runs correctly but is inaccessible from the internet because traffic is being blocked by a firewall. Ubuntu uses UFW by default.

Check your firewall status:

				
					
sudo ufw status

				
			

You should see entries like this:

				
					
Status: active



To Action From

-- ------ ----

OpenSSH ALLOW Anywhere

Apache Full ALLOW Anywhere

OpenSSH (v6) ALLOW Anywhere (v6)

Apache Full (v6) ALLOW Anywhere (v6)

				
			

If the Apache Full profile is missing, enable it:

				
					
sudo ufw allow 'Apache Full'

				
			

Then reload UFW:

				
					
sudo ufw reload

				
			

If you're running Apache on a cloud provider such as the cloud provider, confirm that the cloud firewall also allows inbound connections on ports 80 and 443.

For example, in the the cloud provider Control Panel:

  1. Go to Networking -> Firewalls.
  1. Select your Droplet's firewall.
  1. Ensure inbound rules for HTTP (80) and HTTPS (443) are both allowed.

If you're using a load balancer or CDN, confirm that it is properly forwarding requests to your Droplet's IP address and ports.

7. Identify and Fix Broken Virtual Host Configurations

Apache uses virtual hosts to map domain names to specific directories and configurations. A broken or conflicting virtual host file is one of the most common problems beginners face.

To list all active virtual hosts, use:

				
					
sudo apache2ctl -S

				
			

This command shows each domain's configuration file and port. Look for:

  • The correct ServerName (must match your domain).
  • A valid DocumentRoot path (should point to your web directory).
  • No duplicate entries for the same port.

If you see this warning:

				
					
AH00558: apache2: Could not reliably determine the server's fully qualified domain name

				
			

Add a global ServerName directive to fix it:

				
					
echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf

sudo a2enconf servername.conf

sudo systemctl reload apache2

				
			

If one of your site configurations is broken and prevents Apache from starting, disable it temporarily:

				
					
sudo a2dissite example.com.conf

sudo systemctl reload apache2

				
			

Then review the file in /etc/apache2/sites-available/ for issues such as:

  • Missing </VirtualHost> closing tags
  • Incorrect indentation or misplaced directives
  • Wrong log or document paths

Once fixed, re-enable the site:

				
					
sudo a2ensite example.com.conf

sudo systemctl reload apache2

				
			

Your site should now load correctly.

Tip: When troubleshooting Apache, isolate each issue step-by-step. Start by confirming that the service is running, then check the configuration syntax, permissions, ports, and DNS. Apache's error logs (journalctl and /var/log/apache2/error.log) almost always contain the clues you need.

FAQs

1. How do I install Apache on Ubuntu?

You can install Apache from Ubuntu's default repositories. Update your package index and install Apache with:

				
					
sudo apt update

sudo apt install apache2

				
			

Once installed, Apache starts automatically. You can verify it with:

				
					
sudo systemctl status apache2

				
			

2. How do I start, stop, or restart Apache?

Use the systemctl command to control the Apache service:

				
					
sudo systemctl start apache2

sudo systemctl stop apache2

sudo systemctl restart apache2

				
			

To reload configuration changes without interrupting active connections, use:

				
					
sudo systemctl reload apache2

				
			

You can also check if it starts automatically at boot using:

				
					
sudo systemctl is-enabled apache2

				
			

3. How do I configure virtual hosts in Apache?

Virtual hosts let you host multiple sites on one server. Create a new configuration file in /etc/apache2/sites-available/:

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

				
			

Add a basic configuration block:

				
					
&lt;VirtualHost *:80&gt;

 ServerName example.com

 ServerAlias www.example.com

 DocumentRoot /var/www/example.com

&lt;/VirtualHost&gt;

				
			

Save the file, enable the site, and reload Apache:

				
					
sudo a2ensite example.com.conf

sudo systemctl reload apache2

				
			

4. How do I allow HTTP and HTTPS traffic through the Ubuntu firewall?

If you're using UFW, list the available application profiles with:

				
					
sudo ufw app list

				
			

Then allow full Apache access (both HTTP and HTTPS):

				
					
sudo ufw allow 'Apache Full'

				
			

Check your firewall status to confirm:

				
					
sudo ufw status

				
			

5. How can I test if Apache is working correctly?

Open your browser and visit your server's public IP address:

				
					
http://your_server_ip

				
			

You should see the default Apache welcome page. You can also check the service status with:

				
					
sudo systemctl status apache2

				
			

If the page does not load, review the firewall settings and confirm that Apache is active.

6. Where is the default web root directory in Ubuntu?

By default, Apache serves content from /var/www/html.

You can replace or modify the index.html file in this directory to change what appears on your site's home page. When hosting multiple domains, you can create additional directories such as /var/www/example.com.

7. How do I troubleshoot Apache not starting?

Start by checking for syntax errors:

				
					
sudo apache2ctl configtest

				
			

If you see anything other than "Syntax OK," fix the listed issue. Then review service logs for errors:

				
					
sudo journalctl -u apache2 --no-pager

				
			

If ports 80 or 443 are already in use, identify the conflicting service with:

				
					
sudo ss -tulpn | grep ':80\|:443'

				
			

Permission issues can also prevent Apache from reading files in /var/www/. Make sure your user and group ownership are correct and that directories are readable.

8. How do I enable SSL on Apache in Ubuntu?

Enable the SSL and headers modules first:

				
					
sudo a2enmod ssl

sudo a2enmod headers

				
			

You can then install Let's Encrypt to get a free SSL certificate:

				
					
sudo apt install certbot python3-certbot-apache

sudo certbot --apache -d example.com -d www.example.com

				
			

Certbot will automatically configure HTTPS and handle renewals. Once installed, you can test renewal with:

				
					
sudo certbot renew --dry-run

				
			

Summary

In this tutorial, you installed and configured the Apache web server on an Ubuntu server. You verified that Apache was running, allowed HTTP and HTTPS traffic through the firewall, and created virtual hosts for both protocols. You secured your site with Let's Encrypt SSL certificates, applied key security settings, and learned how to manage Apache modules, logs, and configurations.

Your server is now fully configured and ready to host production websites. To continue exploring, check out the following articles: