This project has been created as part of the 42 curriculum by yihakan.
Inception is a 42 system administration project. The goal is to set up a small web infrastructure entirely with Docker, inside a virtual machine. The stack runs three services in three dedicated containers — NGINX (reverse proxy with TLS), WordPress backed by php-fpm, and MariaDB — connected through a custom Docker network and using named volumes for persistent data.
Prerequisites:
- A Linux virtual machine with Docker and Docker Compose installed.
- The host directory
/home/<login>/datamust be writable by your user. - The domain
<login>.42.frmust be mapped to127.0.0.1in/etc/hosts.
Setup:
- Clone the repository on your VM.
- Edit
srcs/.envandMakefileto use your own login (replaceyihakan). - Replace the placeholder passwords in
secrets/*.txtwith strong values. - Add
127.0.0.1 <login>.42.frto/etc/hosts.
Run:
make # build images and start the stack
make ps # list running services
make logs # follow container logs
make down # stop and remove containers
make fclean # full cleanup (containers, images, volumes, host data)
make re # full rebuild
Open https://<login>.42.fr in your browser. The certificate is self-signed, so
accept the security warning. The WordPress admin panel lives at
https://<login>.42.fr/wp-admin.
Reference material used while building this project:
- Docker docs — https://docs.docker.com
- Docker Compose specification — https://docs.docker.com/compose/compose-file/
- Alpine Linux package index — https://pkgs.alpinelinux.org
- WordPress installation guide — https://wordpress.org/documentation/article/how-to-install-wordpress/
- WP-CLI handbook — https://make.wordpress.org/cli/handbook/
- NGINX TLS configuration — https://nginx.org/en/docs/http/configuring_https_servers.html
- MariaDB documentation — https://mariadb.com/kb/en/documentation/
AI usage: AI was used as a learning aid for the following tasks:
- Drafting the initial Dockerfiles and the entrypoint scripts, then reviewed and adjusted manually to match the subject constraints (no infinite loops, secrets via files, PID 1 behaviour).
- Explaining how php-fpm communicates with NGINX over fastcgi.
- Comparing options for "named volume vs bind mount" and validating the
driver: local+o: bindapproach used here. Every AI suggestion was tested and reviewed; nothing was copy-pasted blindly.
This project relies on Docker to virtualize three independent services. Each service
has its own Dockerfile (built from Alpine 3.20), its own image, and its own
container. They communicate on the user-defined inception bridge network. NGINX is
the only entrypoint exposed to the host, on port 443 only, using TLSv1.2 / TLSv1.3.
srcs/docker-compose.yml— orchestrates the three services, theinceptionnetwork, the named volumes and the secrets.srcs/.env— non-sensitive configuration (domain name, database name, usernames).srcs/requirements/<service>/— Dockerfile, configuration files and entrypoint script for each service.secrets/*.txt— passwords, mounted into containers via Docker secrets at/run/secrets/<name>. Ignored by Git.
- Alpine 3.20 as the base image for all services: small footprint, fast builds.
- Docker secrets for every password. No password is written in any Dockerfile,
compose file, or
.env. - Custom bridge network (
inception). Service-to-service communication is done by container name (mariadb,wordpress). - Named volumes with
driver: localando: bindso the data lives in/home/<login>/data/{mariadb,wordpress}on the host while still being a Docker named volume. - WP-CLI to install WordPress and create the two required users (admin + author)
during first boot only — the entrypoint exits as soon as setup is done and
execs php-fpm in the foreground.
Virtual Machines vs Docker. A VM virtualizes hardware and runs a full guest kernel, which makes it heavy and slow to boot. A Docker container shares the host kernel and isolates only the user space (namespaces, cgroups), so it is much lighter and faster, but less isolated than a VM.
Secrets vs Environment Variables. Environment variables are visible in
docker inspect, in /proc/<pid>/environ, and are easily logged. Docker secrets
are mounted as files inside /run/secrets/, restricted to the services that
declare them, and not exposed by docker inspect. Passwords in this project are
loaded from secrets at startup; only non-sensitive values live in .env.
Docker Network vs Host Network. With network: host, a container shares the
host network namespace — port collisions are possible and there is no network
isolation. A user-defined Docker network (bridge) gives each container its own IP
and DNS-resolvable hostname, isolates traffic, and lets us expose only what we
want (here, port 443 of NGINX).
Docker Volumes vs Bind Mounts. A bind mount maps an arbitrary host path into a
container; the host owns the path and Docker doesn't manage it. A named volume is
managed by Docker (lifecycle, listing, drivers) and is portable. We use named
volumes whose data still lives under /home/<login>/data thanks to the local
driver with o: bind — this satisfies the subject requirement while keeping
Docker as the owner of the volume.