Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This project has been created as part of the 42 curriculum by Edson Baptista Finda.

Contents

Description

Inception is a project designed to teach how to use Docker, an open-source platform which uses a technology called virtualization to enables the creation of virtual environments on a single physical machine, allowing for more efficient use of resources while keeping the production set up almost intact.

These virtual environments are called containers and they are basically isolated packages containing everything your application needs to run - code, dependencies, configuration, etc. To see how useful containers are, lets imagine a team of developers working in an application, every member of the team would need to have all the dependencies of the application installed and configured in their machines, and since those machines could contain different Operating Systems, the instalation and configuration process could be different for each machine leading to long steps following and errors debuging on n different Operating Systems in the team. On the other hand, since containers are compact, you can easily share them between different Operaing Systems without the need of extra configuration, allowing the team to focus on development work, instead of wasting time on the set up of the development environment.

The project is organized into a mandatory core stack and an extended bonus stack that builds on it.

The mandatory part focuses on deploying a simple web infrastructure composed of Nginx, WordPress, and MariaDB, each running inside its own container. The goal is to obtain a functional website accessible through a secure HTTPS connection, with persistent data stored in a database.

The bonus part extends this infrastructure by adding additional services such as Redis, FTP, and Adminer, as well as a free-choice service (Portainer) and a simple static website (Foco), allowing for deeper exploration of containerized architectures.

Instructions

This repository does not include sensitive configuration files in version control. Running make (or make up) sets both of them up automatically:

  • A .env file inside srcs/, containing the required environment variables. If it doesn't already exist (or is empty), it is created from srcs/.env.example — edit it afterwards with your own values.

  • A secrets/ directory at the root of the project containing the password files used by the services. It is created and filled with strong, randomly generated passwords by scripts/generate_secrets.py, without overwriting any file that already exists.

Before running make, you need to make sure your system has Docker and Docker Compose installed.

If this is your first time running the project, you may need an internet connection so your system can download a few required components. After that, the project can work completely offline.

To launch everything, simply type make in the root folder of the repository. This command will automatically build and start all the services, and the website will be accessible through your browser.

Resources

Here are the main resources that helped me develop this project:

Docker

mariadb

wordpress

nginx

redis

ftp

adminer

foco

AI Usage

During this project, I used several AI tools, including ChatGPT, Grok, and Google Assistant, mainly as learning companions to explore system behavior, validate architectural ideas, and clarify technical concepts.

With prior experience in network programming from the webserv project, I spent a significant amount of time discussing Docker’s internal architecture with AI, particularly the daemon–socket communication model used by dockerd, and its similarities with traditional server designs based on I/O multiplexing mechanisms such as select, poll, and epoll.

Building on the networking fundamentals acquired in the netpractice project, I also used AI to better understand how Docker isolates container networks using namespaces and virtual Ethernet (veth) pairs. These discussions covered inbound and outbound traffic, NAT, port mapping, and how data flows between containers and the host.

AI was especially helpful in clarifying storage concepts, particularly the difference between bind mounts and Docker-managed named volumes, and how named volumes can remain managed by Docker while still being mounted on the host when required.

For service configuration and design, I relied on AI to discuss and validate ideas related to MariaDB initialization strategies, security-related decisions such as user permissions and authentication, and the overall relevance of adding Portainer as an auxiliary service in a containerized infrastructure.

Finally, I also used AI to improve the structure, clarity, and language of the project documentation.

Project description

I have implemented a complete containerized infrastructure that fulfills both the mandatory and bonus requirements of the project. Each service runs inside its own dedicated Docker container, and Docker Compose is used to orchestrate the entire system, allowing services to remain isolated while still communicating when necessary.

Architecture and Services Overview

The infrastructure follows a layered design centered around a web application stack commonly known as a LEMP stack (Linux, Nginx, MariaDB, PHP), which is a widely used architecture in real-world web deployments.

In this project, Nginx serves as the main web server and reverse proxy, handling HTTPS traffic and forwarding requests to WordPress, which represents the application layer responsible for generating dynamic content through php-fpm. MariaDB provides the data layer, storing all persistent information required by the website.

To extend the core infrastructure beyond the basic LEMP setup, several additional services were integrated. Redis is used as a caching layer to improve application performance by reducing database load. FTP provides a controlled way to manage website files remotely, while Adminer offers a lightweight web interface for database administration. Foco, a simple static website was also added to demonstrate how additional web content can coexist alongside the main application. Finally, Portainer was included as an infrastructure management tool, offering visibility into running containers, networks, and volumes.

All services communicate through a private Docker network, which keeps internal traffic isolated from the host system. Only services that require external access expose ports to the host, these being Nginx, FTP, Adminer, Portainer, and Foco. This approach balances accessibility with isolation and reflects common practices used in production-grade containerized environments.

Overall, the architecture is modular and extensible. Both mandatory and bonus services integrate into the same design without altering the core structure, demonstrating how a Docker-based LEMP architecture can scale while maintaining clear separation of concerns.

Sources and Structure

