Ubuntu
Docker
Apache2
Automation
Containerization

How to start apache2 automatically in a ubuntu docker container?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In a Docker container, Apache should start as the main foreground process, not as a background service managed by service or systemd. If you make Apache the container's PID 1 process, it starts automatically whenever the container starts.

Use the Dockerfile to Define the Startup Command

The standard Ubuntu-based approach is:

  1. install Apache during image build
  2. copy your site files or config
  3. run Apache in the foreground with CMD
dockerfile
1FROM ubuntu:24.04
2
3RUN apt-get update \
4    && apt-get install -y apache2 \
5    && rm -rf /var/lib/apt/lists/*
6
7COPY ./site/ /var/www/html/
8
9EXPOSE 80
10
11CMD ["apache2ctl", "-D", "FOREGROUND"]

apache2ctl -D FOREGROUND is the critical part. Containers stop when their main process exits, so Apache must stay in the foreground rather than daemonizing itself.

Build and Run the Container

Once the Dockerfile is in place:

bash
docker build -t ubuntu-apache .
docker run --rm -p 8080:80 ubuntu-apache

Now visiting http://localhost:8080 should hit the Apache server running inside the container.

Why service apache2 start Is the Wrong Pattern

Many Linux tutorials teach service management commands such as:

bash
service apache2 start

That is fine on a full VM or bare Ubuntu server. It is usually the wrong pattern in Docker. If you run it inside a RUN instruction, Apache starts only during image build and is gone by the time the container launches. If you run it in a shell script that backgrounds the process, the container may exit immediately afterward.

The Docker model is simpler:

  • one container
  • one main process
  • process stays in the foreground

Add Your Own Virtual Host Configuration

If you need a custom site, copy a vhost file and enable it during the build:

dockerfile
1FROM ubuntu:24.04
2
3RUN apt-get update \
4    && apt-get install -y apache2 \
5    && rm -rf /var/lib/apt/lists/*
6
7COPY ./000-default.conf /etc/apache2/sites-available/000-default.conf
8COPY ./site/ /var/www/html/
9
10EXPOSE 80
11
12CMD ["apache2ctl", "-D", "FOREGROUND"]

Because 000-default.conf is already the enabled default site, replacing it is often enough for small setups. For more custom layouts, enable modules or sites during the build with commands such as a2enmod rewrite.

Logging and Signals Work Better in Foreground Mode

Running Apache in the foreground also makes Docker behavior cleaner:

  • logs flow to the container output more predictably
  • 'docker stop sends signals to the main process correctly'
  • the container lifecycle matches the web server lifecycle

That is exactly what you want in containerized deployments.

A Small Improvement: Avoid Ubuntu If You Only Need Apache

If the goal is "run Apache," the official Apache or HTTPD image is often simpler than building from raw Ubuntu. Still, if you specifically need Ubuntu because of package compatibility or extra tooling, the pattern above is the correct way to auto-start Apache inside that container.

Common Pitfalls

The most common mistake is starting Apache during docker build. Build steps create image layers, not long-running services.

Another mistake is using service apache2 start and expecting the container to stay alive. Docker only tracks the main foreground process, so background services do not keep the container running.

People also forget to expose or publish the HTTP port. Apache may start correctly, but nothing is reachable outside the container without the right port mapping.

Summary

  • Install Apache in the Docker image and run it with apache2ctl -D FOREGROUND.
  • Make Apache the container's main process so it starts automatically when the container starts.
  • Do not use service apache2 start as the primary Docker startup strategy.
  • Copy site files and Apache config during build, not at runtime by hand.
  • Publish the container port when you run it, for example with -p 8080:80.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.