A Debian web server starts quickly with Apache because the default repositories already include the Apache HTTP Server as the apache2 package. Debian does not use the Red Hat-style httpd package or httpd.service unit, so to install Apache on Debian 13 (trixie), Debian 12 (bookworm), or Debian 11 (bullseye), install apache2 and verify apache2.service before opening web traffic.
The base install serves Debian’s default Apache page immediately and includes helper commands such as apache2ctl. From there, the workflow moves into UFW firewall rules, name-based virtual hosts, Let’s Encrypt certificates, status checks, log review, updates, removal, and common startup or permission fixes.
Install Apache on Debian
Update Debian Packages Before Apache
Refresh the APT package index and apply available package updates before installing a network service. The -y flag confirms the upgrade prompt so the command can run without stopping for input.
sudo apt update && sudo apt upgrade -y
These commands use
sudobecause package installation and service management need root privileges. If your account is not ready for sudo yet, follow the Debian guide to add a user to sudoers on Debian.
Install Apache2 Package on Debian
Install the apache2 package from Debian’s default repositories. This package installs the web server, default site configuration, helper commands, and the systemd service unit.
sudo apt install apache2 -y
Debian does not use a separate httpd package or httpd.service unit for Apache. Use apache2 for package operations and apache2.service for service commands.
Check Apache Package Versions on Debian
Debian’s default APT sources currently provide Apache 2.4.66 across the supported releases. The full package revision differs by Debian release and security pocket, which is why package-manager output is more precise than a rounded upstream version number.
| Debian Release | Codename | Current apache2 Candidate | Package Source |
|---|---|---|---|
| Debian 13 | trixie | 2.4.66-1~deb13u2 | trixie/main |
| Debian 12 | bookworm | 2.4.66-1~deb12u1 | bookworm/main |
| Debian 11 | bullseye | 2.4.66-1~deb11u1 | bullseye-security/main |
Verify Apache Service on Debian
Use sudo apache2ctl -v for the version check. Debian places Apache helper commands under /usr/sbin, and that directory may not appear in a regular user’s shell PATH.
If you see /usr/sbin/apachectl in service output or older Apache references, it comes from the same Debian Apache package. Use apache2ctl in Debian commands because that name matches Debian’s package and service naming.
sudo apache2ctl -v
Debian 13 currently reports Apache 2.4.66 from the default package sources:
Server version: Apache/2.4.66 (Debian) Server built: 2026-03-01T13:26:45
Debian 12 and Debian 11 also report Apache 2.4.66 at the moment, but the build date and package revision differ by release.
Check the systemd unit next. The --no-pager flag keeps the status output in the terminal instead of opening an interactive pager.
systemctl status apache2 --no-pager
A working install shows the service enabled and active:
● apache2.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: active (running) since [date] [time] UTC; 2min ago
Docs: https://httpd.apache.org/docs/2.4/
Process: 1234 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 1235 (apache2)
Tasks: 55 (limit: 4915)
Memory: 12.5M
CPU: 150ms
CGroup: /system.slice/apache2.service
├─1235 /usr/sbin/apache2 -k start
├─1236 /usr/sbin/apache2 -k start
└─1237 /usr/sbin/apache2 -k start
Debian 12 and Debian 11 may show /lib/systemd/system/apache2.service instead of the newer /usr/lib/systemd/system/apache2.service path. The important checks are the same: the unit is loaded, enabled, and active.
If the service is inactive, start Apache and enable it for future boots in one step. The --now flag starts the service immediately after enabling it.
sudo systemctl enable apache2 --now
At this point, Apache is listening on port 80 and can serve the default Debian landing page or your own virtual hosts.
Configure UFW Firewall for Apache on Debian
Install UFW for Apache on Debian
UFW is optional on Debian, but it is a practical way to open only the ports Apache needs on a public server. Install UFW from the default repositories, or use the dedicated guide to install UFW on Debian if you want broader firewall setup and removal details.
sudo apt install ufw -y
The -y flag accepts the package transaction prompt automatically.
Enable UFW Without Blocking SSH on Debian
Allow SSH before enabling UFW if you manage the server remotely. Otherwise, the firewall can close your current session before the Apache rules are in place.
If you changed the SSH port, replace
sshwith your actual port rule, such assudo ufw allow 2222/tcp, before enabling the firewall.
sudo ufw allow ssh
Enable UFW after the SSH rule exists. The --force flag skips the interactive confirmation prompt.
sudo ufw --force enable
Expected output:
Firewall is active and enabled on system startup
By default, UFW denies incoming connections and allows outgoing connections. Apache still needs explicit HTTP and HTTPS rules before visitors can reach the site.
Check Apache UFW Profiles on Debian
UFW application profiles give you named shortcuts for common ports. Filter the profile list to the web and SSH entries so the useful lines are easier to read.
sudo ufw app list | grep -E 'Apache|WWW|OpenSSH|SSH'
Relevant output on Debian 13 includes both Apache and legacy WWW profile names:
Apache
Apache Full
Apache Secure
OpenSSH
SSH
WWW
WWW Cache
WWW Full
WWW Secure
Debian 12 and Debian 11 show the WWW profiles instead:
OpenSSH
SSH
WWW
WWW Cache
WWW Full
WWW Secure
Use Apache Full on Debian 13 or WWW Full on Debian 12 and Debian 11 when you want both HTTP port 80 and HTTPS port 443 open.
Allow Apache HTTP and HTTPS Through UFW
Choose the rule that matches how the site will be served. Most public sites should open both ports because HTTP requests usually redirect to HTTPS after certificates are configured.
To allow HTTP (Port 80) only:
# Debian 13:
sudo ufw allow 'Apache'
# Debian 12/11:
sudo ufw allow 'WWW'
For HTTPS (Port 443) only:
# Debian 13:
sudo ufw allow 'Apache Secure'
# Debian 12/11:
sudo ufw allow 'WWW Secure'
For both HTTP and HTTPS:
# Debian 13:
sudo ufw allow 'Apache Full'
# Debian 12/11:
sudo ufw allow 'WWW Full'
Verifying UFW Firewall Rules
Check the active firewall rules after adding the web profile:
sudo ufw status
Debian 13 shows Apache Full when both web ports are open:
Status: active To Action From -- ------ ---- 22/tcp ALLOW Anywhere Apache Full ALLOW Anywhere 22/tcp (v6) ALLOW Anywhere (v6) Apache Full (v6) ALLOW Anywhere (v6)
Debian 12 and Debian 11 show WWW Full for the same HTTP and HTTPS access:
Status: active To Action From -- ------ ---- 22/tcp ALLOW Anywhere WWW Full ALLOW Anywhere 22/tcp (v6) ALLOW Anywhere (v6) WWW Full (v6) ALLOW Anywhere (v6)
Both profile names allow visitors to reach Apache over HTTP and HTTPS.
Test the Apache Default Page
After configuring UFW, verify that a browser can reach the Apache default page. Use your server’s IP address first:
http://your_server_ip
For local installations or testing on the same machine where Apache is installed, use localhost, which points to 127.0.0.1:
http://localhost
A working install shows the Debian Apache2 default landing page.