The project repository is structured to keep configuration, orchestration, and service-specific logic clearly separated. This organization follows the layout suggested in the subject and was intentionally designed to make the infrastructure easier to understand, extend, and maintain.

At the root of the repository, a Makefile is provided to automate common tasks such as building images and launching the full infrastructure. The main orchestration logic is defined in srcs/docker-compose.yml, which describes how all services are built, networked, and started together.

All container-related files are grouped under the srcs/requirements/. Each service has its own dedicated folder, named after the service itself, containing its Dockerfile and, when necessary, additional subdirectories:

  • conf/ for configuration files loaded by the service
  • tools/ for initialization scripts or entrypoints

This structure ensures that each service remains self-contained and can be reasoned about independently. Simpler services only include the files they require, avoiding unnecessary complexity.

Mandatory and bonus services follow the same organizational pattern, reinforcing a consistent design across the entire project. Bonus services are grouped under a dedicated srcs/requirements/bonus/ to clearly distinguish them from the core infrastructure while preserving the same architectural principles.

Sensitive data such as passwords is stored in a dedicated directory secrets/, and excluded from version control using a .gitignore file. This prevents confidential information from being pushed to the remote repository and reflects basic security best practices.

Finally, the repository includes three documentation files: README.md, USER_DOC.md, and DEV_DOC.md. Each document targets a different audience and purpose, ranging from a high-level project overview to user interaction guidelines and technical design explanations.

Design Choices and Constraints

The project was designed according to a set of constraints requiring each service to run inside its own container and forbidding the use of pre-built images that already include the target services. This constraint influenced the decision to create custom Dockerfiles for each service and to control their configuration explicitly.

Another key design choice was to keep services isolated while allowing controlled communication between them. This was achieved by relying on Docker Compose networking rather than exposing unnecessary ports to the host. Only services that required external access were made reachable from outside the container network.

Simplicity and clarity were also guiding principles. Startup flags and minimal entrypoint scripts were preferred over extra configuration files whenever possible, especially for services such as MariaDB, where the init-file path is passed directly as a mariadbd flag instead of living in a dedicated .cnf file, and WordPress which allows you to configure global parameters to simplify the interaction with its CLI. This improves maintainability and reduces the risk of unexpected behavior during container startup.

Finally, the infrastructure was designed to be extensible. The addition of bonus services was done without modifying the core architecture, demonstrating that the initial design could scale while preserving separation of concerns.

Virtual Machines vs Docker

Traditional virtual machines virtualize an entire operating system, including its own kernel, which results in higher resource usage and longer startup times. While this approach provides strong isolation, it is often unnecessary for application-level deployment.

Docker, on the other hand, relies on operating system–level virtualization. Containers share the host kernel while isolating applications through namespaces and control groups. This allows containers to start faster, consume fewer resources, and remain lightweight compared to virtual machines.

For this project, Docker was the most suitable choice because the goal was to deploy multiple services that are isolated but still closely integrated. Using containers makes it easier to manage service dependencies, reproduce environments, and scale the infrastructure without the overhead associated with full virtual machines.

Secrets vs Environment Variables

Configuration values in this project are divided between non-sensitive parameters and sensitive data. Non-sensitive configuration, such as usernames, emails, or paths to secret files, is handled using environment variables.

Sensitive information, including passwords, is managed using Docker secrets. Unlike environment variables, which can be exposed through Docker CLI commands or container inspection, secrets are only made available to containers at runtime and are not directly visible through image metadata or configuration output.

By using secrets, credentials are exposed only to the containers that require them and only for the duration of their execution. This reduces the risk of accidental leaks, prevents sensitive data from being committed to version control, and aligns with best practices for secure containerized deployments.

Docker Network vs Host Network

All services in this project communicate through a dedicated Docker-managed network created and managed by Docker Compose. This network allows containers to resolve each other by their names and exchange data without exposing internal traffic to the host system.

Using a Docker-managed network provides isolation between the containerized environment and the host network. It also simplifies service discovery and avoids port conflicts that would arise if all services were bound directly to the host.

The host network is only used for services that must be accessible externally. Port mapping is applied selectively, ensuring that internal services such as databases remain unreachable from outside the container network.

Docker Volumes vs Bind Mounts

Persistent data in this project is stored using Docker-managed named volumes. These volumes ensure that critical data, such as database files and website content, remains available even if containers are stopped, removed, or recreated.

Although these volumes are mounted to specific directories on the host system using driver options, they are not bind mounts. The volumes are still created, tracked, and managed by Docker itself, which means they can be listed, inspected, and managed using Docker CLI commands. This is a key difference from bind mounts, which rely entirely on host-defined paths and are not managed as first-class Docker objects.

By using named volumes with controlled host mappings, the project benefits from both approaches: Docker retains full control over the lifecycle of the data, while the data remains accessible on the host when needed. This design improves portability, simplifies inspection and maintenance, and maintains a clear separation between application logic and persistent storage.

About

A Dockerized LEMP infrastructure (Nginx, WordPress, MariaDB) built from scratch for 42, extended with Redis, FTP, Adminer, Portainer, and a static site — each service in its own container, orchestrated with Docker Compose, served over HTTPS.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages