// Tutorial · Docker · Webserver

Apache httpd: Statische Website einfach hosten

📅 05.09.2026 ⏱ 6 Min. Lesezeit ✍️ Redaktion

Manchmal braucht es keinen Stack – nur eine Website aus HTML, CSS und Bildern. Der offizielle httpd-Container von Apache ist dafür die denkbar einfachste Lösung: ein Image, ein Dokument-Root, fertig. In diesem Tutorial setzt du deine statische Seite mit Docker Compose auf und bindest sie sauber hinter deinen Reverse Proxy ein.

Warum ein httpd-Container?

Statische Seiten brauchen keine Datenbank, keine Laufzeitumgebung und keine Build-Pipeline – nur einen Webserver, der Dateien ausliefert. Der offizielle Apache-httpd-Container übernimmt genau das: klein, ausgereift, seit Jahrzehnten erprobt. Ideal für persönliche Projekte, Landingpages, Dokumentationen oder Testumgebungen.

Container statt System-Apache: Der Dienst läuft isoliert mit eigenem Dokument-Root – wechselst du die Seite, tauschst du den Volume-Inhalt; willst du etwas anderes, löschst du den Container.

Konzept: Dokument-Root & Port

  • Dokument-Root: Apache liefert standardmäßig alles unter /usr/local/apache2/htdocs aus – genau dort hängst du deinen Website-Ordner ein.
  • Port: Im Container lauscht Apache auf Port 80; nach außen bindest du nur 127.0.0.1:50539.
  • Startdatei: Eine index.html im Dokument-Root wird automatisch als Einstiegsseite geliefert.
  • Statisch heißt statisch: Kein PHP, keine Datenbank – für dynamische Seiten brauchst du andere Images (z. B. php:apache).

Vorbereitung: der Website-Ordner

mkdir -p site1/website
cd site1

Legen wir eine minimale Startseite an im terminal nano website/index.html

<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <title>Meine Seite</title>
</head>
<body>
  <h1>Hallo Welt</h1>
  <p>Diese Seite kommt aus dem httpd-Container.</p>
</body>
</html>

In ./website liegen anschließend alle Dateien, die Apache ausliefern soll – Unterordner, Bilder und CSS einfach mit hineinkopieren.

Docker Compose – die Datei

Legen wir die Docker Compose YAML an im terminal nano compose.yaml

services:
  apache:
    image: httpd:latest            # offizielles Image; besser pinnen, z. B. httpd:2.4-alpine
    container_name: website
    restart: always
    ports:
      - "127.0.0.1:50539:80"       # Web nur lokal – der Proxy reicht nach außen
    volumes:
      - ./website:/usr/local/apache2/htdocs
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 1G
  • ./website wird als Dokument-Root gemountet – jede Änderung ist sofort live, ohne Container-Neustart.
  • restart: always startet den Container nach einem Host-Neustart automatisch.
  • Das Image httpd:latest ist großzügig; wer es schlank mag, nimmt httpd:alpine oder pinst eine Version wie httpd:2.4.
  • Aus deiner Vorlage entfernt: leerer networks: {}-Block und network_mode: bridge (Standard) sowie USER_UID/USER_GID – beim offiziellen httpd-Image nicht unterstützt und ohne Funktion.

Konfiguration: was anpassen?

Für reines Ausliefern von HTML ist keine Konfiguration nötig. Willst du Apache weiter anpassen (Module laden, Verzeichnis-Rechte, .htaccess erlauben), mountest du eine eigene, angepasste httpd.conf schreibgeschützt in den Container:

services:
  apache:
    volumes:
      - ./website:/usr/local/apache2/htdocs
      - ./httpd.conf:/usr/local/apache2/conf/httpd.conf:ro   # eigene Konfiguration
Datei komplett übernehmen: Die gemountete httpd.conf ersetzt die Standard-Konfiguration komplett – also als Basis die Konfiguration des Images nutzen und gezielt erweitern (z. B. LoadModule-Zeilen auskommentieren oder ServerName setzen, um die Startwarnung zu vermeiden). Für einfache Seiten gilt: Finger weg, Standard reicht.

