Apache HTTP Server course

Apache HTTP Server Tutorial: Installation, Website Hosting, Proxies, SSL, and Modules

Learn to install, configure, secure, and troubleshoot Apache HTTP Server on Ubuntu, Debian, and Windows, including virtual hosts, TLS, forward proxies, reverse proxies, and modules.

What Apache HTTP Server Does

Apache HTTP Server is open-source server software that receives HTTP or HTTPS requests and returns web content. It can serve static files such as HTML, CSS, JavaScript, images, and downloads, or forward requests to application backends. The daemon and executable are commonly called httpd.

Apache can operate in several roles:

RoleRequest directionTypical useKey modules or directivesPrimary security concern
Static web serverClient to ApacheDeliver files from a DocumentRootcore, mod_dir, mod_mimeFile permissions and unintended file exposure
Forward proxyClient to external destination through ApacheControlled outbound access for trusted clientsmod_proxy, ProxyRequestsAccidentally creating an open proxy
Reverse proxyClient to Apache to an internal backendPublish web applications and terminate TLSmod_proxy, ProxyPassUnrestricted backend access and spoofed client headers
TLS termination pointEncrypted client connection to ApacheHandle HTTPS before forwarding internallymod_ssl, SSLEngineWeak TLS settings or exposed private keys

Apache's configuration model has several layers: global server settings, loaded modules, virtual hosts, filesystem directory rules, and optional per-directory .htaccess overrides. Central configuration is usually easier to audit and faster than relying on many .htaccess files.

For background, see What Is Apache HTTP Server and What Is a Web Server.

Web and Networking Fundamentals

A browser or other client resolves a hostname through DNS, opens a TCP connection to a server port, sends an HTTP request, and receives an HTTP response. A request contains a method, URL path, protocol version, and headers. A response contains a status code, response headers, and optionally a body.

  • HTTP methods: GET retrieves data, POST submits data, PUT replaces data, PATCH updates part of a resource, and DELETE requests removal. Whether a method is permitted depends on the application and configuration.
  • Request headers: Host, Accept, Authorization, and User-Agent describe the request and client.
  • Response headers: Content-Type, Content-Length, Location, and Cache-Control describe the response.
  • Status codes: 2xx indicates success, 3xx redirection, 4xx a client or access problem, and 5xx a server or backend problem.
  • URL: A URL identifies a scheme such as http or https, hostname, optional port, path, and query string.

Port 80 is the conventional port for HTTP and port 443 is the conventional port for HTTPS. DNS maps names to IP addresses; it does not select an Apache virtual host by itself. After connecting, the browser sends a Host header, which Apache uses with the destination address and port to select a name-based virtual host.

HTTPS is HTTP protected by TLS. During the TLS handshake, Apache presents a certificate, the client validates its chain and hostname, and both sides establish encryption keys. Encryption protects data in transit; it does not automatically make an application or its content trustworthy.

Installing Apache on Ubuntu or Debian

sudo apt update
sudo apt install apache2
sudo systemctl enable --now apache2
sudo systemctl status apache2
sudo apache2ctl configtest

The Linux service is normally named apache2. The executable may be invoked as apache2ctl or httpd, depending on the distribution. A package installation commonly uses these paths:

ItemUbuntu or Debian package installationWindows installationPurpose
Main configuration/etc/apache2/apache2.confconf/httpd.confPrimary server configuration
Virtual-host configuration/etc/apache2/sites-available/ and sites-enabled/Usually included files under conf/Site-specific definitions
Document root/var/www/html by defaultOften htdocs/Public website files
Access log/var/log/apache2/access.loglogs/access.logSuccessful and failed HTTP requests
Error log/var/log/apache2/error.loglogs/error.logStartup, configuration, and runtime errors
Module configuration/etc/apache2/mods-available/ and mods-enabled/LoadModule directives in included configurationFeature extensions

