Containerized infrastructure built from scratch with Docker. A small WordPress site running behind NGINX with TLS, backed by MariaDB — each service in its own container, on a custom network, with persistent volumes. Part of the 42 São Paulo curriculum.
The goal was to build a small production-like setup using only Docker and docker-compose, with one service per container, custom-built images (no pulling pre-baked WordPress / NGINX images from Docker Hub), persistent storage, and a private network between services. The constraints were strict on purpose — every choice had to be deliberate.
┌──────────────┐
client ──▶ │ NGINX (443) │ ──┐
└──────────────┘ │ inception_network
▼ (custom bridge)
┌──────────────────┐
│ WordPress (PHP-FPM) │
└──────────────────┘
│
▼
┌──────────────┐
│ MariaDB │
└──────────────┘
Volumes (host bind mounts):
/home/lmoraes/data/wordpress
/home/lmoraes/data/mariadb
Three services, each built from a custom Dockerfile based on Debian / Alpine. NGINX is the only entrypoint, exposed on 443. WordPress and MariaDB are not reachable from outside the network.
| Service | Role | Notes |
|---|---|---|
| NGINX | Reverse proxy + TLS termination | Self-signed cert, TLS 1.2/1.3 only, forwards PHP requests to wordpress:9000 |
| WordPress | PHP-FPM application | Installed and configured via WP-CLI on first boot |
| MariaDB | Database | Bootstrapped with a custom init script, user and database created from env vars |
- No
:latesttags — every base image is pinned to an explicit version - No pre-built application images — each Dockerfile is written by hand
- Secrets are passed through environment variables, never committed
- All inter-service communication happens on a private custom bridge network
- Data persists across container restarts through bind-mounted host volumes
- Containers auto-restart on failure (
restart: unless-stopped)
Requires Docker and docker-compose. The repo includes a Makefile for the common operations:
make # builds and starts all services
make down # stops the stack
make clean # removes containers, images, and volumes
make re # full rebuildThe site becomes reachable at https://<your-host>/ after the containers boot. Credentials and host paths are configured through an .env file (template included).
.
├── Makefile
└── srcs/
├── docker-compose.yml
├── .env # not committed
└── requirements/
├── nginx/
│ ├── Dockerfile
│ ├── conf/nginx.conf
│ └── tools/
├── wordpress/
│ ├── Dockerfile
│ ├── conf/
│ └── tools/setup.sh
└── mariadb/
├── Dockerfile
├── conf/
└── tools/init.sh
- The difference between a container that boots and a container that is actually ready — and why entrypoint scripts and healthchecks matter more than the Dockerfile itself
- Why
:latestis a footgun in any environment you care about reproducing - How to design a private network so that the database is never reachable from outside, even by mistake
- The pain of bind mounts on permissions when the container user doesn't match the host user
- That secrets in
.envare fine for dev but anything beyond that needs a real secret manager