Compare commits

4 Commits

Author SHA1 Message Date
ea9e9162c9 setting up moodle continued. now it is able to start up 2025-12-04 13:50:34 +01:00
f6410f9239 add maintenance information 2025-12-01 11:56:20 +01:00
139f62e48e more switching to moodle 2025-12-01 11:55:21 +01:00
a698319d73 setup repo for moodle 2025-12-01 11:41:01 +01:00
17 changed files with 1536 additions and 194 deletions

View File

@ -6,7 +6,7 @@ steps:
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
settings:
host: swarm-test.autonomic.zone
stack: custom-php
stack: moodle
networks:
- proxy
generate_secrets: true
@ -14,8 +14,8 @@ steps:
deploy_key:
from_secret: drone_ssh_swarm_test
environment:
DOMAIN: custom-php.swarm-test.autonomic.zone
STACK_NAME: custom-php
DOMAIN: moodle.swarm-test.autonomic.zone
STACK_NAME: moodle
LETS_ENCRYPT_ENV: production
SECRET_DB_PASSWORD_VERSION: v1
SECRET_DB_ROOT_PASSWORD_VERSION: v1

View File

@ -1,4 +1,4 @@
TYPE=custom-php
TYPE=moodle
DOMAIN=example.com
## Domain aliases
@ -6,26 +6,26 @@ DOMAIN=example.com
LETS_ENCRYPT_ENV=production
COMPOSE_FILE=compose.yml
ROOT_PATH=/var/www/html
# environment (needed for PHP frameworks like laravel/symphony)
APP_ENV=prod
## Optional: Specify alternative PHP version
#COMPOSE_FILE=$COMPOSE_FILE:compose.version.yml
#PHP_VERSION=7.4-fpm-alpine
# moodle settings, set to override defaults
#MOODLE_VERSION=stable501/moodle-latest-501
#MOODLE_LANGUAGE=en
#MOODLE_TIMEZONE=Europe/Berlin
#MOODLE_FULLNAME=Moodle site
#MOODLE_SHORTNAME=MS
#MOODLE_ADMINNAME=admin
#MOODLE_ADMINMAIL=mail@example.com
#MOODLE_SUMMARY=site description...
#MOODLE_SUPPORTMAIL=support@example.com
SECRET_ADMIN_PASSWORD_VERSION=v1
## Extra extensions you need as a space separated list (run `abra app YOURAPPDOMAIN run app "php -m"` to see already active extensions)
PHP_EXTENSIONS="pdo_mysql"
## Uncomment to install more packages, space separated
#INSTALL_PACKAGES="libxslt-dev"
## Uncomment to install more PHP extensions or Linux packages
#PHP_EXTENSIONS=""
#INSTALL_PACKAGES=""
# Optional database
#COMPOSE_FILE="$COMPOSE_FILE:compose.mariadb.yml"
#SECRET_DB_ROOT_PASSWORD_VERSION=v1
#SECRET_DB_PASSWORD_VERSION=v1
# Optionally override database name and user
#DB_NAME=site
#DB_USER=site
COMPOSE_FILE="$COMPOSE_FILE:compose.mariadb.yml"
SECRET_DB_ROOT_PASSWORD_VERSION=v1
SECRET_DB_PASSWORD_VERSION=v1
# Local SMTP relay
#COMPOSE_FILE="$COMPOSE_FILE:compose.mailrelay.yml"
@ -40,6 +40,3 @@ PHP_EXTENSIONS="pdo_mysql"
#SMTP_AUTH=on
#SMTP_TLS=on
#SECRET_SMTP_PASSWORD_VERSION=v1
# Use httpd instead of nginx
#COMPOSE_FILE="$COMPOSE_FILE:compose.httpd.yml"

24
MAINTENANCE.md Normal file
View File

