Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
# Ignore items for docker build
# Build-context hygiene for the docker-chamilo image.
# This repo is docker-only: the LMS source is fetched at build time (curl),
# not copied from context, so the context only needs Dockerfile + nginx.conf
# + entrypoint.sh. Exclude everything else to keep the context lean.
.git
.github
*.log
tmp/
# Docs live in the repo for humans; the build never needs them in-context.
AGENTS.md
SETUP.md
36 changes: 0 additions & 36 deletions 000-default.conf

This file was deleted.

90 changes: 90 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# AGENTS.md

Playbook for AI agents (and humans) working in this repo. Read this before
touching the Dockerfile, compose, or LMS ref.

## What this repo is

A **docker-only** repo: it ships a `Dockerfile` that builds a single
**PHP 8.3-FPM + nginx** container for the Chamilo LMS. The LMS source is
**not** vendored — it is **fetched at build time** at a pinned ref of
`chamilo/chamilo-lms` (the `CHAMILO_LMS_REF` build arg). Do **not** commit
the LMS source tree here; that bloats the repo and defeats the slim design.

## Key files

| File | Purpose |
|------|---------|
| `Dockerfile` | Builds the image. Fetches LMS at `CHAMILO_LMS_REF`, installs deps + nginx, sets up FPM. |
| `nginx.conf` | The vhost: serves `public/` statics, proxies `.php` to FPM `127.0.0.1:9000`. |
| `entrypoint.sh` | Starts `php-fpm` (bg) then `exec nginx` (PID 1). |
| `docker-compose.yml` | `chamilo` + `db` (MariaDB 11) + `redis` (Redis 7). |
| `.dockerignore` | Keeps the build context lean (docs, VCS, logs). |

## Build

```bash
# Default: pinned ref from the Dockerfile
docker build -t chamilo-lms .

# Override the LMS ref (tag or full 40-char SHA)
docker build --build-arg CHAMILO_LMS_REF=v3.0.0 -t chamilo-lms .
```

Build is **slow the first time** (~88 MB source tarball + Composer fetch);
later builds are cached. Use `podman` if that's the host runtime.

## Run

```bash
docker compose up -d --build
# → http://localhost/ (first-run installer)
```

Verify the wiring is live (no DB yet, so expect the installer / a Symfony
error page — that **proves** nginx → FPM → PHP is connected):

```bash
curl -s -o /dev/null -w "%{http_code}\n" http://localhost/ # 200/3xx/5xx = wired
docker exec chamilo php -r 'exit((@fsockopen("127.0.0.1",9000)!==false)?0:1);' && echo "FPM up"
docker exec chamilo nginx -t # vhost is valid
```

## Gotchas (do not re-learn these the hard way)

1. **`memory_limit` OOM.** Symfony's `assets:install` post-install script boots
the kernel and exhausts PHP's 128 M default. The Dockerfile writes
`memory_limit=-1` to `/usr/local/etc/php/conf.d/zz-memory.ini`. **Do not
remove that line.** If you override memory, the build OOMs in
`PhpConfigReferenceDumpPass`.
2. **Nested `.git` bloat.** The old approach copied the LMS tree (with its
1.2 GiB `.git`) into the image. This repo fetches a **tarball** (no `.git`),
so the image is ~1.3 GB. If you ever add a `COPY` of a source tree, you
**must** `.dockerignore` the nested `.git`.
3. **Env var names.** The app reads **`DATABASE_*`** (see `.env.dist` of the
LMS), **not** `DB_*`. The compose sets `DATABASE_HOST=db` etc. Renaming
these breaks the DB connection.
4. **FPM is on `9000`, nginx on `80`.** nginx proxies `.php` to
`127.0.0.1:9000`. If you change the FPM port, update **both**
`nginx.conf` (`fastcgi_pass`) and the `entrypoint.sh` readiness check.
5. **`entrypoint.sh` runs as root** (the image default). It must start FPM
before nginx or early requests 502. The readiness loop uses PHP's
`fsockopen` (no extra tools needed).
6. **No TLS.** The image speaks plain HTTP on :80. Terminate TLS in front of
it (reverse proxy / load balancer) for production.

## Releasing a new LMS version

Change **one** thing — the `CHAMILO_LMS_REF` build arg in the `Dockerfile`
(to a tag like `v3.0.0` or a full commit SHA), commit, and rebuild. Prefer a
release **tag** for reproducible public builds; a moving SHA is fine for
pinning "our exact current tree" (the current pin is a master SHA newer than
the latest tag).

## Repo hygiene

- Keep it **slim**: no LMS source, no `vendor/`, no build artifacts.
- Keep `.dockerignore` covering `.git`, `.github`, `*.log`, `tmp/`, and the
markdown docs (they're for humans, not the build).
- The old `000-default.conf` (Apache vhost) was removed — this image is
nginx + FPM, not Apache mod_php. Don't reintroduce Apache.
145 changes: 84 additions & 61 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,61 +1,84 @@
FROM ubuntu:14.04
MAINTAINER Yannick Warnier <ywarnier@chamilo.org>

# Keep upstart from complaining
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -sf /bin/true /sbin/initctl

# Update Ubuntu and install basic PHP stuff
RUN apt-get -y update && apt-get install -y \
curl \
git \
libapache2-mod-php5 \
php5-cli \
php5-curl \
php5-gd \
php5-intl \
php5-mysql \
wget

RUN apt-get install -y openssh-server
RUN mkdir -p /var/run/sshd

# Get Chamilo
RUN mkdir -p /var/www/chamilo
ADD https://github.com/chamilo/chamilo-lms/archive/v1.10.0-alpha.tar.gz /var/www/chamilo/chamilo.tar.gz
WORKDIR /var/www/chamilo
RUN tar zxf chamilo.tar.gz;rm chamilo.tar.gz;mv chamilo* www
WORKDIR www
RUN chown -R www-data:www-data \
app \
main/default_course_document/images \
main/lang \
vendor \
web

# Get Composer (putting the download in /root is discutible)
WORKDIR /root
RUN curl -sS https://getcomposer.org/installer | php
RUN chmod +x composer.phar
RUN mv composer.phar /usr/local/bin/composer

# Get Chash
RUN git clone https://github.com/chamilo/chash.git chash
WORKDIR chash
RUN composer update --no-dev
RUN php -d phar.readonly=0 createPhar.php
RUN chmod +x chash.phar && mv chash.phar /usr/local/bin/chash

# Configure and start Apache
ADD chamilo.conf /etc/apache2/sites-available/chamilo.conf
RUN a2ensite chamilo
RUN a2enmod rewrite
RUN /etc/init.d/apache2 restart
RUN echo "127.0.0.1 docker.chamilo.net" >> /etc/hosts

# Go to Chamilo folder and install
# Soon... (this involves having a SQL server in a linked container)

WORKDIR /var/www/chamilo/www
EXPOSE 22 80
CMD ["/bin/bash"]
# Chamilo LMS — single-container runtime (PHP 8.3-FPM + nginx).
#
# Slim / docker-only image: the LMS source is NOT vendored into this repo.
# It is fetched at build time from a pinned ref of chamilo/chamilo-lms, so
# the image is fully reproducible and this repo stays small.
#
# This replaces the old PHP 5 / ubuntu 14.04 image, which cannot run the
# current (Symfony 7 / PHP 8) LMS.
FROM php:8.3-fpm

# Pinned ref of chamilo/chamilo-lms. Bump to release a new LMS version.
# Accepts a git tag (e.g. v3.0.0-beta.2) or a full commit SHA.
ARG CHAMILO_LMS_REF=c75d279bf4757617286827c5c8dae02a74f438e0

# System packages + PHP extensions the LMS needs.
# curl/ca-certificates : fetch the pinned source; Composer zip dists (TLS)
# nginx : serves the LMS over HTTP (front controller -> FPM)
# git is intentionally omitted — every Composer dependency in composer.lock
# ships a zip dist (no VCS-only packages), so Composer downloads archives via
# the PHP zip extension instead of cloning.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
nginx \
libicu-dev \
libldap-dev \
libpng-dev \
libonig-dev \
libxml2-dev \
libxslt1-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
bcmath \
exif \
gd \
intl \
ldap \
opcache \
pdo \
pdo_mysql \
soap \
xsl \
zip \
&& pecl install --onlyreqdeps --force redis \
&& docker-php-ext-enable redis \
&& rm -rf /var/lib/apt/lists/*

# Web tier: drop the stock default vhost, install ours (listens on :80,
# proxies .php to PHP-FPM at 127.0.0.1:9000, docroot /app/chamilo-lms/public).
RUN rm -f /etc/nginx/sites-enabled/default \
&& rm -rf /var/www/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Raise PHP memory limit for CLI and any child processes.
# Symfony's `assets:install` post-install script boots the kernel and
# exhausts the 128M default; -1 keeps the build from OOM-ing.
RUN echo "memory_limit=-1" > /usr/local/etc/php/conf.d/zz-memory.ini

# Fetch the LMS source at the pinned ref (build-time, not vendored).
# The tarball extracts to a single top-level dir (chamilo-lms-<ref>); rename
# it to /app/chamilo-lms so the path is stable for a tag or a full SHA.
RUN curl -fsSL "https://github.com/chamilo/chamilo-lms/archive/${CHAMILO_LMS_REF}.tar.gz" -o /tmp/lms.tar.gz \
&& mkdir -p /app/lms-fetch \
&& tar -xzf /tmp/lms.tar.gz -C /app/lms-fetch \
&& mv /app/lms-fetch/chamilo-lms-* /app/chamilo-lms \
&& rm -f /tmp/lms.tar.gz \
&& rm -rf /app/lms-fetch /root/.cache

WORKDIR /app/chamilo-lms

# Install Composer, then PHP dependencies + the post-install asset step.
# (assets:install boots the Symfony kernel; memory_limit=-1 keeps it from
# exhausting the 128M default.)
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-interaction --optimize-autoloader \
&& rm -rf /root/.composer /root/.cache/composer

# Start PHP-FPM (daemon) + nginx (foreground, PID 1) on container start.
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

EXPOSE 80 9000
Loading