Apache Httpd 2.4
Videos
Overview: Apache HTTP Server 2.4 on Azure: overview (watch on YouTube)
Launch and log in: Apache HTTP Server 2.4 on Azure: launch and log in (watch on YouTube)
Deep Dive: Apache HTTP Server 2.4 on Azure: deep dive (watch on YouTube)
Overview
This guide shows how to deploy and use Apache HTTP Server 2.4 on Ubuntu 24.04 LTS from SecureAnyCloud on Microsoft Azure.
Apache HTTP Server is a widely used open source web server. It serves static sites, hosts many sites on one server with virtual hosts, and sits in front of application servers as a reverse proxy. This image runs Apache 2.4 from Ubuntu's own noble repository (the apache2 package), so Ubuntu updates it like any other system package. Image version 1.0.20260425 carries Apache 2.4.58 on Ubuntu 24.04 LTS.
Every command and output in this guide comes from a virtual machine deployed from the public Marketplace image (image version 1.0.20260425), using the azureuser account that customers get.
What you get: the Ubuntu package plus the following SecureAnyCloud setup.
- Modules for modern sites. The event MPM, with
ssl,http2,rewrite,headers,proxyandproxy_httpturned on. - Two default virtual hosts. One on port 80 and one on port 443, both serving
/var/www/html. Directory listings are off. - A certificate for each VM. At first boot,
apache-firstboot.servicecreates a new self-signed RSA 2048-bit certificate and key for that VM, so HTTPS works from the start and no two VMs share a key. Replace the certificate with a real one before you serve real visitors (Step 9). - A hardened Server header.
/etc/apache2/conf-available/zz-security-sac.confsetsServerTokens Prod,ServerSignature OffandTraceEnable Off. Responses say onlyServer: Apache, andTRACErequests are refused.
The document root starts empty, and you add your own site in Step 5. Until you do, Apache answers 403 Forbidden for /, because there is no index page and directory listings are switched off.
What's included
- Apache HTTP Server 2.4.58 (image version 1.0.20260425) from Ubuntu's
noblerepository:apache2andapache2-utils
- The event MPM and the
ssl,http2,rewrite,headers,proxyandproxy_httpmodules, turned on
- Default virtual hosts
000-sac.conf(port 80) and000-sac-ssl.conf(port 443), document root/var/www/html
- The first-boot service
apache-firstboot.service, which makes the VM's own certificate in/etc/ssl/sac/
- The hardening file
zz-security-sac.conf
- Ubuntu 24.04 LTS with unattended security upgrades turned on
- Azure Linux Agent (
waagent) and cloud-init for Azure provisioning
- 24/7 SecureAnyCloud support
PHP, a WAF module and a publicly trusted certificate are not included: you add what your site needs.
Connecting to your VM
Item Value
SSH user the administrator you choose at deployment (for example azureuser)
Website http://<vm-ip>/ and https://<vm-ip>/ once your network security group allows 80 and 443
Document root /var/www/html
Configuration /etc/apache2/ (sites-available/, conf-available/, mods-available/)
Logs /var/log/apache2/
Open ports needed 22 (SSH) from your own address; 80 and 443 from the networks your visitors use
Apache has no login of its own, so the image has no web password to look up. The notes file /stage/scripts/apache-credentials.log holds a short description of the certificate set-up and no password.
Prerequisites
- An Azure subscription and an SSH public key
- For the command line route, the Azure CLI on your workstation, signed in with
az login
- A network security group that allows TCP 22 from your own address, and TCP 80 and 443 from your visitors
Choose a virtual machine size that suits your traffic. Apache with the event MPM is light, so a small VM is a reasonable starting point. You can resize later.
Deploy from the Azure portal
On the listing, choose Get it now. In the Azure portal, set your subscription, resource group, region and size, your SSH key and the inbound ports, then choose Review and create. For inbound ports, allow SSH (22), HTTP (80) and HTTPS (443). When the VM exists, narrow SSH to your own address in the network security group.
Deploy from the Azure CLI
Create a resource group and a network security group that allows SSH from your own address and web traffic from everyone. If only your own networks should see the site, put their ranges in place of Internet:
az group create --name myResourceGroup --location eastus
az network nsg create --resource-group myResourceGroup --name my-apache-nsg
az network nsg rule create --resource-group myResourceGroup --nsg-name my-apache-nsg \
--name allow-ssh --priority 100 --protocol Tcp --access Allow \
--source-address-prefixes <your-ip>/32 --destination-port-ranges 22
az network nsg rule create --resource-group myResourceGroup --nsg-name my-apache-nsg \
--name allow-web --priority 110 --protocol Tcp --access Allow \
--source-address-prefixes Internet --destination-port-ranges 80 443The image has a Marketplace purchase plan. Accept its terms once per subscription, then create the virtual machine. Replace <your-vm-size> with the size you chose:
az vm image terms accept --urn sac1647283583153:apache-httpd-ubuntu-24-04:default:latest
az vm create \
--resource-group myResourceGroup \
--name my-apache-vm \
--image sac1647283583153:apache-httpd-ubuntu-24-04:default:latest \
--size <your-vm-size> \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--nsg my-apache-nsg \
--public-ip-sku StandardConnect via SSH
On your own workstation, find the public IP address, then connect:
az vm show --resource-group myResourceGroup --name my-apache-vm --show-details --query publicIps -o tsv ssh azureuser@<vm-ip>If you connect right after the VM starts, wait for first boot to finish:
sudo cloud-init status --waitIt prints status: done.
Check Apache
systemctl is-active apache2 apache-firstboot.service apache2 -v sudo ss -Htln '( sport = :80 or sport = :443 )' | awk '{print $4}'Both services report active, the version line reads Server version: Apache/2.4.58 (Ubuntu), and Apache listens on *:80 and *:443.
curl -s -o /dev/null -w 'http://localhost/ -> HTTP %{http_code}\n' http://localhost/
curl -sk -o /dev/null -w 'https://localhost/ -> HTTP %{http_code}, HTTP/%{http_version}\n' https://localhost/On a new VM both return HTTP 403, the HTTPS one over HTTP/2: Apache is answering, and the document root is still empty. The next step adds a page.
Publish your first page
Put your site's files in /var/www/html. Write an index page, then fetch it:
echo '<h1>It works on Azure</h1>' | sudo tee /var/www/html/index.html curl -s http://localhost/ curl -sk -o /dev/null -w 'HTTP %{http_code}, HTTP/%{http_version}\n' https://localhost/The page comes back over HTTP, and HTTPS returns HTTP 200, HTTP/2. From your workstation, open http://<vm-ip>/ in a browser. https://<vm-ip>/ works too, with a certificate warning until you install a real certificate (Step 9).
To publish a whole site, copy its files into /var/www/html, for example with scp or rsync over SSH. Keep them readable by the www-data user that Apache runs as.
How the configuration is laid out
Apache on Ubuntu keeps each site, module and configuration fragment in its own file, and turns them on with symbolic links:
Directory Holds Turn on / off
/etc/apache2/sites-available/ virtual hosts sudo a2ensite <name> / sudo a2dissite <name>
/etc/apache2/mods-available/ modules sudo a2enmod <name> / sudo a2dismod <name>
/etc/apache2/conf-available/ configuration fragments sudo a2enconf <name> / sudo a2disconf <name>
List what is turned on:
sudo apache2ctl -S 2>/dev/null | head -3 sudo apache2ctl -M 2>/dev/null | grep -E '^ (ssl|rewrite|headers|http2|proxy|proxy_http|mpm_event)_module' ls /etc/apache2/conf-enabled/apache2ctl -S lists the two SecureAnyCloud virtual hosts, *:443 from 000-sac-ssl.conf and *:80 from 000-sac.conf. The module list shows headers, http2, mpm_event, proxy, proxy_http, rewrite and ssl, and conf-enabled includes zz-security-sac.conf.
After any change, test the configuration, then reload Apache. A reload drops no connections:
sudo apache2ctl configtest
sudo systemctl reload apache2configtest prints Syntax OK when the configuration is valid.
Host a site with a name-based virtual host
To serve a domain from its own directory, give it a virtual host. Replace example.com with your domain:
sudo mkdir -p /var/www/example.com echo '<h1>example.com</h1>' | sudo tee /var/www/example.com/index.html
sudo tee /etc/apache2/sites-available/example.com.conf >/dev/null <<'EOF' <VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com <Directory /var/www/example.com> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/example.com-error.log CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined </VirtualHost> EOF
sudo a2ensite example.com
sudo apache2ctl configtest
sudo systemctl reload apache2Check it before your DNS points at the VM by sending the host name yourself:
curl -s -H 'Host: example.com' http://localhost/
curl -s http://localhost/The first request gets the new site (<h1>example.com</h1>), and any other name still gets the default site in /var/www/html. Once your domain's DNS A record points at the VM's public IP, browsers reach the new site by name.
Put Apache in front of an application
The proxy and proxy_http modules are already on, so Apache can pass requests to an application that listens on the VM, for example on 127.0.0.1:8080:
sudo tee /etc/apache2/sites-available/app.example.com.conf >/dev/null <<'EOF' <VirtualHost *:80> ServerName app.example.com ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ </VirtualHost> EOF
sudo a2ensite app.example.com && sudo apache2ctl configtest && sudo systemctl reload apache2 curl -s -H 'Host: app.example.com' http://localhost/With an application answering on port 8080, the last command returns the application's response through Apache. Keep the application on 127.0.0.1 so it is reachable only through Apache, and leave its port closed in the network security group.
HTTPS and a real certificate
The first-boot certificate
First boot made this VM its own self-signed certificate:
sudo cat /var/log/apache-firstboot.log
sudo ls -l /etc/ssl/sac/
sudo openssl x509 -in /etc/ssl/sac/sac.crt -noout -subject -dates -ext subjectAltName
sudo openssl x509 -in /etc/ssl/sac/sac.crt -noout -text | grep -m1 'Public-Key'The log shows the certificate being generated at first boot, the key sac.key is readable by root only (mode 600), the subject is CN = sac-apache with the names localhost, sac-apache and 127.0.0.1, it is valid for one year from first boot, and the key is Public-Key: (2048 bit). First boot runs once: a reboot keeps the same certificate.
Browsers do not trust a self-signed certificate and show a warning. Use it for testing only, and install a real certificate for your domain with one of the two options below.
Option A: a free Let's Encrypt certificate with Certbot
You need a domain whose DNS A record points at the VM's public IP, a virtual host with that ServerName (Step 7), and port 80 open to the internet (Let's Encrypt checks the domain over HTTP). Install Certbot and its Apache plugin from Ubuntu's repository:
sudo apt-get -q update
sudo apt-get install -y certbot python3-certbot-apache certbot --versionIt prints certbot 2.9.0 on Ubuntu 24.04. Then request the certificate for your names:
sudo certbot --apache -d example.com -d www.example.comCertbot's Apache plugin proves you control the domain, installs the certificate in an HTTPS virtual host for those names, and reloads Apache. The package also turns on certbot.timer, which renews certificates before they expire:
systemctl is-enabled certbot.timer
sudo certbot renew --dry-runOption B: your own certificate
To use a certificate from your own certificate authority, copy the certificate (with its chain) and the key onto the VM, keep the key readable by root only, and point the HTTPS virtual host at them. The default HTTPS site reads these two lines:
grep -E 'SSLCertificate(Key)?File' /etc/apache2/sites-available/000-sac-ssl.confThey read SSLCertificateFile /etc/ssl/sac/sac.crt and SSLCertificateKeyFile /etc/ssl/sac/sac.key. Change them to your files (or add the same two lines to your own *:443 virtual host), then run sudo apache2ctl configtest and sudo systemctl reload apache2.
Check the hardening
curl -sI http://localhost/ | grep -i '^Server:' grep -hE '^(ServerSignature|TraceEnable)' /etc/apache2/conf-enabled/zz-security-sac.conf
curl -s -o /dev/null -w 'TRACE -> HTTP %{http_code}\n' -X TRACE http://localhost/The header reads Server: Apache, with no version or operating system, the file shows ServerSignature Off and TraceEnable Off, and a TRACE request gets HTTP 405. The zz- prefix makes the file load after Ubuntu's own security.conf, so its settings win: keep the name.
Keep it updated and running
The image was patched when it was built. Ubuntu security updates install automatically because unattended-upgrades is enabled. Other updates do not, so update a new VM before you put it into service, and update it regularly afterwards:
sudo apt-get -q update
sudo apt-get -y upgradeApache is an Ubuntu package, so Apache updates arrive this way too. Reboot if a new kernel was installed.
Everyday service commands:
sudo systemctl status apache2 --no-pager sudo systemctl reload apache2
sudo systemctl restart apache2
sudo tail -n 50 /var/log/apache2/error.log
sudo tail -n 50 /var/log/apache2/access.logThe default HTTPS site logs to error-ssl.log and access-ssl.log in the same directory, and Ubuntu's logrotate rotates the Apache logs. Before a big change, take a snapshot of the OS disk, and back up /etc/apache2/ and your sites under /var/www/.
Security notes
- Network security group. Allow SSH (22) from your own address only. Open 80 and 443 to the networks your visitors use. The Ubuntu firewall (
ufw) is installed but inactive, so the network security group is what filters traffic.
- Use a real certificate (Step 9) before you serve real visitors. Once HTTPS works with it, you can redirect HTTP to HTTPS and add a
Strict-Transport-Securityheader with theheadersmodule.
- Keep applications behind Apache. Bind them to
127.0.0.1and reach them through a proxy virtual host (Step 8).
- A web application firewall is not included. Ubuntu's
libapache2-mod-security2package adds ModSecurity if you need one.
When you have finished with the examples, remove them:
sudo a2dissite example.com app.example.com
sudo systemctl reload apache2
sudo rm -r /var/www/example.com /etc/apache2/sites-available/example.com.conf /etc/apache2/sites-available/app.example.com.confServer components
Component Path
Apache daemon /usr/sbin/apache2 (apache2.service)
Main configuration /etc/apache2/apache2.conf
Default virtual hosts /etc/apache2/sites-available/000-sac.conf, 000-sac-ssl.conf
Hardening /etc/apache2/conf-available/zz-security-sac.conf
Document root /var/www/html
First-boot certificate and key /etc/ssl/sac/sac.crt, sac.key
First-boot service and log apache-firstboot.service, /usr/local/sbin/apache-firstboot.sh, /var/log/apache-firstboot.log
Logs /var/log/apache2/
Support and licensing
Apache HTTP Server is licensed under the Apache License 2.0. SecureAnyCloud provides round-the-clock technical support for this image by email, with a guaranteed 24-hour response time: sales@secureanycloud.com.
Apache, Apache HTTP Server and the Apache feather logo are trademarks of The Apache Software Foundation. Ubuntu is a registered trademark of Canonical Ltd. SecureAnyCloud is not affiliated with or endorsed by either of them.
Deploy on Azure
Launch Apache HTTP Server 2.4 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com