{"id":31585049,"url":"https://github.com/alx-sch/inception","last_synced_at":"2026-04-06T09:33:35.282Z","repository":{"id":316076183,"uuid":"1059406440","full_name":"alx-sch/inception","owner":"alx-sch","description":"Use Docker to build and orchestrate containerized services: A WordPress web server backed by a MariaDB database.","archived":false,"fork":false,"pushed_at":"2025-11-05T22:35:44.000Z","size":1132,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-06T00:18:14.409Z","etag":null,"topics":["42inception","42projects","docker","docker-compose","docker-network","mariadb","nginx","wordpress"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alx-sch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-18T12:01:59.000Z","updated_at":"2025-11-05T22:35:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"ece73cf0-d9de-42bb-8d4b-ae67e750f2b9","html_url":"https://github.com/alx-sch/inception","commit_stats":null,"previous_names":["alx-sch/inception"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alx-sch/inception","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alx-sch%2Finception","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alx-sch%2Finception/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alx-sch%2Finception/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alx-sch%2Finception/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alx-sch","download_url":"https://codeload.github.com/alx-sch/inception/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alx-sch%2Finception/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31466629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["42inception","42projects","docker","docker-compose","docker-network","mariadb","nginx","wordpress"],"created_at":"2025-10-06T01:26:46.289Z","updated_at":"2026-04-06T09:33:35.273Z","avatar_url":"https://github.com/alx-sch.png","language":"Dockerfile","readme":"# Inception: A Dockerized Web Application Stack\n\n# WIP!!!! NOT FINISHED YET!\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\".assets/inception_badge.png\" alt=\"inception_badge.png\" /\u003e\n\u003c/p\u003e\n\nThis project focuses on system administration and containerization with **Docker**. The goal is to build a multi-container application using **Docker Compose**, featuring separate containers for an NGINX web server, a MariaDB database and a WordPress instance.\n\nThe following features were implemented as well:\n- **Redis caching** with a custom **Redis Explorer** for monitoring cached data.\n- **Adminer** for efficiently inspecting and managing the MariaDB database.\n- **FTP** for handling files in the WordPress PHP-FPM volume.\n- A **static website** built with HTML and CSS.\n\nAll services are built from scratch using custom `Dockerfiles` and communicate securely over a dedicated Docker network.\n\n---\n\n## Table of Contents\n\n- [The Project](#the-project-a-dockerized-web-application-stack)\n     - [Technology Stack](#technology-stack)\n     - [Architecture \u0026 Request Flow](#architecture-and-request-flow)\n     - [How To Use?](#how-to-use)\n- [Docker Introduction](#docker-introduction)\n    - [What is Docker?](#what-is-docker)\n    - [History](#a-bit-of-history)\n    - [Container vs VM](#containers-vs-virtual-machines)\n    - [Applications](#applications)\n- [Deep Dive](#docker-deep-dive)\n    - [Docker Components](#docker-components)\n    - [Docker Workflow](#docker-workflow)\n    - [Docker File](#the-dockerfile)\n    - [Docker Compose](#XXX)\n    - [Docker Commands](#docker-commands)\n    - [Total Cleanup](#total-cleanup)\n- [Setting Up the VM](#setting-up-the-vm)\n- [Setting Up Inception](#setting-up-inception)\n\n---\n\n## The Project\n\nIn this project, I containerize a full-stack web application using Docker. The goal is to learn about system administration, container orchestration and the architecture of modern web services by setting up a WordPress site with NGINX and a MariaDB database from scratch, without using pre-existing official images. The entire stack is deployed within a Debian virtual machine, creating a fully isolated and production-like server environment from the ground up. \n\nThis project emphasizes the importance of isolated environments and the automation of service deployment. By using Docker, it is ensured that the application is portable, scalable and runs consistently across any environment. The `docker-compose.yml` file serves as the master blueprint, defining and connecting the individual services on a private network to form a single, cohesive application.\n\n---\n\n### Technology Stack\n- **Host Environment:** Virtual Machine running Debian 13 (Trixie)\n- **Orchestration:** Docker \u0026 Docker Compose\n- **Web Server / Reverse Proxy:** NGINX with TLSv1.3\n- **Application:** WordPress with PHP-FPM\n- **Database:** MariaDB\n- **Automation:** Makefile\n\n---\n\n### Architecture and Request Flow\n\nThe \"big picture\" of the Inception application is an orchestrated stack of services, each running in its own isolated container. All communication between services happens over a private Docker network, with NGINX being the sole public-facing entry point.\n\n```\n+----------+      HTTPS     +-------------+      HTTP      +----------------+      SQL       +-------------+\n|          | -------------\u003e |             | -------------\u003e |                | -------------\u003e |             |\n|  User's  |                |    NGINX    |                |   WordPress    |                |   MariaDB   |\n|  Browser | \u003c------------- | (Port 443)  | \u003c------------- |   (PHP-FPM)    | \u003c------------- | (Database)  |\n|          |      HTML      |             |      HTML      |                |      Data      |             |\n+----------+                +-------------+                +----------------+                +-------------+\n  ^                                |                                |                              |\n  |                                |                                |                              |\n  +--------------------------------+--------------------------------+------------------------------+\n                                       (Data stored in persistent Docker Volumes)\n```\n\n#### Step-by-Step Breakdown:\n\n1. **The User Arrives (Browser -\u003e NGINX)**\n   - A user opens their web browser and types in your address (e.g., `https.aschenk.42.fr`).\n   - This request travels across the internet and hits your server. **The only container exposed to the outside world is NGINX.** It acts as the front door, security guard and receptionist all in one (a reverse proxy).\n   - NGINX receives the `HTTPS` request. Its first job is **TLS Termination**. It handles the complex encryption/decryption, so WordPress doesn't have to.\n\n3. **The Hand-off (NGINX -\u003e WordPress)**\n   - After decrypting the request, NGINX looks at its configuration. It sees that requests for this domain should be handled by the WordPress service.\n   - It then forwards a simple, unencrypted `HTTP` request over the **private Docker network** to the WordPress container. The WordPress container is not exposed to the internet; it only talks to NGINX.\n\n5. **The Brain at Work (WordPress -\u003e MariaDB)**\n   - The WordPress container receives the request. It's running a PHP processor (`PHP-FPM`) which executes the WordPress application code.\n   - WordPress determines what content is needed to build the page (e.g., the latest blog posts, comments, page content). This data is not in the WordPress container; it's in the database.\n   - WordPress opens a connection to the MariaDB container, again over the private Docker network. It connects using the predefined configuration (hostname, database user, database to access, etc.).\n  \n4. **The Vault Opens (MariaDB -\u003e WordPress)**\n    - The MariaDB container receives the SQL query from WordPress (e.g., `SELECT * FROM wp_posts...`).\n    - It executes the query, gathers the results and sends the data back to the WordPress container. Like WordPress, the MariaDB container is completely isolated from the internet. It only talks to WordPress.\n\n5. **The Assembly and Return (WordPress -\u003e NGINX -\u003e Browser)**\n   - WordPress receives the data from MariaDB. The PHP engine uses this data to assemble the final HTML page.\n   - WordPress sends the complete, rendered HTML page back to NGINX.\n   - NGINX receives the plain HTML, re-encrypts it for `HTTPS` and sends it back across the internet to the user's browser.\n   - The user's browser renders the HTML and they see the beautiful website :)\n\n---\n\n### How to Use?\n\nXXX\n\n---\n\n## Docker Introduction\n\n### What is Docker?\n\nDocker is a platform for developing, shipping and running applications in **containers**. A Docker container can hold any application and its dependencies (code, libraries, system tools, configuration) and run on any machine that has Docker installed.    \n\nThis solves the classic problem of \"it works on my machine\" by packaging the entire application environment into a single, predictable and portable unit.\n\n---\n\n### A Bit of History\n\nDocker was first introduced by Solomon Hykes at PyCon 2013 -- check out his legendary five-minute minute talk [here](https://www.youtube.com/watch?v=wW9CAH9nSLs)\u003csup\u003e\u003ca href=\"#footnote1\"\u003e[1]\u003c/a\u003e\u003c/sup\u003e.     \nOriginally an internal project at his PaaS company dotCloud, it was quickly open-sourced once its potential became clear.\n\nWhile Docker popularized containers, the underlying technology has been part of the Linux kernel for years in the form of **cgroups** (which limit resource usage) and **namespaces** (which isolate processes, filesystems, etc.)\u003csup\u003e\u003ca href=\"#footnote2\"\u003e[2]\u003c/a\u003e\u003c/sup\u003e.    \n\nDocker’s innovation was to create a user-friendly set of tools, a strong community and useful services (public registries, ready-made base images and orchestration tools like Compose and Kubernetes), making those kernel features approachable for everyday developers.\n\n---\n\n### Containers vs. Virtual Machines\n\nA common point of confusion is the difference between a container and a virtual machine (VM):\n\n- **A VM** virtualizes the hardware. It runs a full-blown guest operating system with its own kernel on top of your host OS. Think of it as a complete, separate house with its own plumbing, electricity and foundation.\n  \n- **A Docker Container** virtualizes the operating system. All containers on a host share the host's OS kernel but have their own isolated view of the filesystem and processes. Think of them as apartments in a single building: They all share the building's main foundation and utilities but are completely separate living spaces.\n\nThis makes containers incredibly lightweight, fast to start and efficient compared to VMs.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\".assets/vm-vs-docker.png\" alt=\"vm-vs-docker.png\"  width=\"600\" /\u003e\n    \u003cbr\u003e\n     \u003cspan\u003e\n        \u003cb\u003eVMs (left):\u003c/b\u003e Use a hypervisor (managing virtual hardware), include full guest OS.\u003cbr\u003e\n        \u003cb\u003eContainers (right):\u003c/b\u003e Use Docker engine, share the host OS, isolate at process level\u003csup\u003e\u003ca href=\"#footnote8\"\u003e[8]\u003c/a\u003e\u003c/sup\u003e.\n    \u003c/span\u003e\n\u003c/p\u003e\n\n---\n\n### Applications\n\nDocker is the standard way modern applications are built, shipped and run\u003csup\u003e\u003ca href=\"#footnote3\"\u003e[3\u003c/a\u003e,\u003ca href=\"#footnote4\"\u003e4]\u003c/sup\u003e. Common applications are:\n\n- **Standardized Development Environments**       \n    By packaging an application and its dependencies into a container, companies ensure that their software runs identically everywhere: on a developer's laptop, on a testing server and in production.\n\n- **CI/CD Pipelines**        \n   Docker is a cornerstone of modern **Continuous Integration and Continuous Deployment (CI/CD)**. When a developer pushes new code, automated systems use Docker to:\n    1. Build the code inside a clean, consistent container.\n    2. Run automated tests inside that container.\n    3. If tests pass, push the new container image to a registry.\n    4. Automatically deploy the updated container to production servers.\n \n- **Microservices Architecture**      \n    Docker is the perfect platform for microservices, an architectural style where a large application is broken down into smaller, independent services. Each microservice (e.g., user authentication, payment processing, product catalog) runs in its own container. This makes the application easier to develop, scale and maintain, as different teams can work on different services independently.\n\n- **Cloud and Multi-Cloud Deployment**     \n    Docker containers can run on any cloud provider (AWS, Google Cloud, Azure, etc.) without modification. This portability gives companies the freedom to move applications between different cloud environments without being locked into a single vendor. It's the foundation of modern \"cloud-native\" applications.\n\n---\n\n## Docker Deep Dive\n\n### Docker Components\n\nOverview of multiple Docker components\u003csup\u003e\u003ca href=\"#footnote5\"\u003e[5]\u003c/a\u003e\u003c/sup\u003e:\n\n- **Docker Engine:** The core of Docker. It's a client-server application with three main components: a long-running background service called the **Docker daemon**, a **REST API** that specifies interfaces for programs to talk to the daemon and the **Docker client**.\n \n- **Docker Client:** The primary way users interact with Docker. It's the command-line interface (CLI) tool (e.g., `docker run`, `docker build`) that sends commands to the Docker daemon.\n \n- **Docker Registries:** A storage and distribution system for Docker images. **Docker Hub** is the default public registry, but companies often host private ones for their own images.\n  \n- **Docker Images:** Read-only, executable blueprints that contain everything needed to run an application: the code, a runtime, libraries, environment variables and configuration files.\n  \n- **Dockerfile:** A text file containing a set of instructions on how to build a Docker image. The `docker build` command reads this file to assemble the image layer by layer.\n\n- **Docker Volumes:** The mechanism for persisting data generated by Docker containers. Volumes are managed by Docker and exist outside the container's lifecycle, ensuring your data is safe even if the container is removed.\n\n- **Docker Compose:** A tool for defining and running multi-container applications. It uses a single YAML file (`docker-compose.yml`) to configure all of the application's services, networks and volumes, which can then be started or stopped with a single command.\n\n\u003cbr\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\".assets/docker-engine.png\" alt=\"docker-engine.png\"  width=\"400\" /\u003e\n    \u003cbr\u003e\n     \u003cspan\u003e\n        \u003cb\u003eDocker Engine:\u003c/b\u003e Running a Docker command in the CLI, it communicates with the daemon via a REST API (locally over a Unix socket or TCP). The daemon then manages images, containers, networks and volumes\u003csup\u003e\u003ca href=\"#footnote9\"\u003e[9]\u003c/a\u003e\u003c/sup\u003e.\n    \u003c/span\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\".assets/docker-architecture.png\" alt=\"docker-architecture.png\"  width=\"400\" /\u003e\n    \u003cbr\u003e\n     \u003cspan\u003e\n        \u003cb\u003eDocker Architecture:\u003c/b\u003e The Docker client (CLI) communicates with the Docker Engine on the host to run containers using images, which are often stored and pulled from a registry like Docker Hub.\u003cbr\u003e\n        \u003cb\u003eNGINX:\u003c/b\u003e Web server or reverse proxy; often used to route traffic to containers or load-balance requests.\u003cbr\u003e\n        \u003cb\u003eDocker Hub:\u003c/b\u003e Public container registry (orange logo); stores and distributes Docker images.\u003cbr\u003e\n        \u003cb\u003eOpenStack:\u003c/b\u003e Cloud platform for managing virtual machines, storage and networks; can host Docker infrastructure but is separate from Docker itself.\u003csup\u003e\u003ca href=\"#footnote8\"\u003e[8]\u003c/a\u003e\u003c/sup\u003e.\n    \u003c/span\u003e\n\u003c/p\u003e\n\n---\n\n### Docker Workflow\n\n1. You write a **Dockerfile**, a text file containing instructions to build a Docker image.   \n2. You use the **Docker Client** (`docker build`) to send these instructions to the **Docker Daemon**.\n3. The Docker Daemon executes the instructions, creating a **Docker Image**. This image is a lightweight, stand-alone, executable blueprint of your application's environment.\n4. You use the Docker Client (`docker run`) to tell the Docker Daemon to create and start a **Container** from that image. The container is a live, running instance of your application.\n\n**Docker Compose** streamlines and automates this workflow, especially for applications with multiple services:\n\n1. You write a Dockerfile for each service (e.g., one for your web server, one for your database).\n2. You create a single `docker-compose.yml` file. In this file, you define all your services, tell Compose where to find each service's Dockerfile and describe how they should be connected (e.g., networking, volumes).\n3. You use the **Docker Compose CLI** (`docker-compose up`) to send the entire application definition to the Docker Daemon.\n4. The Docker Daemon then reads the `docker-compose.yml file` and:\n    - **Builds** a Docker Image from each Dockerfile (if it doesn't already exist).\n    - **Creates and starts** a Container from each image, automatically **connecting** them on a shared network so they can communicate.\n\nDocker Compose acts as an orchestrator for the Docker Engine, allowing you to manage the entire build-and-run lifecycle for a multi-container application with a single command.\n\n----\n\n### The Dockerfile\n\nText-based document that is used to create a container image. As an example, the following Dockerfile would produce a ready-to-run Python application\u003csup\u003e\u003ca href=\"#footnote7\"\u003e[7]\u003c/a\u003e\u003c/sup\u003e:\n\n```Dockerfile\nFROM python:3.13\nWORKDIR /usr/local/app\n\n# Install the application dependencies\nCOPY requirements.txt ./\nRUN pip install --no-cache-dir -r requirements.txt\n\n# Copy in the source code\nCOPY src ./src\nEXPOSE 5000\n\n# Setup an app user so the container doesn't run as the root user\nRUN useradd app\nUSER app\n\nCMD [\"uvicorn\", \"app.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8080\"]\n```\n\nA Dockerfile typically follows these steps:\n\n1. Determine your base image\n2. Install application dependencies\n3. Copy in any relevant source code and/or binaries\n4. Configure the final image\n\nSome of the most common instructions in a `Dockerfile` include:\n\n- `FROM \u003cimage\u003e` - this specifies the base image, so what you start with. This could be a minimal OS to build on or a ready-to-use image for a specific application.\n- `WORKDIR \u003cpath\u003e` - this instruction specifies the \"working directory\" or the path in the image where files will be copied and commands will be executed.\n- `COPY \u003chost-path\u003e \u003cimage-path\u003e` - this instruction tells the builder to copy files from the host and put them into the container image.\n- `RUN \u003ccommand\u003e` - this instruction tells the builder to run the specified command.\n- `ENV \u003cname\u003e \u003cvalue\u003e` - this instruction sets an environment variable that a running container will use.\n- `EXPOSE \u003cport-number\u003e` - this instruction sets configuration on the image that indicates a port the image would like to expose.\n- `USER \u003cuser-or-uid\u003e` - this instruction sets the default user for all subsequent instructions.\n- `ENTRYPOINT [\"\u003cexecutable\u003e\", \"\u003cparam1\u003e\"]` - this sets the main command. It typically executes a script or a binary, but can also be a command.\n- `CMD [\"\u003ccommand\u003e\", \"\u003carg1\u003e\"]` - this instruction sets the default command a container using this image will run. This can be overridden when providing a command when starting the container (`docker run my-image \u003cCMD\u003e`).\n\nNote: When multiple `ENTRYPOINT` and `CMD` are specified in a Dockerfile, all but the very last are ignored.\n\n---\n\n### Docker Compose\n\nXXXXX\n\n---\n\n### Docker Commands    \n\nThe most common Docker commands you'll use with a `Dockerfile` are for building an image from the file and running a container based on that image\u003csup\u003e\u003ca href=\"#footnote6\"\u003e[6]\u003c/a\u003e\u003c/sup\u003e:\n\n- `docker build`     \n  This command builds a Docker image from a `Dockerfile` and a \"context\". The context is the set of files at the path specified (in this case, `.`).\n  \n  ```bash\n  docker build -t your-image-name:tag .\n  ```\n  \n  - `-t`: This flag stands for **\"tag\"**. It allows you to name your image and give it a version tag (e.g., `my-app:1.0`). If you don't provide a tag, it defaults to `latest`.\n  - `your-image-name:tag`: The name and tag you choose for your image.\n  - `.`: The period specifies the **build context**. It tells Docker to use the current directory's files for the build.\n\n- `docker run`    \n  Once your image is built, you use this command to start a container from it.\n  \n  ```bash\n  docker run -d -p 8080:80 your-image-name:tag\n  ```\n  \n  - `-d`: Runs the container in **detached mode** (in the background). Without this, your terminal will be attached to the container's log output.\n  - `-p 8080:80`: The **port mapping** flag. It maps port `8080` on your host machine to port `80` inside the container. The format is `HOST_PORT:CONTAINER_PORT`.\n  - `your-image-name:tag`: The name of the image you want to run.\n\n- `docker images`      \n  This command lists all the Docker images you have on your local machine. It's useful for seeing the images you've built.\n  \n  ```bash\n  docker images\n  ```\n  \n  This will show a table with your images, including repository name, tag, image ID, creation date and size.\n\n- `docker ps`    \n  This command shows you all the containers that are currently running.\n  \n  ```bash\n  docker ps\n  ```\n  \n  To see *all* containers, including those that have stopped, add the `-a` flag:\n  ```bash\n  docker ps -a\n  ```\n\n- `docker rmi`     \n  If you want to remove an image from your system, you use this command.\n\n  ```bash\n  docker rmi your-image-name:tag\n  ```\n  \n  You cannot remove an image if it's currently being used by a container. You'll need to stop and remove the container first using `docker stop \u003ccontainer_id\u003e` and `docker rm \u003ccontainer_id\u003e`.\n\n---\n\n### Total Cleanup\n\nThis is a powerful \"total cleanup\" routine. It removes *ALL* Docker resources to free up space:\n\n```bash\n# Stop all containers\ndocker stop $(docker ps -q)\n\n# Then prune everything (images, containers, unnamed volumes)\ndocker system prune -a --volumes\n\n# Also remove named volumes\ndocker volume rm $(docker volume ls -q)\n```\n\nHere's a single-line version achieving the same result:\n```bash\ndocker stop $(docker ps -a -q) \u0026\u0026 docker system prune -af --volumes \u0026\u0026 docker volume rm $(docker volume ls -q)\n```\n\nCheck the disk space consumed by different Docker ressources with:\n```bash\ndocker system df\n```\n\n---\n# Project Setup\n\n## Setting up the VM\n\n### 1. Check Edit Rights for `/etc/hosts` File\n\nThe goal is to successfully access your WordPress website, exposed via NGINX on port 443 (`-p 443:443`), using the custom domain `yourlogin.42.fr`. Since this domain is not public, you must configure **Local Domain Name Resolution** (Local DNS) by editing the `/etc/hosts` file on the machine initiating the request\n\n- **Accessing the site from the Host Machine**:    \n  This scenario relies on **NAT Port Forwarding** configured in the VM software. This rule tells your host machine to redirect traffic from its own loopback address to the VM.     \n  - **VM Software Configuration:**     \n    The VM software must be configured with a NAT network adapter and a Port Forwarding rule:\n       - Host IP: `127.0.0.1` (or blank, which defaults to all interfaces)\n       - Host Port: `443`\n       - Guest IP: leave blank (VirtualBox resolves it automatically); you may also add the VM's internal IP address\n       - Guest Port: `443` \n  - **Edit the Hosts File on the Host Machine:**      \n    Use `sudo` privileges to edit the `/etc/hosts` file on your **main host computer** and add the following entry:\n    ```bash\n    # The Host Machine's NAT rule directs this loopback traffic to the VM.\n    127.0.0.1   yourlogin.42.fr\n    ```\n  💡 **Note:** In this case, setting up a minimal, command-line-only server VM is sufficient.\n\n- **Accessing the site from the VM**:       \n  If you are on a restricted host machine and cannot edit `/etc/hosts`, you can still edit this file within your VM and eventually access the website via the VM's browser. Since the NGINX container exposes port `443` to all interfaces (`0.0.0.0:443`) on the VM, you still use the loopback address.\n  - **Edit the Hosts File on the VM:**     \n    Use `sudo` to edit the `/etc/hosts` file inside the **VM** and add the following entry:\n    ```bash\n    # The VM's Loopback IP is used for direct Docker NATing inside the VM.\n    127.0.0.1   yourlogin.42.fr\n    ```\n  💡 **Note:** In this case, you'd also need to install a desktop environment and GUI when setting up the VM.\n\n--- \n\n### 2. Install the Debian VM\n\nUsing a Debian **minimal install** is recommended for this project. Download a net-install ISO from the [Debian website](https://www.debian.org/distrib/) (choose **64-bit PC netinst iso**).\n\nCreate a new VM in **Oracle VirtualBox** (free, open-source) with the following specifications:\n- Choose a directory with enough disk space (42 Network: `/sgoinfre/`)\n- Load the ISO image.\n- **Base Settings:**\n    - **Type**: Linux / **Version**: Debian (64-bit)\n    - **Subtype**: Debian\n    - **Skip Unattended Installation**: ✔\n    - **Memory**: 2048 MB\n    - **Processors**: 1 CPU\n    - **Disk**: 20 GB (dynamic allocation is fine)\n\nWhen the installer runs:\n- **Software Selection:**\n    - **If you have access rights to the hosts machine's `/etc/hosts` (see above):** Deselect Debian desktop environment and any graphical options such as GNOME to keep the VM light and fast.\n    - Make sure **SSH server** and **standard system utilities** are selected.\n- **Boot Loader:** Install the GRUB boot loader when prompted.\n\n--- \n\n### 3. Enable SSH Access\n\nWorking directly in the VM console is possible but might be inconvient. By creating a \"tunnel\" from the host to the VM's SSH port, you can work from your host machine’s terminal and editor.\n\nInside the VM, confirm the SSH port:\n\n```bash\ngrep Port /etc/ssh/sshd_config\n```\n\nIf `Port 22` is commented out, SSH defaults to port 22, which is what you want.\n\nBy default, the VM is assigned an internal IP address within a private NAT network. This purposefully isolates the VM, making it inaccessible from the external network and providing a basic layer of security. While not strictly required for setting up the port forward, you can check the VM's IP with:\n\n```bash\nhostname -I\n# typically something like 10.0.2.15\n```\n\n#### Set Up Port Forwarding in VirtualBox\n1. Shut down the VM.\n2. In **Settings → Network**, ensure the adapter is set to NAT.\n3. Click Port Forwarding and add a rule:\n      - **Name:** e.g. ssh-access\n      - **Protocol:** TCP\n      - **Host Port**: e.g. `2222` (choose a free port)\n      - **Guest Port**: `22`\n      - **Guest IP**: leave blank (VirtualBox resolves it automatically); you may also add the VM's internal IP address confirmed above\n       \n#### Connect from the Host\n\nStart the VM (you don’t need to log in at the console) and, on the host:\n\n```bash\nssh \u003cvm_username\u003e@localhost -p 2222\n```\n\n#### SSH Config Shortcut\n\nTo simplify the command, edit `~/.ssh/config` on the host:\n\n```bash\nHost myvm\n   HostName localhost\n   User \u003cvm_username\u003e\n   Port 2222\n```\n\nNow you can connect with:\n\n```bash\nssh myvm\n```\n\n#### Use Your Local Editor (e.g. VS Code)\n- Install the **Remote – SSH** extension on VS Code.\n- Click the “\u003e\u003c” icon in the lower-left corner (“Open a Remote Window”).\n- Choose **Connect to Host → myvm** and enter the VM user’s password.\n\nYou can now edit files and run terminals in VS Code as if you were working locally.\n\n---- \n\n### 4. Prepare the Debian Host\n\nTo prepare the minimal Debian server installation for the project and the Docker Engine installation, follow these steps:\n\n#### Add User to Sudo Group\n\nDocker commands typically require elevated privileges. To give your user sudo rights:\n\n```bash\n# Log in as root\nsu -\n\n# Install sudo\napt install sudo\n\n# Add your user to the sudo group (replace with your username)\nusermod -aG sudo \u003cyour_username\u003e\n\n# Verify membership\ngroups your_username\n```\n\nYou should see `sudo` listed in the groups. Type `exit` to leave the root shell, then log out and back in for the change to take effect.\n\n#### Update the System and Install Common Tools\n\nKeep the packages current:\n\n```bash\nsudo apt update \u0026\u0026 sudo apt upgrade -y\n```\n\nInstall a few utilities you’ll use often:\n\n```bash\nsudo apt install curl git make -y\n```\n\n- `git` helps manage project files from a repository.\n- `curl` is handy for downloading installation scripts (used when installing the Docker Engine).\n- `make` is used to execute Makefiles.\n\n---\n\n### 5. Install Docker Engine\n\nFollow Docker’s official guide for the most reliable installation:\n[Install Docker Engine on Debian](https://docs.docker.com/engine/install/debian/)\n\nUse the **“Install using the apt repository”** method. After installation, confirm that Docker is working:\n\n```bash\nsudo docker run hello-world\n```\n\nIf you see the “Hello from Docker!” message, your setup is complete.\n\n#### Add to User to Docker Group\n\nDocker commands must be run by the root user or via sudo by default.   \nTo simplify things, you can add your user to the `docker` group, allowing you to run all `docker` commands without needing the `sudo` prefix.\n\n```bash\n# Log in as root\nsu -\n\n# Add your user to the docker group (replace with your username)\nusermod -aG docker \u003cyour_username\u003e\n\n# Verify membership\ngroups your_username\n```\n\n---\n\n## Setting up Inception\n\n### Test Isolated Containers First\n\nWhile the ultimate goal of Inception is to create a multi-container application orchestrated by Docker Compose, the foundation of a stable system lies in building and testing services in isolation first. This workflow can be thought of as \"unit testing\" for infrastructure.\n\nBefore we can connect all the services, we ideally prove that each one (MariaDB, WordPress and NGINX) is individually robust, secure and functional. This isolates variables, making debugging the final, integrated application much easier.\n\n---\n\n### MariaDB\n\nMariaDB is a free and open-source Relational Database (using tables, rows and columns) by the original developers of MySQL. It stores the WordPress data (like users, settings and posts) in organized tables using SQL commands.\n\nThe goal is to set up a correctly initialized and persistent MariaDB container. The current `init_db.sh` uses the secure method of reading passwords from Docker secret files (`cat /run/secrets/...`). To allow for isolated testing of the container as described below (without Docker Compose), the script needs to use environment variables for passwords (`{$DB_ROOT_PASSWORD}`, `{$DB_PASSWORD}`) instead.\n\nThe files used to build the MariaDB image and container are found in [`srcs/requirements/mariadb`](srcs/requirements/mariadb):\n\n- `Dockerfile`: This is the main blueprint. It starts from a base Debian image, installs the MariaDB server packages and copies our custom configuration and scripts into the image. It also defines the `ENTRYPOINT` and `CMD` to ensure that the container starts gracefully.\n  \n - `tools/init_db.sh`: This is the core logic of the container. It's a script that runs every time the container starts. It checks if the database has already been initialized. If not, it uses the `mariadbd --bootstrap` command to securely set up the database, create the WordPress user, grant the correct permissions and change filesystem ownership to the `mysql` user. If the database already exists, the script does nothing.\n\n- `conf/50-server.cnf`: This configuration file overrides the default `bind-address` setting to `0.0.0.0`, allowing the database to accept connections from other containers (like WordPress) over the private Docker network.\n\n1. **Building the Image**    \n\n    First, we use the `Dockerfile` to build a custom image.\n  \n    ```bash\n    docker build -t mariadb:inception ./srcs/requirements/mariadb\n    ```\n\n    Check the Docker build output: All steps should complete successfully (each step is shown in blue when it succeeds). Docker's layer caching will make subsequent builds almost instant if no files have changed.\n\n2. **Running the Isolated Container**\n\n    Next, we run the container using `docker run`. This is where we simulate the environment that Docker Compose will eventually provide, passing in all necessary configurations as environment variables (`-e`) and attaching a persistent volume (`-v`):\n    \n   ```bash\n    docker run -d --name mariadb \\\n      -p 3306:3306 \\\n      -v db_data:/var/lib/mysql \\\n      -e DB_NAME=wordpress \\\n      -e DB_USER=db_user \\\n      -e DB_PASSWORD=user_pass \\\n      -e DB_ROOT_PASSWORD=root_pass \\\n      mariadb:inception\n    ```\n\n3. **Verification and Testing**\n\n    With the container running, we perform a series of checks to validate its state and functionality.\n    \n     **A. Log Analysis (`docker logs`)**\n\n    The first step is to check the container's logs to ensure the initialization script behaved as expected. On the first run with an empty volume, the logs should show the full initialization sequence.\n\n    ```bash\n    docker logs mariadb\n    ```\n\n    The output must show all `echo` messages from the `init_db.sh` script, confirming each stage of the setup was reached.\n\n   **B. Interactive Testing (`docker exec`)**\n\n   Next, gain access to the container via an interactive shell to perform live tests from the perspective of an administrator and the application itself.\n\n    ```bash\n    docker exec -it mariadb bash\n    ```\n\n    Once inside, we verify the following:\n   \n    - **Root Access:** Can we log in as the MariaDB `root` user with the correct password? (`mysql -u root -p`)\n    - **Application User Access:** Can we log in as the dedicated `wp_user` and connect to the `wordpress` database? (`mysql -u db_user -p wordpress`)\n    - **Permissions and Security:** When logged in as `wp_user`, do `SHOW DATABASES;` and `SHOW GRANTS;` confirm that the user has `ALL PRIVILEGES` on the `wordpress` database and can see nothing else?\n    -  **Full CRUD Test:** As the `db_user`, verify that you can perform a complete Create, Read, Update and Delete cycle (`CREATE TABLE`, `INSERT`, `SELECT`, `UPDATE`, `DELETE`, `DROP TABLE`)? This is the ultimate proof that all permissions are correct. Learn more about these SQL commands [here](https://datalemur.com/blog/sql-create-read-update-delete-drop-alter)\u003csup\u003e\u003ca href=\"#footnote10\"\u003e[10]\u003c/a\u003e\u003c/sup\u003e and [here](https://www.almabetter.com/bytes/cheat-sheet/mariadb)\u003csup\u003e\u003ca href=\"#footnote11\"\u003e[11]\u003c/a\u003e\u003c/sup\u003e.\n\n    ⚠️ **Note on GitHub Codespaces:**\n\n    Due to a specific incompatibility between this container and the Codespaces runtime, `docker exec` may fail. Connecting directly to the database from the Codespaces terminal is a reliable workaround:\n\n    ```bash\n    mysql -h 127.0.0.1 -u wp_user -p wordpress\n    ```\n\n    You can now proceed with the permission and CRUD tests.\n\n    **C. Persistence Test (`docker stop` / `docker rm`)**\n\n    Finally, ensure that the data survives in the allocated volume even when the container is completely removed.\n\n   1. **Stop and remove the container:** `docker stop mariadb` and then `docker rm mariadb`. The container is now gone.\n\n   2. **Re-run the container:** Use the exact same `docker` run command from step 2, ensuring you attach the same volume (`-v db_data:/var/lib/mysql`).\n\n   3. **Verify the logs:** The new container's logs (`docker logs mariadb`) must now show the message `Database directory is not empty. Skipping initialization.`. This proves our script's logic is correct and that the data persisted in the volume.\n\nAfter all these checks pass, we can consider the MariaDB service fully validated and ready for integration. All other service containers are validated using a similar methodology. Once each component is proven to be stable and correct, we proceed to the final integration phase: orchestrating the entire application with Docker Compose.\n\n---\n\n```bash\nopenssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout inception.key -out inception.crt\n```\n\n- `openssl req`: Starts the utility to create a certificate request (or, with -x509, a self-signed certificate).\n- `x509`: Creates a **self-signed certificate** instead of a request.\n- `nodes`: **No DES/No Encryption:** Disables the use of a passphrase for the private key. This is critical for Docker, as Nginx cannot start automatically if it needs a password to read the key.\n- `days 365`: Sets the certificate's validity period to 365 days.\n- `newkey rsa:2048`: Generates a new **Private Key** using the RSA algorithm with a length of 2048 bits (standard security).\n- `keyout inception.key`: **Output File for the Private Key (Secret):** This is your `ssl_priv_key` file.\n- `out inception.crt`: **Output File for the Certificate (Public Key):** This is your `ssl_pub_key` file.\n\n#### Prompts You Must Answer\n\nWhen you run the command, OpenSSL will prompt you to enter information to embed into the certificate. Since this is for development, the values don't need to be perfectly accurate, but the **Common Name** is important:\n\n- **Country Name (2 letter code):** `DE`\n- **State or Province Name:** `Berlin`\n- **Locality Name (city):** `Berlin`\n- **Organization Name:** `42 Berin`\n- **Organizational Unit Name:** `Inception Project`\n- **Common Name (FQDN of your server):** `aschenk.42.fr` (Crucial: Must match your Nginx `server_name`)\n- **Email Address:** `XXX@aschenk.42.fr`\n\n---\n\n## References\n\n\u003ca name=\"footnote1\"\u003e[1]\u003c/a\u003e Hykes, S.; PyCon 2013 (Mar 13, 2013). [*The future of Linux Containers*](https://www.youtube.com/watch?v=wW9CAH9nSLs)         \n\u003ca name=\"footnote2\"\u003e[2]\u003c/a\u003e Subendran, B.; Medium (Feb 13, 2024). [*Namespaces and cgroups*](https://hanancs.medium.com/namespaces-and-cgroups-3eb99041e04f)     \n\u003ca name=\"footnote3\"\u003e[3]\u003c/a\u003e Docker Inc. (2025). [*What is Docker?*](https://docs.docker.com/get-started/docker-overview/)      \n\u003ca name=\"footnote4\"\u003e[4]\u003c/a\u003e ur Rehman, O.; Folio3 Cloud Services (Jun 23, 2025). [*Docker Use Cases: Top 15 Most Common Ways To Use Docker*](https://cloud.folio3.com/blog/docker-use-cases/)      \n\u003ca name=\"footnote5\"\u003e[5]\u003c/a\u003e Sonalijain; Medium (Jan 5, 2024). [*Docker Components*](https://cloud.folio3.com/blog/docker-use-cases)      \n\u003ca name=\"footnote6\"\u003e[6]\u003c/a\u003e Coursera Inc. (2025). [*Docker Cheat Sheet*](https://www.coursera.org/collections/docker-cheat-sheet)      \n\u003ca name=\"footnote7\"\u003e[7]\u003c/a\u003e Docker Inc. (2025). [*Writing a Dockerfile*](https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/)     \n\u003ca name=\"footnote8\"\u003e[8]\u003c/a\u003e Avi; Geekflare (Dec 21, 2024). [*Docker Architecture and its Components for Beginners*](https://geekflare.com/devops/docker-architecture/)     \n\u003ca name=\"footnote9\"\u003e[9]\u003c/a\u003e Rahul; Tecadmin.net (Apr 26, 2025). [*Docker 101: An Introduction to Containerization Technology*](https://tecadmin.net/docker-introduction/) \n\u003ca name=\"footnote10\"\u003e[10]\u003c/a\u003e Singh, N.; DataLemur(Jan 19, 2025). [*SQL CRUD: CREATE, READ, UPDATE, DELETE, DROP, and ALTER in SQL*](https://datalemur.com/blog/sql-create-read-update-delete-drop-alter)\n\u003ca name=\"footnote11\"\u003e[11]\u003c/a\u003e Abhani, J; AlmaBetter (Dec 15, 2024). [*MariaDB Cheat Sheet*](https://www.almabetter.com/bytes/cheat-sheet/mariadb)  \n\nThe project badge is from [this repository](https://github.com/ayogun/42-project-badges) by Ali Ogun.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falx-sch%2Finception","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falx-sch%2Finception","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falx-sch%2Finception/lists"}