Create Virtual Hosts for Apache HTTP
Name-based virtual hosts let one Apache instance serve separate domains from separate document roots. The example below uses example.com; replace that domain everywhere with your real hostname.
Create and Set Permissions for Apache Directories
Apache serves /var/www/html by default. Keep that directory as the fallback site, then create a separate document root for example.com.
Create a document root for the example domain:
sudo mkdir -p /var/www/example.com/html
Assign ownership to your current user with the $USER environment variable. The shell expands $USER before sudo runs, so the directory becomes editable by your account while Apache can still read it.
sudo chown -R "$USER":"$USER" /var/www/example.com
Setting ownership to your user account makes static-site editing easier. For production applications where Apache, PHP, or another service writes files, use the ownership model required by that application instead of applying one rule to every site.
Verify the correct permissions are set for the web root:
ls -l /var/www/
The output should show the new site directory and the default web root:
drwxr-xr-x 3 username username 4096 [date] example.com drwxr-xr-x 2 root root 4096 [date] html
If the directory is not readable and searchable by Apache, correct the directory permissions:
sudo chmod 755 /var/www/example.com /var/www/example.com/html
Create a sample index.html page with nano:
nano /var/www/example.com/html/index.html
Paste the following HTML content:
<html>
<head>
<title>Welcome to example.com</title>
</head>
<body>
<h1>Success! The example.com virtual host is working.</h1>
</body>
</html>
After writing, save the file (CTRL+O), then exit (CTRL+X).
Create a Virtual Host for Apache HTTP
Create a virtual host configuration file under /etc/apache2/sites-available/:
sudo nano /etc/apache2/sites-available/example.com.conf
Paste this HTTP-only virtual host, replacing the domain names and document root if your site uses different values:
<VirtualHost *:80>
ServerAdmin webmaster@example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/html
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
The ServerName directive handles the primary host, ServerAlias covers the www name, and DocumentRoot points Apache at the directory created earlier.
After setting the configuration, save the file (CTRL+O) and exit (CTRL+X).
Activate the Apache HTTP Virtual Host
Enable the new virtual host with Apache’s helper commands. a2ensite and a2dissite manage the symbolic links under /etc/apache2/sites-enabled/ for you.
Disable the default site if this server should answer with your new virtual host instead:
sudo a2dissite 000-default.conf
Enable the new virtual host:
sudo a2ensite example.com.conf
Test your configuration for syntax errors before reloading Apache:
sudo apache2ctl configtest
A successful test ends with:
Syntax OK
You may also see an AH00558 fully qualified domain name warning before Syntax OK. That warning does not mean the virtual host syntax failed; the troubleshooting section below covers the fix.
If there are errors, Apache shows the exact file and line number:
AH00526: Syntax error on line 3 of /etc/apache2/sites-enabled/example.com.conf: Invalid command 'DocuemntRoot', perhaps misspelled
Reload Apache to activate the new virtual host without dropping established connections:
sudo systemctl reload apache2
Apache should now serve the custom landing page when requests match example.com or www.example.com. If DNS is not ready yet, test locally with a temporary hosts-file entry or a request that sends the correct Host header.

Create a Let’s Encrypt SSL Certificate for Apache
Use Let’s Encrypt after the HTTP virtual host works and your domain points at the server. Certbot can read the Apache virtual host, request the certificate, and add the HTTPS redirect automatically. For renewal troubleshooting and advanced options, use the dedicated guide to secure Apache with Let’s Encrypt on Debian.
Install the Apache Certbot Plugin
Install the Apache plugin for Certbot from Debian’s default repositories:
sudo apt install python3-certbot-apache -y
Generate the SSL Certificate
Request a certificate for both the apex domain and the www hostname. Replace the email address and domains before running the command.
sudo certbot --apache --agree-tos --redirect --email you@example.com -d example.com -d www.example.com
The main options do the following:
--apache: Uses Certbot’s Apache plugin to find and update the matching virtual host.--redirect: Adds an HTTP-to-HTTPS redirect after the certificate is issued.-d: Adds each domain name that should appear on the certificate.
Add stronger options such as HSTS only after you confirm the HTTPS site is correct. HSTS tells browsers to keep using HTTPS for the domain, so a mistaken rollout can linger for visitors.
Validating SSL Configuration
After Certbot succeeds, the site should load over https://example.com and https://www.example.com. Requests to the old HTTP URL should redirect to HTTPS because the command used --redirect.
Open the site in a browser and check that the address bar shows HTTPS without certificate warnings. If the browser still shows HTTP, recheck DNS, the virtual host names, and the Certbot output.
Automating SSL Certificate Renewal
Let’s Encrypt certificates last 90 days. Debian’s Certbot package installs automated renewal through a systemd timer or cron job, but a dry run confirms that renewal can still complete with your current Apache configuration.
Run a renewal dry run with:
sudo certbot renew --dry-run
A successful dry run means Certbot can renew the certificate path without waiting for the real expiry window.
Monitoring Your Apache HTTP Service
Apache exposes enough status and log data to catch most configuration, traffic, and permission problems before they become outages.
Configure Apache mod_status
Debian enables the Apache status module during a default install. If it was disabled later, enable it again with:
sudo a2enmod status
The status module provides a local status page with live worker and request information. Edit its configuration before exposing it beyond localhost:
sudo nano /etc/apache2/mods-enabled/status.conf
You should see a configuration block like this:
<Location /server-status>
SetHandler server-status
Require local
</Location>
By default, Require local restricts access to local connections such as 127.0.0.1. To allow a trusted address, use Require ip followed by that IP address. Avoid Require all granted on production servers because the status page exposes sensitive runtime information.
Checking Apache Server Status
Access the status page from an allowed address:
http://your_server_ip/server-status
The status page shows details such as:
- The number of workers serving requests
- The number of idle workers
- The current CPU usage
- Details about the requests being processed
Configuring Apache Log Files
Apache writes logs under /var/log/apache2/. Debian keeps that directory readable by root and the adm group, so most one-off checks should use sudo.
- Access log (
/var/log/apache2/access.log): Records each request served by the web server. - Error log (
/var/log/apache2/error.log): Records startup, configuration, permission, and request-processing errors.
Use these logs first when a virtual host returns the wrong page, a permission problem causes 403 errors, or Apache fails to reload.
Tips for Managing Your Apache HTTP Web Server
The day-to-day commands below cover log review and service control after Apache is installed.
Understanding Apache Server Logs
Apache logs are the fastest way to diagnose broken virtual hosts, unexpected status codes, and suspicious traffic. The examples below use common command-line tools; the generic tail command guide and grep command guide cover the flags in more depth.
Review Recent Log Entries
Use tail with sudo to check recent log entries:
sudo tail /var/log/apache2/access.log
sudo tail /var/log/apache2/error.log
Monitor Logs in Real-Time
Watch logs in real-time while troubleshooting:
sudo tail -f /var/log/apache2/error.log
Search for Specific Errors
Use grep to find specific error codes or patterns:
sudo grep "404" /var/log/apache2/error.log
sudo grep -c "500" /var/log/apache2/error.log
Identify Unique IP Addresses Accessing the Server
Use awk, sort, and uniq to list unique IP addresses from the access log:
sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq
To identify the top 10 IP addresses by request volume:
sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -10
These checks are intentionally simple. For heavier traffic analysis, use a log analyzer or ship Apache logs into your monitoring stack.
Manage Apache HTTP Service Commands
Use these systemctl commands for routine Apache service control:
Stopping the Apache Web Server:
sudo systemctl stop apache2
Starting the Apache Web Server:
sudo systemctl start apache2
Restarting the Apache Web Server:
Use restart for major changes (module installation, MPM changes):
sudo systemctl restart apache2
Reloading the Apache Web Server:
Use reload for configuration changes (virtual hosts, .htaccess) without dropping active connections:
sudo systemctl reload apache2
Disabling Apache on Server Boot:
sudo systemctl disable apache2
Enabling Apache on Server Boot:
This is typically enabled by default upon installation:
sudo systemctl enable apache2
Update and Remove Apache
Regular maintenance keeps Apache on the current Debian security build. The commands below update only the Apache package, then show a removal path that separates package removal from site-data cleanup.
Update Apache HTTP
Refresh APT metadata before checking for Apache updates:
sudo apt update
To update only Apache without upgrading all packages on your system, use the --only-upgrade flag:
sudo apt install --only-upgrade apache2
The --only-upgrade flag upgrades apache2 only if it is already installed. Back up important virtual host files before upgrading production servers, then verify the package version and service state:
sudo apache2ctl -v
systemctl status apache2 --no-pager
Remove Apache HTTP
If you enabled UFW rules only for Apache, remove those web rules before uninstalling the package. Keep UFW itself installed if it protects SSH or other services. Replace the profile name if you opened only HTTP or only HTTPS earlier.
# Debian 13:
sudo ufw delete allow 'Apache Full'
# Debian 12/11:
sudo ufw delete allow 'WWW Full'
Stop Apache first if you are removing it from an active server:
sudo systemctl stop apache2
Remove the main Apache package with APT. Review APT’s package list before confirming, especially on desktop systems where Apache can be tied to sharing helpers or other local services.
sudo apt remove apache2
Review optional dependency cleanup separately. On reused desktop or VM systems, sudo apt autoremove can also target unrelated old kernels or helpers, so read the package list before confirming.
sudo apt autoremove
To remove Apache package configuration files as well, purge the Apache package split:
sudo apt purge apache2 apache2-bin apache2-data apache2-utils
Verify that the Apache package split is no longer installed:
dpkg -l apache2 apache2-bin apache2-data apache2-utils 2>/dev/null | grep '^ii'
A removed package set returns no matching installed-state lines. If you purged the packages, dpkg -l may show no package rows or uninstalled states instead.
The next cleanup command permanently deletes the example virtual host, its web files, and optional
servername.conffile created earlier. Back up any real website files before removing a production document root.
If you followed the virtual host example and no longer need those files, remove them explicitly:
sudo rm -rf /var/www/example.com
sudo rm -f /etc/apache2/sites-available/example.com.conf
sudo rm -f /etc/apache2/sites-enabled/example.com.conf
sudo rm -f /etc/apache2/conf-available/servername.conf
sudo rm -f /etc/apache2/conf-enabled/servername.conf
Confirm the example files are gone:
sudo find /var/www /etc/apache2 \( -path '*example.com*' -o -name 'servername.conf' \) -print 2>/dev/null
No output means the example document root, site files, and optional ServerName configuration were removed.
Troubleshooting Common Apache Issues
When Apache does not behave as expected, start with the exact service, log, or configuration error instead of changing multiple settings at once.
Apache Fails to Start: Port Already in Use
If Apache fails to start, check the service status for the first error message:
sudo systemctl status apache2
If the status output mentions Address already in use or could not bind to address, another service is using port 80 or 443. Find the listener with ss:
sudo ss -ltnp 'sport = :80'
The output shows which program is using the port:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=12345,fd=6))
In this example, Nginx is using port 80. Stop the conflicting service before starting Apache:
sudo systemctl stop nginx
sudo systemctl start apache2
403 Forbidden: Permission Denied Errors
When you see 403 Forbidden in a browser, Apache may not be able to read the website files or the virtual host may deny access. Check the error log first:
sudo tail -20 /var/log/apache2/error.log
Look for lines containing “Permission denied” or “AH01630”. A typical permission error looks like:
[timestamp] [authz_core:error] [pid 1234] [client 192.168.1.100:54321] AH01630: client denied by server configuration: /var/www/example.com/html/
Verify the web directory ownership and permissions:
ls -la /var/www/example.com/html/
The output should show files readable by Apache. The owner may be your user account for static files or www-data for applications that need Apache or PHP to write content:
drwxr-xr-x 2 username username 4096 [date] . drwxr-xr-x 4 root root 4096 [date] .. -rw-r--r-- 1 username username 174 [date] index.html
If permissions are incorrect for the static example site, fix them with:
sudo chown -R "$USER":"$USER" /var/www/example.com
sudo chmod 755 /var/www/example.com /var/www/example.com/html
sudo chmod 644 /var/www/example.com/html/index.html
Configuration Syntax Errors
Test Apache syntax before reloading the service. A syntax error can prevent Apache from starting or reloading cleanly:
sudo apache2ctl configtest
A successful test shows:
Syntax OK
A configuration error shows the exact file and line number:
AH00526: Syntax error on line 8 of /etc/apache2/sites-enabled/example.com.conf: Invalid command 'DocuemntRoot', perhaps misspelled or defined by a module not included in the server configuration
This indicates line 8 has a typo: “DocuemntRoot” should be “DocumentRoot”. Open the file and correct the error:
sudo nano /etc/apache2/sites-available/example.com.conf
Apache Shows AH00558 ServerName Warning
A fresh Apache install often prints this warning during apache2ctl configtest:
AH00558: apache2: Could not reliably determine the server's fully qualified domain name Syntax OK
The final Syntax OK line means the configuration parsed successfully. To suppress the warning, set a global ServerName value and enable that small configuration file:
printf '%s\n' 'ServerName example.com' | sudo tee /etc/apache2/conf-available/servername.conf > /dev/null
sudo a2enconf servername
sudo apache2ctl configtest
sudo systemctl reload apache2
Virtual Host Shows Default Page Instead of Your Site
When a browser shows the Apache default page instead of your custom site, the virtual host may not be enabled or the requested host name may not match the configured ServerName. Verify enabled sites:
ls -la /etc/apache2/sites-enabled/
You should see your configuration file as a symbolic link:
lrwxrwxrwx 1 root root 39 [date] example.com.conf -> ../sites-available/example.com.conf
If missing, enable it and reload Apache:
sudo a2ensite example.com.conf
sudo systemctl reload apache2
Also verify that ServerName and ServerAlias match how you access the site. If you type example.com in your browser but the configuration only names www.example.com, Apache may route the request to the wrong virtual host.
Check Apache Error Logs for Other Issues
For issues that do not match the cases above, read the latest Apache errors:
sudo tail -50 /var/log/apache2/error.log
To watch errors appear in real-time while you test in another terminal or browser:
sudo tail -f /var/log/apache2/error.log
Press Ctrl+C to stop watching the log.
Additional Security Considerations
SSL certificates and firewall rules are only the baseline for a public web server. Add a web application firewall with ModSecurity for Apache on Debian when you host applications that need request filtering, and use Fail2ban on Debian to ban repeated hostile requests from Apache or SSH logs.
For remote administration, enable SSH on Debian with key-based authentication before relying on the server from another machine. For dynamic sites, install PHP on Debian, add a database with the MariaDB installation guide for Debian, or deploy a full site with WordPress with Apache on Debian.
Conclusion
Apache is running on Debian with a verified service unit, firewall rules, virtual host structure, and an HTTPS path through Let’s Encrypt. From here, add application support with PHP and MariaDB, or compare the stack with Install Nginx on Debian if an event-driven web server fits your workload better.
Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>