How to Install Apache2 on Ubuntu
Get Apache serving your own domain over HTTP on a clean Ubuntu server, with the firewall opened correctly and a virtual host that won't fall over the moment you add a second site. Tested on 26.04, 24.04 and 22.04.
Type your own and every command below updates. Nothing leaves your browser.
Apache is the web server I reach for when I want something predictable. It’s in Ubuntu’s default repositories, it starts on boot without being asked twice, and the Debian-style config layout makes a lot of sense once you know which directory does what.
We’ll go from a clean Ubuntu server to Apache serving your own domain, with the firewall configured properly rather than left wide open. The commands are identical on Ubuntu 26.04, 24.04 and 22.04, and all three are tested.
Before You Start
- A server running Ubuntu 26.04, 24.04 or 22.04, with a user that has
sudoaccess - A domain with an A record pointing at your server’s public IP
- Port 80 reachable from outside, which most cloud firewalls allow by default (do check yours)
If you haven’t pointed a domain at the server yet you can still follow along to the end of step 4, then come back for the virtual host once DNS is sorted.
Step 1: Update the Package Index
sudo apt update
This refreshes the list of available packages so you install the current Apache build rather than whatever your server image happened to ship with. It takes a few seconds on a fresh server.
Step 2: Install Apache
sudo apt install -y apache2
The -y answers the confirmation prompt for you. Ubuntu enables and starts the apache2 service as part of the install, so there’s no separate systemctl enable to run afterwards.
Check what you’ve landed on:
apache2 -v
Server version: Apache/2.4.66 (Ubuntu)
Server built: 2026-07-06T15:33:20
Step 3: Open the Firewall
Ubuntu ships with ufw, and Apache registers a set of application profiles with it during install. You can see them with:
sudo ufw app list
Available applications:
Apache
Apache Full
Apache Secure
OpenSSH
Apache opens port 80, Apache Secure opens 443, and Apache Full opens both. We’re only doing HTTP here, so Apache is the one you want:
sudo ufw allow "Apache"
Don’t skip this one. If you enable ufw later without an Apache rule already in place, the site goes dark and the cause isn’t obvious from the server’s point of view, since Apache carries on looking perfectly healthy.
Step 4: Check Apache Is Running
systemctl status apache2
You’re looking for Active: active (running) near the top. Press q to get your prompt back.
Now ask the server for its own default page:
curl -s -o /dev/null -w "%{http_code}\n" http://localhost
200
A 200 means Apache is listening and serving. If you get 000 instead, Apache isn’t running at all and step 5 won’t help you, so sort that first.
Step 5: Create a Virtual Host
Apache serves /var/www/html out of the box. That’s fine for a quick test, but a virtual host per site keeps things tidy and turns adding a second domain later into a five minute job.
Create the document root:
sudo mkdir -p /var/www/yourdomain.com/public_html
Hand ownership to your own user so you can deploy files without reaching for sudo every time:
sudo chown -R $USER:$USER /var/www/yourdomain.com/public_html
Drop in a placeholder page so there’s something to look at:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>yourdomain.com</title>
</head>
<body>
<h1>yourdomain.com is live</h1>
</body>
</html>
Then the virtual host itself:
<VirtualHost *:80>
ServerName yourdomain.com
ServerAlias www.yourdomain.com
DocumentRoot /var/www/yourdomain.com/public_html
ErrorLog ${APACHE_LOG_DIR}/yourdomain.com-error.log
CustomLog ${APACHE_LOG_DIR}/yourdomain.com-access.log combined
</VirtualHost>
Enable your site, and disable the default one so it stops catching requests that should be going to yours:
sudo a2ensite yourdomain.com.conf
sudo a2dissite 000-default.conf
Test the configuration before you reload anything. Apache refuses to start on a syntax error, and finding that out now is a good deal more pleasant than finding out during a restart:
sudo apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK
That AH00558 warning turns up even though you’ve set ServerName inside the virtual host, and it’s harmless. There’s a note in the troubleshooting section below if you’d rather silence it.
sudo systemctl reload apache2
reload picks up the new config without dropping existing connections, which is the one to use on a live server. restart also works and is a bigger hammer than you need here.
Verify It Worked
Run this one from your own machine rather than from the server, so you’re testing DNS, the firewall and Apache together rather than just the last of the three:
curl -s http://yourdomain.com
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>yourdomain.com</title>
</head>
<body>
<h1>yourdomain.com is live</h1>
</body>
</html>
If that returns your page, you have a working Apache install serving your domain. Open it in a browser for good measure.
Troubleshooting
AH00558: apache2: Could not reliably determine the server's fully qualified domain name
You’ll see this from configtest even with ServerName set inside your virtual host, because Apache is complaining about the absence of a global one. It’s a warning rather than an error and Apache runs perfectly well with it. If it bothers you, add a line to /etc/apache2/conf-available/servername.conf with ServerName yourdomain.com and enable it with sudo a2enconf servername.
Job for apache2.service failed after install
Usually something else is already sitting on port 80, and nginx is the usual culprit. Find out who:
sudo ss -tlnp | grep ':80'
Stop the other service, or move Apache to a different port, then start Apache again.
403 Forbidden instead of your page
Apache can read /var/www/yourdomain.com/public_html but can’t traverse the directories above it. Check the permissions:
namei -l /var/www/yourdomain.com/public_html/index.html
Every directory in that chain needs to be executable by www-data. sudo chmod 755 /var/www/yourdomain.com usually settles it.
Conclusion
You’ve got Apache serving a virtual host on port 80, which is the right place to stop before adding TLS. The obvious next step is a certificate, and Let’s Encrypt will pick up the ServerName you’ve just set rather than making you type it again.
If something here doesn’t work on your setup, do drop me a line at hello@ubuntutorials.com with the Ubuntu version you’re on and I’ll get it retested.