Apache in Docker uses the official httpd image. The image is bare-bones — no PHP, no fancy modules pre-enabled beyond the defaults — so the recipes split into "static site server" (which works out of the box) and "do something more" (which means mounting a custom config or switching to a related image like php:apache).
How do I run Apache in Docker?
Serve the current directory as a static site:
docker run -d --name apache \
-p 8080:80 \
-v "$(pwd):/usr/local/apache2/htdocs:ro" \
httpd:2.4Visit http://localhost:8080 — anything in the host directory is served.
Configure version, port, and the directory to serve.
Mount a custom httpd.conf
The image's config lives at /usr/local/apache2/conf/httpd.conf. To override:
docker run -d --name :container_name
-p :host_port:80
-v "$(pwd)/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro"
-v ":site_dir:/usr/local/apache2/htdocs:ro"
httpd::httpd_versionStart from the image's own config as a base — copy it out first:
docker run --rm httpd::httpd_version cat /usr/local/apache2/conf/httpd.conf > httpd.confThen edit locally and mount it back in.
Enable mod_rewrite (for .htaccess)
mod_rewrite is built into the image but not loaded by default. Without it, .htaccess files with RewriteRule are silently ignored. Two changes to the config:
# Uncomment this line
LoadModule rewrite_module modules/mod_rewrite.so
# In the <Directory "/usr/local/apache2/htdocs"> block, change
AllowOverride None
# to
AllowOverride AllAfter mounting the edited config and restarting, .htaccess rules work.
Run as non-root
The official httpd image runs as root by default and starts worker processes as www-data. For a tighter setup, the httpd:2.4-alpine variant is smaller; for a non-root-by-default option, the bitnami/apache image is the common pick (listens on 8080 by default, runs entirely as user 1001).
Pair with PHP
For Apache plus PHP (a common LAMP stack), don't try to install PHP into the httpd image — use the php:apache image, which is httpd with mod_php baked in:
docker run -d --name app
-p :host_port:80
-v "$(pwd):/var/www/html"
php:8.4-apacheDocument root is /var/www/html. PHP files in the bind-mounted directory just work.
Reverse proxy with mod_proxy
Less common than Nginx for reverse-proxy duty, but Apache can do it via mod_proxy:
ProxyPreserveHost On
ProxyPass / http://app:3000/
ProxyPassReverse / http://app:3000/mod_proxy is built in; load it the same way as mod_rewrite. For new reverse-proxy setups, Nginx or Caddy are more common picks; Apache fits when you already have Apache modules in play.
Compose example
services:
apache:
image: httpd::httpd_version
ports:
"::host_port:80"
volumes:
./site:/usr/local/apache2/htdocs:ro
./httpd.conf:/usr/local/apache2/conf/httpd.conf:ro
restart: unless-stoppedCommon pitfalls
.htaccessignored.mod_rewritenot loaded, orAllowOverride Nonefor the document root. Fix both inhttpd.conf.- 404 on
index.php. Wrong image — the plainhttpdimage has no PHP. Usephp:VERSION-apache. - Permission errors on bind mount. Apache reads as
www-data(UID 33). Ensure the host directory is world-readable, or run the file mounts read-only with:ro. - Port 80 in use on the host. Pick a different host port (
-p 8080:80). - Editing httpd.conf and not seeing changes. Either the bind mount isn't pointing where you think, or you need to restart the container (
docker restart :container_name). Apache doesn't reload config without a restart orapachectl gracefulinside the container.
FAQ
httpd:2.4 is plain Apache, no PHP. php:8.4-apache is Apache plus PHP plus mod_php pre-wired. For static sites or reverse-proxy use, the plain image is fine; for PHP sites, the combined image saves you from installing PHP into the httpd image yourself.
Two reasons combined: mod_rewrite is not loaded in the default config, and AllowOverride None on the document-root directory tells Apache to skip .htaccess files entirely. Load the module and set AllowOverride All in httpd.conf.
/usr/local/apache2/htdocs/. The php:apache image is different — it uses /var/www/html/.
Yes. Use <VirtualHost *:80> blocks in your config, mount the per-site document roots, and use ServerName to route. Beyond two sites, a reverse-proxy approach (one container per app, Nginx or Traefik in front) is more flexible.
docker exec :container_name apachectl graceful performs a graceful restart — workers finish their current requests, then re-read the config. For non-graceful: docker restart :container_name.
Sources
Authoritative references this article was fact-checked against.
- Official Apache httpd image — Docker Hubhub.docker.com
- Apache httpd 2.4 documentationhttpd.apache.org





