diff --git a/Dockerfile b/Dockerfile index 4570a49..93e66c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.20.0 -ARG BASE_IMAGE=libops/ojs:php83 +ARG BASE_IMAGE=libops/ojs:nginx-1.30.3-php84 FROM ${BASE_IMAGE} ARG TARGETARCH diff --git a/Makefile b/Makefile index 23e35b1..7d87778 100644 --- a/Makefile +++ b/Makefile @@ -1,33 +1,21 @@ -.PHONY: build deps init init-if-needed up down rollout lint run test +SHELL := /bin/bash -DOCKER_IMAGE=libops/ojs:php83 +.PHONY: help rollout test lint +.SILENT: -deps: - docker compose pull --ignore-buildable +-include custom.Makefile -build: deps - docker compose build --pull +help: ## Show this help message + echo 'Usage: make [target]' + echo '' + echo 'Available targets:' + awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%s\033[0m\t%s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort | column -t -s $$'\t' -lint: - ./scripts/lint.sh - - -init: build - docker compose run --rm init - -init-if-needed: build - ./scripts/init-if-needed.sh - -up: init-if-needed - docker compose up --remove-orphans -d - -down: - docker compose down - -rollout: +rollout: ## Roll out the currently checked out OJS stack ./scripts/rollout.sh -run: up - -test: +test: ## Run template checks ./scripts/test.sh + +lint: ## Lint template files + ./scripts/lint.sh diff --git a/README.md b/README.md index d27b1fe..a415b9d 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,83 @@ -# Open Journal Systems (OJS) Docker Container +# Open Journal Systems Docker Template -Dockerized deployment of [Open Journal Systems](https://pkp.sfu.ca/software/ojs/) based on the [Islandora Buildkit](https://github.com/Islandora-Devops/isle-buildkit) OJS PHP/nginx base image. +LibOps Docker Compose template for running [Open Journal Systems](https://pkp.sfu.ca/software/ojs/) with Traefik, MariaDB, and the LibOps OJS PHP/nginx image. -## Quick Start - -```bash -make up -``` - -Access OJS at `http://localhost`. - -`make up` runs `scripts/init-if-needed.sh`, which inspects the rendered Docker Compose config and only runs the `init` service when required secrets or named volumes are missing. - -The installation will run automatically on first startup. The default admin credentials are: -- Username: `admin` (configurable via `OJS_ADMIN_USERNAME`) -- Password: Contents of `./secrets/OJS_ADMIN_PASSWORD` -- Email: `admin@example.com` (configurable via `OJS_ADMIN_EMAIL`) - -## Configuration - -### OJS Configuration - -| Environment Variable | Default | Source | Description | -| :------------------- | :------ | :----- | :---------- | -| DB_HOST | mariadb | environment | MariaDB hostname | -| DB_PORT | 3306 | environment | MariaDB port | -| DB_NAME | ojs | environment | Database name | -| DB_USER | ojs | environment | Database user | -| DB_PASSWORD | (generated) | secret | Database password (stored in `./secrets/OJS_DB_PASSWORD`) | -| OJS_SALT | (generated) | secret | Salt for password hashing (stored in `./secrets/OJS_SALT`) | -| OJS_API_KEY_SECRET | (generated) | secret | Secret for API key encoding (stored in `./secrets/OJS_API_KEY_SECRET`) | -| OJS_SECRET_KEY | (generated) | secret | Internally this is used for any encryption (specifically cookie encryption if enabled) (stored in `./secrets/OJS_SECRET_KEY`) | -| OJS_ADMIN_USERNAME | admin | environment | Initial admin username | -| OJS_ADMIN_EMAIL | admin@example.com | environment | Initial admin email | -| OJS_ADMIN_PASSWORD | (generated) | secret | Initial admin password (stored in `./secrets/OJS_ADMIN_PASSWORD`) | -| OJS_LOCALE | en | environment | Primary locale/language | -| OJS_TIMEZONE | UTC | environment | System timezone | -| OJS_FILES_DIR | /var/www/files | environment | Directory for uploaded files | -| OJS_OAI_REPOSITORY_ID | ojs.localhost | environment | OAI-PMH repository identifier | -| OJS_ENABLE_BEACON | 1 | environment | Enable PKP usage statistics beacon (1=enabled, 0=disabled) | -| OJS_SESSION_LIFETIME | 30 | environment | How long to stay logged in (in days) | -| OJS_X_FORWARDED_FOR | Off | environment | Trust X-Forwarded-For header. Enable PKP usage statistics beacon (Off, On) | -| OJS_SMTP_SERVER | host.docker.internal | environment | SMTP server for outgoing mail; defaults to the Docker host relay | -| OJS_SMTP_PORT | 25 | environment | SMTP server port | -| OJS_DEFAULT_ENVELOPE_SENDER | (empty) | environment | Optional default envelope sender for outgoing mail | - -OJS sends mail through the Docker host by default. On LibOps production hosts, the host MTA forwards to the managed relay; for local testing, copy `docker-compose.override-example.yaml` to `docker-compose.override.yaml` to add Mailpit and point OJS at `mailpit:1025`. - -### Nginx and PHP Settings - -See https://github.com/Islandora-Devops/isle-buildkit/tree/main/nginx#nginx-settings - -## Ingress - -Traefik is the only published ingress for the stack. The OJS container listens only on the internal Compose network, while Traefik publishes `${HOST_INSECURE_PORT:-80}` and routes requests to OJS. - -`docker-compose.yaml` is the production-shaped default. Local development changes should be copied from `docker-compose.override-example.yaml` to `docker-compose.override.yaml`; the example only exposes MariaDB for debugging and does not change the ingress path. +## Requirements +- `sitectl` installed on the host that will run the site. +- Docker with the Compose v2 plugin installed on the same host. -Set `DOMAIN` to the site hostname and `ACME_EMAIL` to the Let's Encrypt registration email before enabling the TLS override. +## Quick start -## Secrets Management +Create a new OJS site from this template: -Secrets are stored in the `./secrets/` directory and mounted into the container at runtime. The `generate-secrets.sh` script creates secure random values for: - -- `DB_ROOT_PASSWORD` - MariaDB root password -- `OJS_DB_PASSWORD` - OJS database user password -- `OJS_ADMIN_PASSWORD` - OJS admin user password -- `OJS_API_KEY_SECRET` - Secret for API key encoding/decoding -- `OJS_SALT` - Salt for password hashing - -## Customization - -You can customize the installation by: - -1. Setting environment variables in `docker-compose.yaml` -2. Overriding default values in the Dockerfile -3. Adding custom plugins to `plugins/` +```bash +sitectl create ojs/default \ + --template-repo https://github.com/libops/ojs \ + --path ./my-ojs-site \ + --type local \ + --checkout-source template \ + --default-context +``` -### Adding Plugins +The site is served through Traefik at `http://localhost`. The first boot installs OJS automatically. The default admin account is `admin`; its password is generated in `./secrets/OJS_ADMIN_PASSWORD`. -Place plugin directories in the appropriate subdirectory under `plugins/`: +## Basic operations with sitectl -- `blocks/` - Block plugins -- `gateways/` - Gateway plugins -- `generic/` - Generic plugins -- `importexport/` - Import/export plugins -- `metadata/` - Metadata plugins -- `oaiMetadataFormats/` - OAI metadata format plugins -- `paymethod/` - Payment method plugins -- `pubIds/` - Public identifier plugins -- `reports/` - Report plugins -- `themes/` - Theme plugins +Run these from the generated checkout, or add `--context ` when operating from elsewhere. -Plugins with `composer.json` files will automatically have their dependencies installed during the build. +```bash +# Start or update the Compose stack +sitectl compose up --remove-orphans -d -## Volumes +# Check the site and context configuration +sitectl healthcheck +sitectl validate -The following volumes are created for data persistence: +# Update image tags or pin a full image reference +sitectl image set --tag ojs=nginx-1.30.3-php84 +sitectl image set --image ojs=libops/ojs:nginx-1.30.3-php84@sha256:... -- `mariadb-data` - MariaDB database files -- `ojs-cache` - OJS cache files -- `ojs-files` - Uploaded files (submissions, etc.) -- `ojs-public` - Public files +# Enable local development bind mounts +sitectl set dev-mode enabled +sitectl converge -## Updating OJS Version +# Switch TLS modes +sitectl traefik tls mkcert --domain ojs.localhost +sitectl traefik tls letsencrypt --email ops@example.org -To update the OJS version, modify the `OJS_VERSION` build argument in the Dockerfile: +# Trust an upstream load balancer or reverse proxy +sitectl set reverse-proxy enabled --trusted-ip 203.0.113.10/32 +sitectl converge -```dockerfile -ARG OJS_VERSION=3_5_0-3 +# Raise upload limits for larger submissions +sitectl set upload-limits enabled --max-upload-size 2G --upload-timeout 10m +sitectl converge ``` -Version tags follow the format used in the [PKP OJS repository](https://github.com/pkp/ojs/tags). +See the [OJS sitectl plugin docs](https://github.com/libops/sitectl-docs/blob/main/plugins/ojs.mdx) for lifecycle operations, OJS tools, PKP tools, and recurring maintenance. -## Troubleshooting +## Makefile -### Installation Logs - -If the automatic installation fails, check the container logs: +The Makefile is intentionally small. It only keeps template-specific targets that are not core sitectl operations: ```bash -docker compose logs ojs +make rollout +make test +make lint ``` -### Database Connection Issues - -Ensure the MariaDB container is healthy before the OJS container starts: +Use `sitectl compose ...`, `sitectl traefik ...`, and `sitectl set ...` directly for normal stack operations. -```bash -docker compose ps -``` +## Template notes -### Resetting Installation +- `traefik` is the only published ingress. +- `ojs` is built from this repository and based on the LibOps OJS PHP/nginx image. +- `mariadb` stores application data. +- Secrets are generated into `./secrets/`. +- Custom plugins can be added under `plugins/`. -To completely reset and reinstall: - -```bash -docker compose down -v -docker compose run --rm init -docker compose up --remove-orphans -d -``` +OJS sends mail through the Docker host by default. For local SMTP testing, use the override example to add Mailpit and point OJS at `mailpit:1025`. ## License diff --git a/docker-compose.yaml b/docker-compose.yaml index ba7ac02..bf150c9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -29,7 +29,7 @@ secrets: services: init: - image: libops/base@sha256:4a8d3997ac565981cd91ca36fd5a2b64955bac8d78a3632abd5a7137609be631 + image: libops/base:3.2.2.0 restart: no volumes: - ./secrets:/secrets:rw @@ -45,6 +45,7 @@ services: - --providers.file.filename=/etc/traefik/dynamic/ojs.yml - --providers.file.watch=true - --entrypoints.web.address=:80 + - --entrypoints.web.transport.respondingTimeouts.readTimeout=300s environment: DOMAIN: "${DOMAIN:-localhost}" TRAEFIK_TLS_ENABLED: "false" @@ -58,12 +59,12 @@ services: ojs: <<: *common - image: libops/ojs:php83 + image: libops/ojs:nginx-1.30.3-php84 build: context: . pull: true args: - BASE_IMAGE: libops/ojs:php83 + BASE_IMAGE: libops/ojs:nginx-1.30.3-php84 extra_hosts: - "host.docker.internal:host-gateway" environment: