# Egeya 11.5 v4199 in Docker Stack: - nginx - PHP-FPM 8.2 - MariaDB 10.11 - Egeya v4199 The layout intentionally follows a tested nginx + PHP-FPM deployment rather than the older Apache-based Docker example. ## Why nginx + PHP-FPM Egeya 11 supports PHP up to 8.2. The nginx configuration uses synthetic URLs through: ```nginx location / { log_not_found off; rewrite ^(.*)$ /index.php?go=$1 last; } ``` Do not replace this with: ```nginx try_files $uri $uri/ /index.php?go=$uri; ``` The rewrite form preserves the original query string used by Egeya upload requests, including fields such as `entity` and `entity-id`. The PHP location also passes: ```nginx fastcgi_param E2_SYNTH_URLS true; ``` Direct access to PHP files under `/system` and `/user`, `user/settings.json`, `*.psa`, and `.ht*` is blocked. ## Upload temporary directory The `data` directory is mounted once at `/var/www/egeya-data`. Persistent paths are: ```text /var/www/egeya-data/user /var/www/egeya-data/pictures /var/www/egeya-data/tmp ``` Inside both application images, `/var/www/html/user` and `/var/www/html/pictures` are symbolic links into this single mount. PHP is configured with: ```ini upload_tmp_dir = /var/www/egeya-data/tmp sys_temp_dir = /var/www/egeya-data/tmp ``` This is deliberate. A standard container `/tmp` is on the container filesystem, while `pictures` is on a bind mount. Moving an uploaded file between them may cross mount boundaries and fail with `EXDEV`. Keeping the upload temporary directory and `pictures` under the same mount avoids that class of failure. ## Project structure ```text Dockerfile compose.yaml .env.example .dockerignore .gitignore docker/nginx/egeya.conf.template docker/php/egeya-entrypoint.sh docker/php/www-egeya.conf scripts/prepare.sh scripts/migrate-files.sh scripts/import-db.sh data/user data/pictures data/tmp backup secrets ``` Create the structure manually if required: ```bash mkdir -p docker/nginx docker/php scripts data/user data/pictures data/tmp backup secrets touch Dockerfile compose.yaml .env.example .dockerignore .gitignore \ docker/nginx/egeya.conf.template \ docker/php/egeya-entrypoint.sh docker/php/www-egeya.conf \ scripts/prepare.sh scripts/migrate-files.sh scripts/import-db.sh \ data/user/.gitkeep data/pictures/.gitkeep data/tmp/.gitkeep \ backup/.gitkeep secrets/.gitkeep ``` ## Prepare ```bash chmod +x scripts/*.sh ./scripts/prepare.sh ``` Review `.env` before starting. ## Build ```bash docker compose build --pull ``` Both `nginx` and `php` targets are built from the same Egeya source stage, so the static files seen by nginx and the PHP code executed by PHP-FPM are from the same Egeya release. Optional source integrity check: ```text EGEYA_SHA256= ``` ## Start ```bash docker compose up -d docker compose ps docker compose logs --tail=100 nginx php db ``` By default nginx listens only on: ```text 127.0.0.1:8080 ``` This is suitable when another reverse proxy terminates HTTPS on the Docker host. ## Data model The application code is immutable and comes from the Docker images. Persistent data is limited to: - `data/user` - `data/pictures` - `data/tmp` - MariaDB named volume `db_data` Do not copy an old `/system` directory into the container. Updating the image updates `/system` and the bundled application files. Custom additions stored below `user`, including `user/extras`, migrate together with the user data. ## Migration from a bare-metal installation Assume the current installation is: ```text /var/www/blog ``` ### 1. Stop writes on the old installation Stop the web application or otherwise prevent writes for the final synchronization. ### 2. Create a database dump Example: ```bash mysqldump \ --single-transaction \ --quick \ --triggers \ --default-character-set=utf8mb4 \ egeya > egeya.sql ``` Copy the dump to: ```text backup/egeya.sql ``` ### 3. Copy file data If the old blog tree is locally available: ```bash ./scripts/migrate-files.sh /var/www/blog ./data ``` For a remote source, an equivalent rsync is: ```bash rsync -aHAX old-host:/var/www/blog/user/ ./data/user/ rsync -aHAX old-host:/var/www/blog/pictures/ ./data/pictures/ ``` Do not copy `/system`. Do not copy the old nginx configuration into the application image. Use `docker/nginx/egeya.conf.template`. ### 4. Prepare secrets and configuration ```bash ./scripts/prepare.sh ``` Set the target database name and user in `.env` before initializing MariaDB. ### 5. Start MariaDB and import the dump ```bash ./scripts/import-db.sh backup/egeya.sql ``` ### 6. Start PHP and nginx ```bash docker compose up -d php nginx ``` ### 7. Validate ```bash docker compose ps docker compose logs --tail=200 php nginx ``` Check at least: - public pages - author login - note editor - image upload - audio/video upload if used - editing an existing note - built-in security check - access to `/system/core.php` returns 403 - access to `/user/settings.json` returns 403 For upload diagnostics, the application log is available at: ```text data/user/logs/main.log ``` It is created by the PHP container entrypoint if absent. ## Database credentials Egeya receives database settings through its supported environment variables: ```text E2_DB_SERVER E2_DB_USER_NAME E2_DB_PASSW E2_DB_NAME ``` The Compose file does not place the password directly in its environment section. It mounts a Docker secret and the PHP entrypoint exports its contents as `E2_DB_PASSW` immediately before starting PHP-FPM. PHP-FPM is explicitly configured with `clear_env = no` so the Egeya process can see these variables. ## Updating Egeya Change: ```text EGEYA_VERSION= ``` If necessary also set `EGEYA_URL` and `EGEYA_SHA256`. Then rebuild and recreate the application containers: ```bash docker compose build --pull php nginx docker compose up -d --no-deps --force-recreate php nginx ``` The persistent `user`, `pictures`, and database data are not replaced. Before an update, make a database dump and a copy of `data`. ## Useful commands Validate Compose rendering: ```bash docker compose config ``` PHP configuration: ```bash docker compose exec php php -i | grep -E 'upload_tmp_dir|sys_temp_dir|upload_max_filesize|post_max_size' ``` Verify that temp and pictures resolve to the same mounted filesystem: ```bash docker compose exec php sh -c 'df -T /var/www/egeya-data/tmp /var/www/egeya-data/pictures' ``` Check the nginx configuration: ```bash docker compose exec nginx nginx -T ``` Check protected paths: ```bash curl -i http://127.0.0.1:8080/system/core.php curl -i http://127.0.0.1:8080/user/settings.json ```