@ -0,0 +1,24 @@
# Moodle Recipe Maintenance
All contributions should be made via a pull request. This is to ensure a certain quality / consistency, that others can rely on.
## Maintainer Responsibilities
A recipe maintainer has the following responsibilities:
- respond to pull requests / issues within a week
- make image security updates within a day
- make image patch / minor updates within a week
- make image major updates within a month
In order to fullfill these responsibilities a recipe maintainer:
- has to watch the repository (to get notifications)
- needs to make sure renovate is configured properly
## Merge rules
A pull request can be merged if it is approved by at least one maintainer. For pull requests opened by a maintainer they need to be approved by another maintainer.
## Becoming a maintainer
Everyone can apply to be a recipe maintainer. Simply add your self to the list in the [README.md](./README.md) and open a new pull request with the change.

View File

@ -1,64 +1,27 @@
# custom-php
# Moodle
Coöp Cloud + [PHP](https://php.org) + MariaDB (optional) + Nginx = 🥳
Learning Management System (LMS)
<!-- metadata -->
* **Category**: Development
* **Status**: 3, stable
* **Maintainer**: [@stevensting](https://git.coopcloud.tech/stevensting)
* **Category**: Learning
* **Status**: 0, development
* **Image**: [`php`](https://hub.docker.com/_/php), 4, upstream
* **Healthcheck**: Yes
* **Backups**: Yes
* **Email**: 3
* **Tests**: 2
* **SSO**: No
* **Healthcheck**: no
* **Backups**: no
* **Email**: no
* **Tests**: no
* **SSO**: no
<!-- endmetadata -->
## Basic usage
1. Set up Docker Swarm and [`abra`][abra]
2. Deploy [`coop-cloud/traefik`][cc-traefik]
3. `abra app new custom-php --secrets` (optionally with `--pass` if you'd like
to save secrets in `pass`)
4. `abra app config YOURAPPDOMAIN`
- be sure to change `$DOMAIN` to something that resolves to
your Docker swarm box
- if you need to enable the optional database, uncomment `COMPOSE_FILE="compose.yml:compose.mariadb.yml"` in which case configure your site to load the DB credentials from env:
- `getenv('DB_NAME');`
- `getenv('DB_HOST');`
- `getenv('DB_USER');`
- `@file_get_contents(getenv('DB_PASSWORD_FILE'));`
5. Deploy with `abra app deploy YOURAPPDOMAIN`
6. Copy your site files using something like: `abra app cp YOURAPPDOMAIN index.html app:/var/www/html/` or if you want to copy an entire directory: `tar -cf - -C my_site/path/here . | abra app cp YOURAPPDOMAIN - app:/var/www/html/`
7. Use [restore functionality](https://docs.coopcloud.tech/backup-restore/) to import a SQL file into the db
8. Open the configured domain in your browser to check all is good
## Extra
Indicate extensions you need in the `PHP_EXTENSIONS` env var. The entrypoint script will install them on startup. The same for necessary packages with
`INSTALL_PACKAGES`
You can see what PHP extensions compiled into the image by checking the output of `abra app run YOURAPPDOMAIN app "php -m"`
You can see the PHP config and environment by checking the output of `abra app run YOURAPPDOMAIN app "php -i"`
## Email
There is a local or remote SMTP relay configuration available.
* **local**: `COMPOSE_FILE=compose.yml:compose.mailrelay.yml`
* **remote**: `COMPOSE_FILE=compose.yml:compose.mailrelay.yml:compose.smtp.yml`
Below are the instructions for the local relay.
1. Deploy [`postfix-relay`][cc-postfix-relay]
2. `abra app config YOURAPPDOMAIN`, and uncomment the email lines; change
`MAIL_FROM` to make sure the domain is the same as `postfix-relay`'s
`$DOMAIN` or in its `$EXTRA_SENDER_DOMAINS`
1. `abra app new moodle --secrets`
2. `abra app config YOURAPPDOMAIN`
- be sure to change `$DOMAIN` to something that resolves to your Docker swarm box
3. `abra app deploy YOURAPPDOMAIN`
- attention: installing all packages and php extensions necessary can take a couple of minutes. check logs for progress
[abra]: https://git.autonomic.zone/autonomic-cooperative/abra
[cc-traefik]: https://git.autonomic.zone/coop-cloud/traefik
[cc-postfix-relay]: https://git.autonomic.zone/coop-cloud/traefik

11
abra.sh
View File

@ -1,11 +1,10 @@
# export PHP_VERSION=7.4
export NGINX_DEFAULT_CONF_VERSION=v7
export PHP_UPLOADS_CONF_VERSION=v4
export ENTRYPOINT_CONF_VERSION=v2
export NGINX_DEFAULT_CONF_VERSION=v1
export PHP_CONF_VERSION=v1
export ENTRYPOINT_CONF_VERSION=v1
export ENTRYPOINT_MAILRELAY_CONF_VERSION=v1
export ENTRYPOINT_HTTPD_CONF_VERSION=v1
export HTTPD_VHOSTS_CONF_VERSION=v1
export MSMTP_CONF_VERSION=v3
export MSMTP_CONF_VERSION=v1
export MOODLE_CONF_VERSION=v1
abra_backup_app() {
_abra_backup_dir "app:/var/www/html/"

View File

@ -1,42 +0,0 @@
version: "3.8"
services:
frontend:
image: httpd:2.4.62
networks:
- proxy
depends_on:
- app
deploy:
restart_policy:
condition: on-failure
labels:
- "traefik.enable=true"
- "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80"
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})"
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
# Redirect from EXTRA_DOMAINS to DOMAIN
- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirect"
- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLForceHost=true"
- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLHost=${DOMAIN}"
- coop-cloud.${STACK_NAME}.frontend.version=1.20-c628b67d
volumes:
- site_content:/var/www/html/
entrypoint: "/docker-entrypoint.sh"
configs:
- source: entrypoint_httpd_conf
target: /docker-entrypoint.sh
mode: 0555
- source: httpd_vhosts_conf
target: /usr/local/apache2/conf/extra/httpd-vhosts.conf
configs:
entrypoint_httpd_conf:
name: ${STACK_NAME}_entrypoint_httpd_conf_${ENTRYPOINT_HTTPD_CONF_VERSION}
file: entrypoint.httpd.sh
httpd_vhosts_conf:
name: ${STACK_NAME}_httpd_vhosts_conf_${HTTPD_VHOSTS_CONF_VERSION}
file: httpd-vhosts.conf
template_driver: golang

View File

@ -3,24 +3,23 @@ services:
app:
environment:
- DB_HOST=${STACK_NAME}_db
# - DB_HOST=db
- DB_USER=${DB_USER:-site}
- DB_USER=moodle
- DB_PASSWORD_FILE=/run/secrets/db_password
- DB_NAME=${DB_NAME:-site}
- DB_NAME=moodle
secrets:
- db_password
depends_on:
- db
db:
image: "mariadb:10.6"
image: "mariadb:12.1"
volumes:
- "mariadb:/var/lib/mysql"
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_password
- MYSQL_DATABASE=${DB_NAME:-site}
- MYSQL_USER=${DB_USER:-site}
- MYSQL_DATABASE=moodle
- MYSQL_USER=moodle
- MYSQL_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password

View File

@ -1,6 +0,0 @@
---
version: "3.8"
services:
app:
image: php:${PHP_VERSION}

View File

@ -1,32 +1,46 @@
version: "3.8"
services:
app:
image: php:8.4.3-fpm-alpine3.20
image: php:8.4-fpm-alpine3.22
volumes:
- "site_content:/var/www/html/"
- site_content:/var/www/html/
- moodledata:/var/www/moodledata
networks:
- backend
- proxy
environment:
- PHP_EXTENSIONS
- APP_ENV
- MOODLE_LANGUAGE=${MOODLE_LANGUAGE:-en}
- MOODLE_TIMEZONE=${MOODLE_TIMEZONE:-Europe/Berlin}
- MOODLE_VERSION=${MOODLE_VERSION:-stable501/moodle-latest-501}
- MOODLE_FULLNAME
- MOODLE_SHORTNAME
- MOODLE_ADMINNAME=${MOODLE_ADMINNAME:-admin}
- MOODLE_ADMIN_PASSWORD_FILE=/run/secrets/admin_password
- MOODLE_ADMINMAIL
- MOODLE_SUMMARY
- MOODLE_SUPPORTMAIL
configs:
- source: php_uploads_conf
target: /usr/local/etc/php/conf.d/uploads.ini
- source: php_conf
target: /usr/local/etc/php/conf.d/php.ini
- source: entrypoint_conf
target: /docker-entrypoint.sh
mode: 0555
- source: moodle_conf
target: /var/www/html/config.php
entrypoint: /docker-entrypoint.sh
deploy:
update_config:
failure_action: rollback
order: start-first
labels:
- coop-cloud.${STACK_NAME}.app.version=2.0.0+8.4.3-fpm-alpine3.20
- coop-cloud.${STACK_NAME}.app.version=0.0.1
frontend:
image: nginx:1.20-alpine
networks:
- proxy
- backend
depends_on:
- app
deploy:
@ -50,7 +64,7 @@ services:
target: /etc/nginx/conf.d/default.conf
environment:
- STACK_NAME
- ROOT_PATH
- ROOT_PATH=/var/www/html/public
- DOMAIN
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost"]
@ -60,11 +74,11 @@ services:
# start_period: 1m
networks:
backend:
# internal: true
proxy:
external: true
volumes:
site_content:
moodledata:
configs:
entrypoint_conf:
name: ${STACK_NAME}_entrypoint_conf_${ENTRYPOINT_CONF_VERSION}
@ -74,6 +88,10 @@ configs:
name: ${STACK_NAME}_nginx_default_conf_${NGINX_DEFAULT_CONF_VERSION}
file: nginx.conf
template_driver: golang
php_uploads_conf:
name: ${STACK_NAME}_php_uploads_conf_${PHP_UPLOADS_CONF_VERSION}
file: uploads.ini
php_conf:
name: ${STACK_NAME}_php_conf_${PHP_CONF_VERSION}
file: php.ini
moodle_conf:
name: ${STACK_NAME}_moodle_conf_${MOODLE_CONF_VERSION}
file: config-dist.php.tmpl
template_driver: golang

1347
config-dist.php.tmpl Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
#!/bin/sh
sed -i 's,#Include conf/extra/httpd-vhosts.conf,Include conf/extra/httpd-vhosts.conf,g' /usr/local/apache2/conf/httpd.conf
sed -i '/LoadModule rewrite_module/s/^#//g' /usr/local/apache2/conf/httpd.conf && \
sed -i 's#AllowOverride [Nn]one#AllowOverride All#' /usr/local/apache2/conf/httpd.conf && \
sed -i '/LoadModule proxy_module/s/^#//g' /usr/local/apache2/conf/httpd.conf
sed -i '/LoadModule proxy_fcgi_module/s/^#//g' /usr/local/apache2/conf/httpd.conf
httpd-foreground

View File

@ -1,14 +1,48 @@
#!/bin/sh
echo Installing necessary packages...
apk update
apk add libzip-dev zip libpng-dev libxml2-dev icu-dev alpine-conf sudo
{{ if (env "INSTALL_PACKAGES") }}
apk add {{ env "INSTALL_PACKAGES" }}
{{ end }}
# opcache is only available in the alpine community repo
setup-apkrepos -c1
apk add php84-opcache
echo Installing PHP extensions...
docker-php-ext-install zip
docker-php-ext-install pdo_mysql
docker-php-ext-install mysqli
docker-php-ext-install gd
docker-php-ext-install intl
docker-php-ext-install soap
docker-php-ext-install exif
docker-php-ext-install unicode
{{ if (env "PHP_EXTENSIONS") }}
echo Installing PHP extensions: {{ env "PHP_EXTENSIONS" }}
docker-php-ext-install {{ env "PHP_EXTENSIONS" }}
{{ end }}
# todo: check if already installed
echo "Installing..."
cd /var/www
curl "https://download.moodle.org/download.php/direct/{{ env "MOODLE_VERSION" }}.tgz" -L -o moodle.tgz
tar xzf moodle.tgz --strip-components=1 -C /var/www/html
chown -R root /var/www/html
chmod -R 0755 /var/www/html
mkdir moodledata
chmod 0777 /var/www/moodledata
# run database installer with www user
chown www-data /var/www/html/
cd /var/www/html/admin/cli
sudo -E -u www-data php install_database.php --agree-license --fullname="{{ env "MOODLE_FULLNAME" }}" \
--shortname="{{ env "MOODLE_SHORTNAME" }}" --adminuser="{{ env "MOODLE_ADMINNAME" }}" --adminpass=$(cat /run/secrets/admin_password) --adminemail="{{ env "MOODLE_ADMINMAIL" }}" --summary="{{ env "MOODLE_SUMMARY" }}" --supportemail="{{ env "MOODLE_SUPPORTMAIL" }}"
chown -R root /var/www/html/
echo "Installation finished..."
#fi
exec "$@"
php-fpm

View File

@ -1,17 +0,0 @@
<VirtualHost *:80>
DocumentRoot /var/www/html/
ServerName {{ env "DOMAIN" }}
ErrorLog logs/{{ env "DOMAIN" }}-error_log
CustomLog logs/{{ env "DOMAIN" }}-access_log common
<Directory /var/www/html/>
AllowOverride All
DirectoryIndex index.php index.php
Options -Indexes
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:fcgi://{{ env "STACK_NAME" }}_app:9000"
</FilesMatch>
</VirtualHost>

View File

@ -12,7 +12,7 @@ server {
location / {
index index.html index.htm index.php;
gzip_static on;
try_files $uri $uri/ $uri.html $uri.php index.php?$query_string /index.php?$query_string;
try_files $uri $uri/ /r.php$is_args$args;
}
#error_page 404 /404.html;
@ -32,18 +32,45 @@ server {
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
# try_files $uri /index.php =404;
fastcgi_pass {{ env "STACK_NAME" }}_app:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 600;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
location ~ \.php(/|$) {
# Split the path info based on URI.
fastcgi_split_path_info ^(.+\.php)(/.*)$;
# Note: Store the original path_info. It will be wiped out in a moment by try_files.
set $path_info $fastcgi_path_info;
# Look for the php file, trying a trailing slash for directories if required.
# Finally, send the request to the router - r.php - as a fallback.
try_files $fastcgi_script_name $fastcgi_script_name/ /r.php$is_args$args;
# File was found - pass to fastcgi.
fastcgi_pass {{ env "STACK_NAME" }}_app:9000;
# Alternately, pass to unix socket (depends on pool listen configuration)
# fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
include fastcgi_params;
# Re-apply the path_info after including fastcgi_params.
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
location /dataroot/ {
internal;
alias /var/www/moodledata/; # ensure the path ends with /
}
# Hide all dot files but allow "Well-Known URIs" as per RFC 5785
location ~ /\.(?!well-known).* {
return 404;
}
# This should be after the php fpm rule and very close to the last nginx ruleset.
# Don't allow direct access to various internal files. See MDL-69333
location ~ (/vendor/|/node_modules/|composer\.json|/readme|/README|readme\.txt|/upgrade\.txt|/UPGRADING\.md|db/install\.xml|/fixtures/|/behat/|phpunit\.xml|\.lock|environment\.xml) {
deny all;
return 404;
}
# deny access to .htaccess files, if Apache's document root

17
php.ini Normal file
View File

@ -0,0 +1,17 @@
; This is a subset of the php.ini-production template file: https://github.com/php/php-src/blob/master/php.ini-production
; Extend as needed
; upload settings
file_uploads = On
upload_max_filesize = 256M
post_max_size = 256M
log_errors = On
error_log = /dev/stderr
; opcache, configured according to https://docs.moodle.org/501/en/OPcache
opcache.enable = 1
opcache.revalidate_freq = 60
opcache.enable_cli = 1
zend.exception_ignore_args = On
max_input_vars = 5000

View File

@ -1,3 +0,0 @@
This version adds optional HTTPD (apache) support, instead of the default Nginx.
This "should" be "fine", but please proceed with caution, taking a backup before
upgrade probably even more important than usual.

View File

@ -1,5 +0,0 @@
file_uploads = On
upload_max_filesize = 256M
post_max_size = 256M
log_errors = On
error_log = /dev/stderr