Test locally with curl -I http://localhost/. From another machine, use the server's IP address or DNS name. A firewall must permit inbound TCP traffic on ports 80 and, after TLS configuration, 443. For example, on systems using UFW:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

If local access works but remote access fails, check the server's listening address, host firewall, network firewall, cloud security rules, DNS, and whether the client is using the expected IP.

See Install Apache on Ubuntu for a focused installation guide.

Installing Apache on Windows

Obtain a compatible Apache HTTP Server binary distribution for Windows from a trusted distribution source. Match the build architecture and runtime requirements to the operating system. Extract it to a directory such as C:\Apache24, then inspect conf\httpd.conf. Set paths such as ServerRoot, DocumentRoot, and ServerName to match the installation.

cd C:\Apache24\bin
httpd.exe -t
httpd.exe -k start
httpd.exe -k stop
httpd.exe -k restart
httpd.exe -k install

Run the command prompt with appropriate privileges when installing or controlling a service. Logs are normally under C:\Apache24\logs\. Test with http://localhost/ or curl -I http://localhost/. If Apache reports that it cannot bind to port 80 or 443, identify and stop or reconfigure conflicting software such as another web server, a development stack, or a container publishing the same port.

See Install Apache on Windows.

Service Operation and Validation

Always validate syntax before a reload or restart:

sudo apache2ctl configtest
sudo systemctl status apache2
sudo systemctl reload apache2
sudo systemctl restart apache2
sudo systemctl stop apache2
sudo systemctl start apache2
sudo systemctl enable apache2

A graceful reload causes Apache to reread configuration while allowing existing workers or connections to finish where supported. A full restart stops and starts the service and can interrupt active connections. Use a restart when a changed module or process state requires it; otherwise prefer a validated graceful reload.

Inspect processes and listening sockets with:

sudo ss -tulpn | grep -E ':80|:443'
ps aux | grep '[a]pache2'
sudo journalctl -u apache2 -n 50 --no-pager
sudo tail -f /var/log/apache2/error.log

On Windows, use httpd.exe -t, the Services console, Event Viewer, and the Apache logs directory.

Configuration Structure

Apache directives use a name followed by arguments. Whitespace separates arguments, and a # begins a comment. Directives are valid only in particular contexts, such as server configuration, virtual host, directory, files, or location context. More specific sections can override or refine broader settings, subject to directive rules and inheritance.

The primary file includes other files. On Debian-based systems, /etc/apache2/apache2.conf works with /etc/apache2/ports.conf, configuration fragments in conf-enabled/`, module links in `mods-enabled/`, and virtual-host links in `sites-enabled/. Files in conf-available, mods-available, and sites-available are definitions that are not necessarily active until enabled.

Important contexts include:

  • Listen defines addresses and ports on which Apache accepts connections.
  • VirtualHost groups settings for an address and port combination.
  • ServerName defines the primary hostname; ServerAlias adds names.
  • DocumentRoot identifies the public filesystem directory.
  • Directory controls access and behavior for filesystem paths.
  • Files applies rules to matching filenames.
  • Location applies rules to URL paths, whether or not they map to files.

.htaccess files are read for directories only when the relevant AllowOverride setting permits it. They are useful when users or applications need limited per-directory control, but central configuration is generally preferred because it is more visible, efficient, and easier to validate.

Useful references include Apache2 Conf File, Ports Conf File, Sites Available Directory, Sites Enabled Directory, Mods Available Directory, and Mods Enabled Directory.

Hosting a Basic Static Website

Create a site directory and a simple page:

sudo mkdir -p /var/www/example.test/public
sudo sh -c 'printf "%s\n" "<h1>Example site</h1>" > /var/www/example.test/public/index.html'
sudo chown -R root:root /var/www/example.test
sudo find /var/www/example.test -type d -exec chmod 755 {} \;
sudo find /var/www/example.test -type f -exec chmod 644 {} \;

Apache needs execute permission to traverse directories and read permission for files. The example gives administrators ownership and does not grant Apache general write access. If an application must write uploads or cache data, provide narrowly scoped writable directories rather than making the entire document root writable.

<VirtualHost *:80>
    ServerName example.test
    DocumentRoot /var/www/example.test/public

    <Directory /var/www/example.test/public>
        Require all granted
        Options -Indexes +FollowSymLinks
        AllowOverride None
        DirectoryIndex index.html
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/example.test-error.log
    CustomLog ${APACHE_LOG_DIR}/example.test-access.log combined
</VirtualHost>

Save the definition under sites-available, enable it, validate, and reload:

sudo a2ensite example.test.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
curl -I http://example.test/

Options -Indexes prevents Apache from displaying a directory listing when no index file exists. Access logs record requests, status codes, response sizes, referrers, and user agents. Error logs explain failures such as permission denials, missing files, and startup problems. More detail is available in Log Files: Access Log and Error Log.

Name-Based Virtual Hosting

A virtual host is an Apache configuration block associated with a hostname, port, or address. Multiple names can share one IP address because browsers send the requested hostname in the Host header.

<VirtualHost *:80>
    ServerName example.test
    ServerAlias www.example.test
    DocumentRoot /var/www/example.test/public
    <Directory /var/www/example.test/public>
        Require all granted
        Options -Indexes +FollowSymLinks
        AllowOverride None
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/example.test-error.log
    CustomLog ${APACHE_LOG_DIR}/example.test-access.log combined
</VirtualHost>

<VirtualHost *:80>
    ServerName app.example.test
    DocumentRoot /var/www/app.example.test/public
    <Directory /var/www/app.example.test/public>
        Require all granted
        Options -Indexes
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/app-error.log
    CustomLog ${APACHE_LOG_DIR}/app-access.log combined
</VirtualHost>

DNS records must point both names to the server. Without public DNS, add temporary entries to the client's hosts file, such as 192.0.2.10 example.test app.example.test. Test routing explicitly:

curl -H 'Host: example.test' http://192.0.2.10/
curl -H 'Host: app.example.test' http://192.0.2.10/

Define a safe default virtual host that serves minimal content or rejects unknown names. If no hostname matches, Apache generally uses the first applicable virtual host for that address and port, so ordering matters. See Create New Virtual Host and Default Virtual Host.

Apache as a Forward Proxy

A forward proxy is selected by clients and makes outbound requests on their behalf. It can support controlled egress, testing, or a trusted network policy. It is different from a reverse proxy: a reverse proxy is selected by the public client and hides or fronts backend services.

Enable the required proxy support, then apply an explicit allow policy:

sudo a2enmod proxy proxy_http
sudo systemctl reload apache2
<IfModule mod_proxy.c>
    ProxyRequests On
    <Proxy "*">
        Require ip 192.0.2.0/24
    </Proxy>
</IfModule>

# Use only on a controlled network; do not expose this service publicly.

Configure clients to use the proxy and permit only approved source networks. Combine network firewall restrictions with Apache authorization. Authentication may be added for an explicitly managed user population, but it does not replace network restrictions. Monitor proxy logs and destination patterns. An open proxy is a forward proxy reachable by unauthorized users and can be abused for scanning, fraud, or concealed traffic. See Configure Apache as a Forward Proxy.

Apache as a Reverse Proxy

A reverse proxy accepts public requests and forwards them to an application listening on a private address or port. For example, an application can listen on 127.0.0.1:3000 while Apache handles the public hostname, TLS, logging, and access policy.

sudo a2enmod proxy proxy_http headers
sudo systemctl reload apache2
<VirtualHost *:80>
    ServerName app.example.test
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "http"
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
    ProxyTimeout 60
    ErrorLog ${APACHE_LOG_DIR}/app-proxy-error.log
    CustomLog ${APACHE_LOG_DIR}/app-proxy-access.log combined
</VirtualHost>

ProxyPass maps a URL path to a backend URL. ProxyPassReverse adjusts response headers such as redirects so clients continue to use the public URL. ProxyPreserveHost On passes the original Host header. Applications commonly use X-Forwarded-For, X-Forwarded-Proto, and related headers to understand the original client and scheme; configure trusted proxy handling in the application so clients cannot spoof these values.

For WebSockets, enable the appropriate proxy support and configure the WebSocket path and upgrade handling for the Apache version in use. Set realistic connection and proxy timeouts: excessive values can consume workers, while values that are too short break slow operations. Exclude paths from a broad proxy mapping when Apache must serve local files or administrative endpoints. Confirm the backend is bound only where intended and is not publicly reachable.

TLS commonly terminates at Apache. Apache decrypts the client connection, applies routing and policy, then sends HTTP or separately encrypted HTTPS to the backend. Internal encryption may still be required by policy or network boundaries. See Configure Apache as a Reverse Proxy.

HTTPS and TLS Configuration

A TLS certificate is a signed document containing a public key and identity names. A certificate authority signs it, usually through intermediate certificates that form a certificate chain. The matching private key is secret and allows Apache to establish TLS sessions. Never place private-key contents in a web-accessible directory or include them in support output.

sudo a2enmod ssl
sudo a2ensite default-ssl
sudo apache2ctl configtest
sudo systemctl reload apache2
<VirtualHost *:443>
    ServerName example.test
    DocumentRoot /var/www/example.test/public
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.test/fullchain.pem
    SSLCertificateKeyFile /etc/ssl/private/example.test/privkey.pem
    <Directory /var/www/example.test/public>
        Require all granted
        Options -Indexes +FollowSymLinks
        AllowOverride None
    </Directory>
</VirtualHost>

Use a trusted certificate provider for public websites. A self-signed certificate is appropriate only for controlled testing and will normally produce client warnings. Create an HTTP virtual host that redirects the intended hostname to HTTPS, while considering exceptions needed for health checks or certificate validation. Use current Apache and OpenSSL guidance to disable obsolete protocols and weak algorithms rather than copying outdated cipher lists.

Protect key files with restrictive ownership and permissions, monitor expiration, renew certificates before they expire, and reload Apache after renewal. Test with curl -vk https://example.test/ during diagnosis; omit -k for normal certificate validation. A TLS inspection client can reveal the presented names, expiration, and chain. See Configure SSL.

Modules and Extensibility

Apache's core provides basic server behavior, while loadable modules add capabilities. Common modules include:

  • mod_ssl for TLS.
  • mod_proxy and mod_proxy_http for proxying.
  • mod_rewrite for URL transformations and redirects.
  • mod_headers for request and response headers.
  • mod_auth_basic and authorization modules for authentication and access control.
  • mod_deflate for response compression.
  • mod_status for server status reporting.
apache2ctl -M
sudo a2enmod rewrite
sudo a2dismod autoindex
sudo apache2ctl configtest
sudo systemctl reload apache2

Module dependencies matter: proxying HTTP requires the relevant proxy provider, and TLS requires SSL support. Enable only features required by the deployment. After changing modules, validate syntax and inspect the error log before assuming the reload succeeded.

Logging, Monitoring, and Diagnostics

An access log records handled requests. Common fields include client address, timestamp, request line, status code, response size, referrer, and user agent. An error log records startup messages, configuration failures, permission problems, missing files, proxy failures, and runtime errors.

curl -I http://localhost/
sudo tail -f /var/log/apache2/access.log /var/log/apache2/error.log
sudo apache2ctl -M
sudo ss -tulpn | grep -E ':80|:443'

Increase LogLevel temporarily when investigating a specific problem, then return it to a normal level to avoid excessive volume and sensitive diagnostic exposure. A basic health check can request a small static endpoint and verify the expected status and body. Restrict mod_status and other administrative endpoints to localhost or an administrator network; do not expose operational data publicly.

Status codeMeaningLikely Apache-related causesInitial checks
200SuccessRequest served normallyConfirm content and response headers
301 or 302RedirectHTTP-to-HTTPS rule or application redirectInspect the Location header and redirect loop
403ForbiddenDirectory rule, filesystem permissions, or .htaccess denialRead the error log and check parent-directory traversal
404Not foundWrong DocumentRoot, virtual host, path, or missing fileCheck Host routing, file name, DNS, and per-site log
500Internal server errorInvalid rewrite, application error, or permitted .htaccess problemInspect error log and validate configuration
502Bad gatewayBackend connection or response failureRequest backend directly and inspect proxy errors
503Service unavailableStopped backend, overload, or maintenance policyCheck backend process, capacity, and timeout settings

Security and Operational Practices

  • Update Apache, the operating system, modules, OpenSSL, and certificate tooling.
  • Use least-privilege ownership and permissions. Keep private keys readable only by the required service account or privileged startup process.
  • Do not place secrets, backups, configuration files, or private keys under a public DocumentRoot.
  • Keep directory listing disabled unless it is an intentional, reviewed feature.
  • Restrict administrative endpoints, status pages, proxy clients, and backend networks.
  • Review firewall rules so only necessary ports are exposed.
  • Hide unnecessary server information and avoid publishing detailed error output to clients.
  • Review enabled modules and remove features that the deployment does not need.
  • Rotate and retain logs according to operational and privacy requirements.
  • Test certificate renewal, backups, graceful reloads, and service recovery before an outage occurs.

Troubleshooting Workflow

When a deployment fails, isolate one layer at a time:

  1. Run apache2ctl configtest on Linux or httpd.exe -t on Windows.
  2. Inspect service status, startup output, and the error log.
  3. Check listening sockets and port conflicts with ss or the platform's network tools.
  4. Test locally with curl, then test remotely to separate application, firewall, and DNS problems.
  5. For virtual hosts, send an explicit Host header and inspect the per-site access log.
  6. For a 403, check every parent directory's traversal permission, the applicable Directory rule, and unexpected .htaccess files.
  7. For a 404, verify the selected virtual host, DocumentRoot, requested filename, and DNS or hosts-file mapping.
  8. For a 502 or 503, request the backend directly from the Apache host, verify its process and port, and inspect proxy errors and timeouts.
  9. For TLS errors, verify the hostname, certificate chain, key path, permissions, port 443 virtual host, and certificate expiration.

Frequently Used Directives

DirectivePurposeTypical contextExample use case
ListenBind a port or addressServerListen 80
ServerNameSet the primary hostnameServer or VirtualHostServerName example.test
ServerAliasAdd matching hostnamesVirtualHostServerAlias www.example.test
DocumentRootChoose public filesServer or VirtualHostDocumentRoot /var/www/site/public
DirectoryControl filesystem-path behaviorServer or VirtualHostRequire all granted
VirtualHostGroup site and listener settingsServer<VirtualHost *:80>
ErrorLogSet error-log destinationServer or VirtualHostErrorLog logs/site-error.log
CustomLogSet access-log format and destinationServer or VirtualHostCustomLog logs/site-access.log combined
ProxyPassMap a URL path to a backendServer or VirtualHostProxyPass / http://127.0.0.1:3000/
ProxyPassReverseRewrite backend response location headersServer or VirtualHostProxyPassReverse / http://127.0.0.1:3000/
SSLEngineEnable TLS processingVirtualHostSSLEngine on
SSLCertificateFileSet the certificate or chain pathVirtualHostSSLCertificateFile /path/fullchain.pem
SSLCertificateKeyFileSet the private-key pathVirtualHostSSLCertificateKeyFile /path/privkey.pem

Next Steps

Once the basic server works, study virtual-host defaults, TLS lifecycle automation, URL rewriting, authentication, compression, caching, WebSockets, load balancing, monitoring, and web-application firewalls. The most useful operational habit is consistent: make one change, validate syntax, reload gracefully, test with a client, and read the relevant log.