Public Access
Initial
This commit is contained in:
commit
6765ec8991
17 files changed
+825
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
backup
|
||||||
|
secrets
|
||||||
|
data
|
||||||
|
*.zip
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
COMPOSE_PROJECT_NAME=egeya
|
||||||
|
|
||||||
|
EGEYA_VERSION=4199
|
||||||
|
EGEYA_URL=
|
||||||
|
EGEYA_SHA256=
|
||||||
|
EGEYA_DB_NAME=egeya
|
||||||
|
EGEYA_DB_USER=egeya
|
||||||
|
|
||||||
|
MARIADB_VERSION=10.11
|
||||||
|
|
||||||
|
HTTP_BIND=127.0.0.1
|
||||||
|
HTTP_PORT=8080
|
||||||
|
NGINX_SERVER_NAME=_
|
||||||
|
|
||||||
|
PHP_MEMORY_LIMIT=512M
|
||||||
|
PHP_UPLOAD_MAX_FILESIZE=512M
|
||||||
|
PHP_POST_MAX_SIZE=1024M
|
||||||
|
PHP_MAX_EXECUTION_TIME=300
|
||||||
|
PHP_MAX_INPUT_TIME=300
|
||||||
|
|
||||||
|
TZ=Europe/Berlin
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
.env
|
||||||
|
backup/*
|
||||||
|
!backup/.gitkeep
|
||||||
|
data/*
|
||||||
|
!data/user/
|
||||||
|
!data/user/.gitkeep
|
||||||
|
!data/pictures/
|
||||||
|
!data/pictures/.gitkeep
|
||||||
|
!data/tmp/
|
||||||
|
!data/tmp/.gitkeep
|
||||||
|
secrets/*
|
||||||
|
!secrets/.gitkeep
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
ARG EGEYA_VERSION=4199
|
||||||
|
ARG EGEYA_URL=""
|
||||||
|
ARG EGEYA_SHA256=""
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim AS egeya-source
|
||||||
|
|
||||||
|
ARG EGEYA_VERSION
|
||||||
|
ARG EGEYA_URL
|
||||||
|
ARG EGEYA_SHA256
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends ca-certificates curl unzip; \
|
||||||
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
|
archive_url="${EGEYA_URL:-https://blogengine.ru/download/e2_distr_v${EGEYA_VERSION}.zip}"; \
|
||||||
|
work_dir="$(mktemp -d)"; \
|
||||||
|
curl -fL \
|
||||||
|
--retry 5 \
|
||||||
|
--retry-delay 2 \
|
||||||
|
--connect-timeout 20 \
|
||||||
|
--user-agent "egeya-docker/${EGEYA_VERSION}" \
|
||||||
|
"$archive_url" \
|
||||||
|
-o "$work_dir/egeya.zip"; \
|
||||||
|
if [ -n "$EGEYA_SHA256" ]; then \
|
||||||
|
echo "$EGEYA_SHA256 $work_dir/egeya.zip" | sha256sum -c -; \
|
||||||
|
fi; \
|
||||||
|
mkdir -p "$work_dir/unpacked" /opt/egeya-release; \
|
||||||
|
unzip -q "$work_dir/egeya.zip" -d "$work_dir/unpacked"; \
|
||||||
|
if [ -f "$work_dir/unpacked/index.php" ]; then \
|
||||||
|
source_dir="$work_dir/unpacked"; \
|
||||||
|
else \
|
||||||
|
source_dir="$(find "$work_dir/unpacked" -maxdepth 2 -type f -name index.php -printf '%h\n' | head -n 1)"; \
|
||||||
|
fi; \
|
||||||
|
test -n "$source_dir"; \
|
||||||
|
cp -a "$source_dir"/. /opt/egeya-release/; \
|
||||||
|
test -f /opt/egeya-release/index.php; \
|
||||||
|
rm -rf "$work_dir"
|
||||||
|
|
||||||
|
FROM php:8.2-fpm-bookworm AS php
|
||||||
|
|
||||||
|
ENV EGEYA_ROOT=/var/www/html \
|
||||||
|
EGEYA_DATA_DIR=/var/www/egeya-data \
|
||||||
|
EGEYA_DEFAULTS_DIR=/opt/egeya-defaults
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
libavif-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
|
libjpeg62-turbo-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libzip-dev; \
|
||||||
|
docker-php-ext-configure gd \
|
||||||
|
--with-avif \
|
||||||
|
--with-freetype \
|
||||||
|
--with-jpeg \
|
||||||
|
--with-webp; \
|
||||||
|
docker-php-ext-install -j"$(nproc)" \
|
||||||
|
exif \
|
||||||
|
gd \
|
||||||
|
mbstring \
|
||||||
|
opcache \
|
||||||
|
pdo_mysql \
|
||||||
|
zip; \
|
||||||
|
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=egeya-source /opt/egeya-release/ /var/www/html/
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
mkdir -p "$EGEYA_DEFAULTS_DIR/user" "$EGEYA_DEFAULTS_DIR/pictures"; \
|
||||||
|
if [ -d "$EGEYA_ROOT/user" ]; then \
|
||||||
|
cp -a "$EGEYA_ROOT/user"/. "$EGEYA_DEFAULTS_DIR/user"/; \
|
||||||
|
fi; \
|
||||||
|
if [ -d "$EGEYA_ROOT/pictures" ]; then \
|
||||||
|
cp -a "$EGEYA_ROOT/pictures"/. "$EGEYA_DEFAULTS_DIR/pictures"/; \
|
||||||
|
fi; \
|
||||||
|
rm -rf "$EGEYA_ROOT/user" "$EGEYA_ROOT/pictures"; \
|
||||||
|
ln -s "$EGEYA_DATA_DIR/user" "$EGEYA_ROOT/user"; \
|
||||||
|
ln -s "$EGEYA_DATA_DIR/pictures" "$EGEYA_ROOT/pictures"; \
|
||||||
|
chown -R www-data:www-data "$EGEYA_ROOT" "$EGEYA_DEFAULTS_DIR"
|
||||||
|
|
||||||
|
COPY docker/php/egeya-entrypoint.sh /usr/local/bin/egeya-entrypoint
|
||||||
|
COPY docker/php/www-egeya.conf /usr/local/etc/php-fpm.d/zz-egeya.conf
|
||||||
|
|
||||||
|
RUN chmod 0755 /usr/local/bin/egeya-entrypoint
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
EXPOSE 9000
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=15s --timeout=5s --start-period=20s --retries=5 \
|
||||||
|
CMD php -r '$s=@fsockopen("127.0.0.1",9000,$e,$m,2); if(!$s){exit(1);} fclose($s);'
|
||||||
|
|
||||||
|
ENTRYPOINT ["egeya-entrypoint"]
|
||||||
|
CMD ["php-fpm"]
|
||||||
|
|
||||||
|
FROM nginx:1.28-bookworm AS nginx
|
||||||
|
|
||||||
|
ENV EGEYA_ROOT=/var/www/html \
|
||||||
|
EGEYA_DATA_DIR=/var/www/egeya-data
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends curl; \
|
||||||
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
|
if getent passwd www-data >/dev/null; then \
|
||||||
|
sed -ri 's/^user[[:space:]]+[^;]+;/user www-data;/' /etc/nginx/nginx.conf; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
COPY --from=egeya-source /opt/egeya-release/ /var/www/html/
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
rm -rf "$EGEYA_ROOT/user" "$EGEYA_ROOT/pictures"; \
|
||||||
|
ln -s "$EGEYA_DATA_DIR/user" "$EGEYA_ROOT/user"; \
|
||||||
|
ln -s "$EGEYA_DATA_DIR/pictures" "$EGEYA_ROOT/pictures"; \
|
||||||
|
rm -f /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
COPY docker/nginx/egeya.conf.template /etc/nginx/templates/egeya.conf.template
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=15s --timeout=5s --start-period=20s --retries=5 \
|
||||||
|
CMD curl -fsS http://127.0.0.1/ >/dev/null || exit 1
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
# 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=<sha256 of e2_distr_v4199.zip>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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=<new build number>
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
Whitespace-only changes.
+131
@@ -0,0 +1,131 @@
|
|||||||
|
name: ${COMPOSE_PROJECT_NAME:-egeya}
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: mariadb:${MARIADB_VERSION:-10.11}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
MARIADB_DATABASE: ${EGEYA_DB_NAME:-egeya}
|
||||||
|
MARIADB_USER: ${EGEYA_DB_USER:-egeya}
|
||||||
|
MARIADB_PASSWORD_FILE: /run/secrets/db_password
|
||||||
|
MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
|
||||||
|
command:
|
||||||
|
- --character-set-server=utf8mb4
|
||||||
|
- --collation-server=utf8mb4_unicode_ci
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
- db_root_password
|
||||||
|
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
php:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: php
|
||||||
|
args:
|
||||||
|
EGEYA_VERSION: ${EGEYA_VERSION:-4199}
|
||||||
|
EGEYA_URL: ${EGEYA_URL:-}
|
||||||
|
EGEYA_SHA256: ${EGEYA_SHA256:-}
|
||||||
|
|
||||||
|
image: ${EGEYA_PHP_IMAGE:-local/egeya-php}:${EGEYA_VERSION:-4199}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
environment:
|
||||||
|
E2_DB_SERVER: db
|
||||||
|
E2_DB_USER_NAME: ${EGEYA_DB_USER:-egeya}
|
||||||
|
E2_DB_PASSW_FILE: /run/secrets/db_password
|
||||||
|
E2_DB_NAME: ${EGEYA_DB_NAME:-egeya}
|
||||||
|
PHP_MEMORY_LIMIT: ${PHP_MEMORY_LIMIT:-512M}
|
||||||
|
PHP_UPLOAD_MAX_FILESIZE: ${PHP_UPLOAD_MAX_FILESIZE:-512M}
|
||||||
|
PHP_POST_MAX_SIZE: ${PHP_POST_MAX_SIZE:-1024M}
|
||||||
|
PHP_MAX_EXECUTION_TIME: ${PHP_MAX_EXECUTION_TIME:-300}
|
||||||
|
PHP_MAX_INPUT_TIME: ${PHP_MAX_INPUT_TIME:-300}
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/www/egeya-data
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
- CMD
|
||||||
|
- php
|
||||||
|
- -r
|
||||||
|
- '$$s=@fsockopen("127.0.0.1",9000,$$e,$$m,2); if(!$$s){exit(1);} fclose($$s);'
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: nginx
|
||||||
|
args:
|
||||||
|
EGEYA_VERSION: ${EGEYA_VERSION:-4199}
|
||||||
|
EGEYA_URL: ${EGEYA_URL:-}
|
||||||
|
EGEYA_SHA256: ${EGEYA_SHA256:-}
|
||||||
|
|
||||||
|
image: ${EGEYA_NGINX_IMAGE:-local/egeya-nginx}:${EGEYA_VERSION:-4199}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
php:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
environment:
|
||||||
|
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
|
||||||
|
NGINX_CLIENT_MAX_BODY_SIZE: ${PHP_POST_MAX_SIZE:-1024M}
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "${HTTP_BIND:-127.0.0.1}:${HTTP_PORT:-8080}:80"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/www/egeya-data:ro
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
- backend
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
frontend:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
backend:
|
||||||
|
driver: bridge
|
||||||
|
internal: true
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
file: ./secrets/db_password
|
||||||
|
|
||||||
|
db_root_password:
|
||||||
|
file: ./secrets/db_root_password
|
||||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,54 @@
|
|||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
server_name ${NGINX_SERVER_NAME};
|
||||||
|
|
||||||
|
keepalive_timeout 70;
|
||||||
|
client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};
|
||||||
|
|
||||||
|
root /var/www/html;
|
||||||
|
index index.php index.html;
|
||||||
|
|
||||||
|
location ~* ^.+\.(jpg|jpeg|gif|css|html|htm|png|js|webp|avif|svg|mp3|ogg|mp4|mov)$ {
|
||||||
|
access_log off;
|
||||||
|
expires 30d;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 /errors/404.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
log_not_found off;
|
||||||
|
rewrite ^(.*)$ /index.php?go=$1 last;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(system|user)/.*\.php$ {
|
||||||
|
deny all;
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /user/settings.json {
|
||||||
|
deny all;
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /user/settings.psa {
|
||||||
|
deny all;
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param E2_SYNTH_URLS true;
|
||||||
|
fastcgi_pass php:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.ht {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.psa$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EGEYA_DATA_DIR="${EGEYA_DATA_DIR:-/var/www/egeya-data}"
|
||||||
|
EGEYA_DEFAULTS_DIR="${EGEYA_DEFAULTS_DIR:-/opt/egeya-defaults}"
|
||||||
|
PHP_RUNTIME_INI="/usr/local/etc/php/conf.d/zz-egeya-runtime.ini"
|
||||||
|
|
||||||
|
PHP_MEMORY_LIMIT="${PHP_MEMORY_LIMIT:-512M}"
|
||||||
|
PHP_UPLOAD_MAX_FILESIZE="${PHP_UPLOAD_MAX_FILESIZE:-512M}"
|
||||||
|
PHP_POST_MAX_SIZE="${PHP_POST_MAX_SIZE:-1024M}"
|
||||||
|
PHP_MAX_EXECUTION_TIME="${PHP_MAX_EXECUTION_TIME:-300}"
|
||||||
|
PHP_MAX_INPUT_TIME="${PHP_MAX_INPUT_TIME:-300}"
|
||||||
|
|
||||||
|
copy_defaults_if_empty() {
|
||||||
|
local name="$1"
|
||||||
|
local source_dir="${EGEYA_DEFAULTS_DIR}/${name}"
|
||||||
|
local target_dir="${EGEYA_DATA_DIR}/${name}"
|
||||||
|
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
|
||||||
|
if [ -d "$source_dir" ] && [ -z "$(find "$target_dir" -mindepth 1 -print -quit)" ]; then
|
||||||
|
cp -a "$source_dir"/. "$target_dir"/
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read_secret_to_env() {
|
||||||
|
local env_name="$1"
|
||||||
|
local file_env_name="${env_name}_FILE"
|
||||||
|
local file_path="${!file_env_name:-}"
|
||||||
|
|
||||||
|
if [ -n "$file_path" ]; then
|
||||||
|
if [ ! -r "$file_path" ]; then
|
||||||
|
printf 'Secret file is not readable: %s\n' "$file_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf -v "$env_name" '%s' "$(cat "$file_path")"
|
||||||
|
export "$env_name"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_defaults_if_empty user
|
||||||
|
copy_defaults_if_empty pictures
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$EGEYA_DATA_DIR/tmp" \
|
||||||
|
"$EGEYA_DATA_DIR/tmp/sessions" \
|
||||||
|
"$EGEYA_DATA_DIR/user/logs"
|
||||||
|
|
||||||
|
touch "$EGEYA_DATA_DIR/user/logs/main.log"
|
||||||
|
|
||||||
|
chown -R www-data:www-data \
|
||||||
|
"$EGEYA_DATA_DIR/user" \
|
||||||
|
"$EGEYA_DATA_DIR/pictures" \
|
||||||
|
"$EGEYA_DATA_DIR/tmp"
|
||||||
|
|
||||||
|
chmod 0700 "$EGEYA_DATA_DIR/tmp" "$EGEYA_DATA_DIR/tmp/sessions"
|
||||||
|
|
||||||
|
read_secret_to_env E2_DB_PASSW
|
||||||
|
|
||||||
|
cat > "$PHP_RUNTIME_INI" <<EOF_INI
|
||||||
|
memory_limit = ${PHP_MEMORY_LIMIT}
|
||||||
|
upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}
|
||||||
|
post_max_size = ${PHP_POST_MAX_SIZE}
|
||||||
|
max_execution_time = ${PHP_MAX_EXECUTION_TIME}
|
||||||
|
max_input_time = ${PHP_MAX_INPUT_TIME}
|
||||||
|
upload_tmp_dir = ${EGEYA_DATA_DIR}/tmp
|
||||||
|
sys_temp_dir = ${EGEYA_DATA_DIR}/tmp
|
||||||
|
session.save_path = ${EGEYA_DATA_DIR}/tmp/sessions
|
||||||
|
EOF_INI
|
||||||
|
|
||||||
|
exec /usr/local/bin/docker-php-entrypoint "$@"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[www]
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
||||||
|
decorate_workers_output = no
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
DUMP_FILE="${1:-${PROJECT_DIR}/backup/egeya.sql}"
|
||||||
|
|
||||||
|
if [ ! -r "$DUMP_FILE" ]; then
|
||||||
|
printf 'SQL dump not found or not readable: %s\n' "$DUMP_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
|
docker compose up -d db
|
||||||
|
|
||||||
|
docker compose exec -T db sh -ec '
|
||||||
|
exec mariadb \
|
||||||
|
-u"$MARIADB_USER" \
|
||||||
|
-p"$(cat /run/secrets/db_password)" \
|
||||||
|
"$MARIADB_DATABASE"
|
||||||
|
' < "$DUMP_FILE"
|
||||||
|
|
||||||
|
printf 'Imported database dump: %s\n' "$DUMP_FILE"
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE_BLOG_DIR="${1:-/var/www/blog}"
|
||||||
|
TARGET_DATA_DIR="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/data}"
|
||||||
|
|
||||||
|
for name in user pictures; do
|
||||||
|
source_dir="${SOURCE_BLOG_DIR}/${name}"
|
||||||
|
target_dir="${TARGET_DATA_DIR}/${name}"
|
||||||
|
|
||||||
|
if [ ! -d "$source_dir" ]; then
|
||||||
|
printf 'Source directory not found: %s\n' "$source_dir" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
rsync -aHAX --delete "$source_dir"/ "$target_dir"/
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir -p "${TARGET_DATA_DIR}/tmp"
|
||||||
|
|
||||||
|
printf 'Copied user and pictures from %s to %s\n' "$SOURCE_BLOG_DIR" "$TARGET_DATA_DIR"
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${PROJECT_DIR}/.env"
|
||||||
|
ENV_EXAMPLE="${PROJECT_DIR}/.env.example"
|
||||||
|
SECRETS_DIR="${PROJECT_DIR}/secrets"
|
||||||
|
DATA_DIR="${PROJECT_DIR}/data"
|
||||||
|
|
||||||
|
create_secret() {
|
||||||
|
local path="$1"
|
||||||
|
|
||||||
|
if [ ! -s "$path" ]; then
|
||||||
|
umask 077
|
||||||
|
openssl rand -base64 48 | tr -d '\n' > "$path"
|
||||||
|
printf '\n' >> "$path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$SECRETS_DIR" \
|
||||||
|
"$DATA_DIR/user" \
|
||||||
|
"$DATA_DIR/pictures" \
|
||||||
|
"$DATA_DIR/tmp"
|
||||||
|
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
create_secret "$SECRETS_DIR/db_password"
|
||||||
|
create_secret "$SECRETS_DIR/db_root_password"
|
||||||
|
|
||||||
|
chmod 0600 \
|
||||||
|
"$SECRETS_DIR/db_password" \
|
||||||
|
"$SECRETS_DIR/db_root_password"
|
||||||
|
|
||||||
|
printf 'Project prepared: %s\n' "$PROJECT_DIR"
|
||||||
Whitespace-only changes.
Reference in new issue
Block a user