Zugriff & Reverse Proxy

Da der Container nur auf 127.0.0.1:50539 lauscht, übernimmt dein Reverse Proxy die Veröffentlichung – so bekommst du HTTPS und saubere Hostnamen, ohne den Apache direkt zu exponiert:

server {
  listen 443 ssl;
  http2 on;
  server_name meine.domain;

  ssl_certificate     /etc/ssl/private/meine.domain/fullchain.cer;
  ssl_certificate_key /etc/ssl/private/meine.domain/meine.domain.key;

  location / {
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      
      # KORREKTUR: Aktiviert Keep-Alive-Verbindungen zum Apache-Container
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      
      proxy_pass http://127.0.0.1:50539;
  }

Alternativ reicht für die lokale Kontrolle: curl http://127.0.0.1:50539 – ohne Proxy erreichst du die Seite nur auf dem Host selbst.

Erster Start & Test

docker compose up -d
docker compose logs apache
  • Test im Browser oder per curl http://127.0.0.1:50539 – du solltest deine index.html sehen.
  • Im Log erscheinen Zugriffe und etwaige Startfehler – bei „AH00558: ServerName“ einfach ServerName localhost in der Config setzen (nur Kosmetik).
  • Dateien änderst du direkt in ./website – ein Neustart ist nicht nötig, nur ein Browser-Refresh.
  • Mehrere Seiten? Einfach mehrere Container mit eigenen Ordnern und Ports – oder ein Image pro Projekt.

Betrieb: Updates & Grenzen

Deine Daten liegen ausschließlich in ./website – ein „Backup“ ist damit schlicht eine Kopie dieses Ordners. Updates ziehst du per docker compose pull && docker compose up -d. Beim Pinnen des Tags (httpd:2.4) bleibst du vor größeren Sprüngen (z. B. 2.4 → 2.6) geschützt, weil du bewusst aktualisierst.

Die vier Merksätze: ① Der Dokument-Root ist /usr/local/apache2/htdocs. ② Statische Seiten brauchen keine Konfiguration. ③ Nach außen geht nur der Proxy – Port bleibt auf localhost. ④ Ein Backup ist die Kopie von ./website.

Häufige Probleme (FAQ)

ProblemLösung
403 ForbiddenRechte prüfen: Der Mount-Pfad muss existieren und für den Container lesbar sein – die Dateien nicht dem Host-User allein „versperren“.
404 statt index.htmlLiegt die Datei direkt in ./website? Apache sucht sie im gemounteten Dokument-Root.
Änderungen erscheinen nichtBrowser-Cache leeren – der Mount greift sofort; ein Neustart des Containers ist nicht nötig.
Port bereits belegtExternen Port ändern (z. B. 50539 → 50550) – der Container-Port 80 bleibt unverändert.
USER_UID/USER_GID wirken nichtErwartet: Das offizielle httpd-Image unterstützt diese Variablen nicht – einfach entfernen.
Seite nur lokal erreichbarGewollt: Der Reverse Proxy (siehe Abschnitt „Zugriff“) muss den Hostnamen auf 127.0.0.1:50539 richten.

Fazit

Wer statische Websites hosten will, braucht keine dicken Images oder komplexe Orchestrierung – der offizielle httpd-Container ist mit einem Mount und einem Port in zwei Minuten einsatzbereit. Und weil die Seite als Volume liegt, bleibt der Container austauschbar: Dateien sind das Produkt, der Webserver nur die Verpackung.

Die vier Merksätze: ① Statisch = kein Konfigurationsaufwand. ② ./website mounten, fertig. ③ Nur der Proxy sieht den Apache. ④ Version pinnen, dann sind Updates gefahrlos.
📝
....

Wir betreiben unsere komplette Infrastruktur selbst auf Open-Source-Software und schreiben nur über Tools, die wir im Alltag wirklich einsetzen. Fragen zum Artikel? Schreib uns.