Skip to content

ComboStrap/dokuwiki-docker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

98 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dokuwiki in Docker

About

This repository contains the Dokuwiki in Docker image.

Get a Dokuwiki installation with a website in a single line of command.

Example: Starter Web Site

To get a Dokuwiki server with the Combostrap Starter Site available at http://localhost:8080, execute:

docker run \
  --name combo-site-starter \
  --rm \
  -p 8081:80 \
  -e DOKU_DOCKER_GIT_SITE='https://github.com/ComboStrap/site-starter' \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

Table of Content

The table of content (TOC) is available on GitHub at the right corner of this document.

Features

You got out of the box:

Max and average request durations of Combostrap from the monitoring dashboard

monitoring request duration graph

How to

Set an admin user

By default, a site will run with the readonly ACL policy. The site cannot be edited at all.

If you want to set an admin user, you need to set the following variables:

  • DOKU_DOCKER_ACL_POLICY to public: the policy applied
  • DOKU_DOCKER_ADMIN_NAME to the user admin name
  • DOKU_DOCKER_ADMIN_PASSWORD to the user admin password
  • DOKU_DOCKER_ADMIN_EMAIL to the user admin email (Optional)

Example:

docker run \
  --name combo-site-starter \
  --rm \
  -p 8081:80 \
  -e DOKU_DOCKER_ACL_POLICY='public' \
  -e DOKU_DOCKER_ADMIN_NAME='admin' \
  -e DOKU_DOCKER_ADMIN_PASSWORD='welcome' \
  -e DOKU_DOCKER_ADMIN_EMAIL='admin@example.com' \
  -e DOKU_DOCKER_GIT_SITE='https://github.com/ComboStrap/site-starter' \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

The above command:

Mount a Volume

You may mount a volume to keep your installation intact between restart.

Example:

  • Desktop Linux / Windows WSL
cd ~/your-site
docker run \
  --name combo-site-starter \
  --rm \
  --user 1000:1000 \
  -p 8081:80 \
  -v $PWD:/var/www/html \
  ghcr.io/combostrap/dokuwiki:php8.3-latest
  • On Windows, don't bind mount a local directory as volume. See perf

On a desktop, Dokuwiki would be available at: http://localhost:8081

Note: If the volume is empty, after the run, it will be filled with a new dokuwiki installation.

Choose the installed dokuwiki version

You can choose the initial version to install via the DOKUWIKI_VERSION environment.

Example with the 2024-02-06b "Kaos" release

docker run \
  --name combo-site-starter \
  --rm \
  -p 8081:80 \
  -e DOKUWIKI_VERSION=2024-02-06b \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

Get Healthcheck / Liveness / Probes / Container State

If you wish to set a healthcheck point, you may use:

  • the dokuwiki ping endpoint /dokuwiki-docker/ping.php (ie ping.php endpoint)
  • or the php-fpm endpoint /php-fpm/doku/ping (ie to the ping.path and ping.response configurations)

Note that:

  • if the page php-fpm is full because there is too much request (bots or visitors), the dokuwiki ping will fail while the php-fpm endpoint will not
  • if you want more control on php-fpm, you can create your own image and use the php-fpm-healthcheck

Example:

  • in docker: the HEALTCHECK is already defined in the Dockerfile
  • in a Kubernetes manifest
containers:
  - name: container-name
    # Startup Probe: Used to check if the application has started before starting the other probes
    # periodSeconds * failureThreshold = 10 * 10 = 100 seconds to starts
    startupProbe:
      httpGet:
        path: /dokuwiki-docker/ping.php
        port: 80
      # 5 seconds after the start
      initialDelaySeconds: 5
      # The probe is performed every 55 second
      periodSeconds: 10
      # after 3 failed prob, the container is considered unhealthy.
      failureThreshold: 10
      # after 1 successful prob, the container is considered healthy.
      successThreshold: 1
    # Readiness Probe: Checks if the app is ready to serve traffic.
    # If it fails, the pod is removed from the service endpoints.
    # Used also in rollout
    readinessProbe:
      httpGet:
        path: /dokuwiki-docker/ping.php
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
      failureThreshold: 3
      successThreshold: 1
    # livenessProbe Probe
    # If it fails, the pod is restarted
    livenessProbe:
      httpGet:
        path: /dokuwiki-docker/ping.php
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
      failureThreshold: 3
      successThreshold: 1

Disable Automatic Default Starter WebSite Installation

By default, this image will install the default Starter ComboStrap WebSite automatically after the initial Dokuwiki Installation.

To disable this behavior, you need to set the DOKU_DOCKER_STARTER_SITE environment variable to false

docker run -e DOKU_DOCKER_STARTER_SITE=false

Set in dev mode

By default, this image will run php in production mode. You can set it in dev mode via the DOKU_DOCKER_ENV to see warning and other alerts.

Example:

docker run -e DOKU_DOCKER_ENV=dev ....

Configure Php

Php can be configured via environment variables.

The convention is that you need to:

  • capitalize the configuration name
  • replace all separator by _
  • and add PHP_ as prefix.

For instance for the date.timezone, you need to set the PHP_DATE_TIMEZONE environment.

docker run -e PHP_DATE_TIMEZONE=UTC ....

All actual possibles configurations can be seen in the php dokuwiki-docker.ini files

Configure Php-Fpm Pool

Php-Fpm runs 2 pools of threads:

  • pages: with the highest priority, for page rendering (ie doku.php and css.php)
  • www (default): with the lowest priority, for all other requests (image, media, ...)

You can configure them with the following environment variables.

# Doku Pool (Pages)
PHP_FPM_PM_PAGES_MAX_SPARE_SERVERS=1 # the minimum number of thread in idle
PHP_FPM_PM_PAGES_MAX_SPARE_SERVERS=2 # the maximum number of thread in idle
PHP_FPM_PM_PAGES_MAX_CHILDREN=3 # the maximum number of threads
PHP_FPM_PM_PAGES_MAX_REQUESTS=500 # Number of requests processed before restart (0 means no restart)
PHP_FPM_PM_PAGES_MEMORY_LIMIT=128M # The maximum amount of request memory (the php default)
# WWW Pool (Default, media)
PHP_FPM_PM_WWW_MIN_SPARE_SERVERS=2
PHP_FPM_PM_WWW_MAX_SPARE_SERVERS=3
PHP_FPM_PM_WWW_MAX_CHILDREN=4
PHP_FPM_PM_WWW_MAX_REQUESTS=500
PHP_FPM_PM_WWW_MEMORY_LIMIT=384M # 384 and not 128 because of the taskrunner indexing 

The pages pool has less thread than the default pool because for one page, you ask much more resources (one or more image, ...).

How to use? For instance for the max.children number of threads for the doku pool, you would need to set the PHP_FPM_PM_PAGES_MAX_CHILDREN environment.

To change it from 3 to 4

docker run -e PHP_FPM_PM_PAGES_MAX_CHILDREN=4 ....

The pool configuration will result in a low or high memory usage. See the dedicated section

The environment variables are used in their corresponding files:

Note: The priority of the pool was set via the process.priority php-fpm configuration but is no more used because it kills pod to pod network communication on Kubernetes.

Calculate the Memory Capacity Sizing

The total memory is memory taken by the php code:

  • at rest
  • at request time

Memory at rest

Memory at rest is the space taken by all php classes loaded in memory.

Below is an example of a 221Mb container after a load of 4 bots downloading the whole Combostrap website with the default sizing:

32 MB php-fpm: master process
37 MB php-fpm: pool doku
34 MB php-fpm: pool www
34 MB php-fpm: pool www
54 MB caddy run -c
30 MB /usr/bin/python3 /usr/bin/supervisord -c

You can configure the maximum number of php-fpm children threads to manage the maximum memory size.

You can count:

  • 40MB by thread
  • 35MB for the master php-fpm thread
  • 60MB for the Caddy web server
  • 30MB for the process controller (supervisor)

Memory at request time

The memory limit is the memory that the php request will use.

The default value is defined by pool:

You may increase this values in the pool configuration

They are maximum, the memory used on a request by request basis are way lower

  • between 2 and 30M for a large wiki
  • between 2 and 7M for a normal wiki.

Example of a large wiki:

Request memory

Why? Because dokuwiki loads the images and index in memory for processing.

Test a load

You can test your website by download it with wget

Example:

WEBSITE_URL=https://combostrap.com # replace with your URL
wget --recursive --level=inf --no-parent --timestamping --quiet --show-progress --output-file=wget-log.txt "$WEBSITE_URL"

If you start this command 4 times, you would fake 4 bots, crawling your website.

Get Php Info Endpoint

To see the actual configuration, you can hit the endpoint:

http://localhost:8081/dokuwiki-docker/phpinfo.php

This endpoint is protected by the admin user credentials. If you want to get access, you need to set the admin user

Run as the host user

By default, the container will run as root but if you mount a volume from your desktop, you may want to change the user to the host user to not get any permission issues.

You do it by setting the user option.

# check your ids (uid:gid)
# By default, the first user is 1000:1000
# and was created with the name `me`
id
# then use them
docker run \
  --user 1000:1000 \
  --rm \
  -p 8081:80 \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

Get a Bash Shell in the container

Example:

docker exec -ti your-container-name bash 
# example
docker exec -ti combo-site-starter bash

Note that you get the same environment as the running container thanks to the bash.bashrc located at /etc/bash.bashrc.

Change the savedir configuration

If you want to use data has a namespace (ie https://example.com/data/yourpage), you can't by default because the savedir is forbidden for security reasons by the web server

To use data as a namespace, you need to

  • rename the directory data to dokudata
  • set the savedir configuration to dokudata in your conf/local.php file
$conf['savedir'] = './dokudata';
  • set the environment DOKU_DOCKER_SAVE_DIR to dokudata in a docker run
docker run \
  -e DOKU_DOCKER_SAVE_DIR='dokudata' \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

Note: You can change the dokudata value to whatever you want.

Update the Docker image

We support for now only one tag by php version, therefore you need to delete the image before pulling it again

Example for php8.3

docker rmi ghcr.io/combostrap/dokuwiki:php8.3-latest
docker pull ghcr.io/combostrap/dokuwiki:php8.3-latest

How to disable the automatic update of the search index

When a pod/container is starting the Search Index is updated, otherwise any search or Combo SQL would not return any data.

If you wish to disable this automatic update, you need to set the environment variable DOKU_DOCKER_SEARCH_INDEX to off

Example:

docker run \
  -e DOKU_DOCKER_SEARCH_INDEX='off' \
  ...

You can then update it with the comboctl tool.

Example with the starter site

docker exec -ti combo-site-starter comboctl index

Note on Performance:

  • In case of rollout, this extra processing should not impact the availability of your container if you set the readiness probes
  • If the rollout takes too long, you need to set up a volume so that the index is only updated and not created from scratch.

How to clean up a Dokuwiki Instance (maintenance)?

Dokuwiki creates a lot of temporary files that needs to be removed periodically to keep the size on the disk small.

The DokuWiki Docker image contains the comboctl cli cleanup function
to do exactly that.

You can execute it like that. Example with the starter container name:

docker exec \
  -e BASH_ENV=/etc/bash.bashrc \
  combo-site-starter \
  bash -c 'comboctl cleanup' 

It will:

  • Purge the cache
  • Purge the attic (old revisions)
  • Purge the locks
  • Purge the sqlite log of Combo cache and Router Redirections
  • Clean the meta (pages and media) directories. It ensures that there is one meta, changes or indexed file by page or media.

You can control the retention days with the following environment variables:

  • DOKU_DOCKER_CLEAN_CACHE_RETENTION_DAYS: the retention days for the cache (default to 10)
  • DOKU_DOCKER_CLEAN_ATTIC_RETENTION_DAYS: the retentions days for the old pages revisions (default to 360)
  • DOKU_DOCKER_CLEAN_MEDIA_ATTIC_RETENTION_DAYS: the retentions days for the old media revisions (default to 90)

Example with the starter container name

docker exec \
  -e BASH_ENV=/etc/bash.bashrc \
  -e DOKU_DOCKER_CLEAN_CACHE_RETENTION_DAYS=5 \
  -e DOKU_DOCKER_CLEAN_ATTIC_RETENTION_DAYS=90 \
  -e DOKU_DOCKER_CLEAN_MEDIA_ATTIC_RETENTION_DAYS=30 \
  combo-site-starter \
  bash -c 'comboctl cleanup' 

The dedicated Dokuwiki Web Page on maintenance has more information on this topic.

How to define the rate limit for pages?

By default, there is a rate limit of max 2 pages every 1 second.

A human would not click quicker.

You can configure the rate limite for pages via this environment variables:

DOKU_DOCKER_PAGES_RATE_LIMIT_EVENTS=2 # the number of pages request
DOKU_DOCKER_PAGES_RATE_LIMIT_WINDOW=1s # the window (1s) 

Note that if you are behind a proxy, you should be sure to set it as trusted otherwise the client would be the proxy, and you would hit the rate limit pretty quickly.

To disable the rate limit, you need to increase the rate limit environment variables.

Performance

How to report slow requests?

By default, the image will not report any slow request for the pages

You can enable it by setting the environment variable PHP_FPM_PM_PAGES_REQUEST_SLOWLOG_TIMEOUT to a period of time.

Example: Setting all pages request above 1s as slow:

docker run \
  -e PHP_FPM_PM_PAGES_REQUEST_SLOWLOG_TIMEOUT=1s # ie upper limit of human flow of though

Note:

The slow request and their trace will be logged into the file /var/log/php-fpm/pages.slow.log

How to install and configure a large wiki

A large wiki is a wiki with a thousand of pages and media.

You will recognize them when the search index update takes a long time to refresh (more than one minute).

Example of a 4.9G dokuwiki data directory. As you can see the cache directory is 12 times bigger than the raw data (ie pages and media)

3.5G    ./cache
285M    ./media
184M    ./meta
821M    ./attic
53M     ./pages
26M     ./media_attic
15M     ./index
5.4M    ./media_meta
1.5M    ./log
68K     ./locks
960K    ./tmp

With a large wiki, you should:

Example:

docker run \
  -e DOKU_DOCKER_SEARCH_INDEX='off' \
  -v $PWD:/var/www/html \
  ...

If your data lives in Git, you should consider using git-lfs to reduce the size of the volume. Why ? Because otherwise you get your media (images, ...), not once but twice:

  • in the .git directory
  • and in the working directory (ie data\media)

Poor Windows Perf with Local Directory Volume

On Windows, you should not mount a windows host local directory because it will be fucking slow.

ie DON'T do that

docker run ^
  -v c:\home\username\your-site:/var/www/html ^
  ghcr.io/combostrap/dokuwiki:php8.3-latest

Mounting a Windows folder into a Docker container is always slow no matter how you do it. WSL2 is even slower than WSL1 in that respect.

See the related issue that explains that this is structural.

The solution is buried into the Docker WSL best practice

It's recommended that you store source code and other data that is bind-mounted into Linux containers.

You should then:

  • move the site data into the WSL Distro
  • and from a Linux shell run:
docker run \
  -v ~\your-site:/var/www/html \
  ghcr.io/combostrap/dokuwiki:php8.3-latest

How to Git

DokuWiki Docker supports two developments mode with Git:

  • the pull mode: you create your pages locally, and you make them public by pulling your Git repository
  • the push mode: you create your pages on the server, and you push your changes

Git: Pull Mode - Set your ComboStrap Git WebSite

In this mode, you would:

To publish your website, you would then define the ComboStrap WebSite with the $DOKU_DOCKER_GIT_SITE environment variable to a git URL.

Example:

# https
docker run -e DOKU_DOCKER_GIT_SITE=https://github.com/ComboStrap/site-starter.git
# ssh
docker run -e DOKU_DOCKER_GIT_SITE=git@github.com:namespace/repo.git

Git: Push mode

In Push mode, you will commit and push changes from your Docker container to your Git Repository.

You can make change online from your server container and push them to your git repository.

To make this happen, you need to perform the following configuration:

  • Create a private SSH key and register it in your Git Provider. Example: GitHub
  • At the run command
    • Mount the private SSH key with a standard default name (ie for instance id_ed25519) in the ~/ssh directory.
    • Set the Git URI to an SSH one.; ie git@github.com:namespace/repo.git, not https://
docker run \
  -e DOKU_DOCKER_GIT_SITE=git@github.com:namespace/repo.git  
  ghcr.io/combostrap/dokuwiki:php8.3-latest
  • Get into your container / pod
# docker
docker exec -it containerName bash -l
# Kubernetes
kubectl exec -it podName -- bash -l
kubectl exec -it $(kubectl get pod -l app=appName -o jsonpath='{.items[0].metadata.name}') -- bash -l
  • The Git Author Info are already set to the admin user and email, but you can change them with the following commands:
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
  • You can now use git as normal and push any changes
git status
git add .
git commit -m "My Commit message"
git push

How to monitor DokuWiki Docker

You can get the php-fpm metrics on the status page for the 2 pools at:

  • localhost/php-fpm/pages/status for the pages pool
  • localhost/php-fpm/www/status for the default pool

You can extract them

  • via curl
  • via an Prometheus exporter

And graph them

Monitoring php-fpm with Curl

Example:

# Pages Pool
docker exec -ti combo-site-starter curl localhost/php-fpm/pages/status?full
# Default Pool (Media, Task Runner...)
docker exec -ti combo-site-starter curl localhost/php-fpm/www/status?full
pool:                 doku
process manager:      dynamic
start time:           07/Aug/2024:14:04:53 +0000
start since:          173
accepted conn:        21
listen queue:         0
max listen queue:     0
listen queue len:     4096
idle processes:       1
request method:       GET
request URI:          /php-fpm/doku/status?full
content length:       0
user:                 -
script:               /var/www/html
last request cpu:     0.00
last request memory:  0

The status endpoint is available only from localhost (ie ip 127.0.0.1) for security reason therefore you need to run it via docker exec

For the documentation over the data and usage, see the configuration file

Monitoring php-fpm with Prometheus

You can use the HiPages php-fpm_exporter to collect the metrics.

Example as side container in Kubernetes.

initContainers:
  - name: php-fpm-exporter
    image: hipages/php-fpm_exporter:2.2.0
    restartPolicy: Always
    env:
      - name: PHP_FPM_SCRAPE_URI
        value: "tcp://127.0.0.1:9000/status,tcp://127.0.0.1:9001/status"
      - name: PHP_FPM_FIX_PROCESS_COUNT
        value: "1"
    ports:
      - containerPort: 9253

Monitoring php-fpm Dashboard

We have created a new relic dashboard that you can get here.

It's based on:

Example of graph: the max and average request durations of https://combostrap.com

monitoring request duration graph

Docker Image

Docker Tag

We support for now only one tag by php version, therefore you need to delete the image before pulling it again

php8.3-latest

where:

  • phpX.X is the php version used
  • latest is the version of this image

Dokuwiki is installed if not found on the volume. See how to choose the installed dokuwiki version

Docker Image Components

All images contain :

Docker Image List

The list of Docker images is available on GitHub

How to contribute

If you want to contribute to this image, check the dev page that explains how to start the image to develop the script.

FAQ

Is the Docker Image Proxy Ready?

Yes. By default, this image will trust all proxy that are in a private range.

ie: 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 fd00::/8 ::1

Otherwise, you can set the IP or CIDR of trusted proxy with the DOKU_DOCKER_TRUSTED_PROXY environment variable

# example with a Kubernetes CIDR node where the ingress is installed
DOKU_DOCKER_TRUSTED_PROXY=10.42.1.0/24

More information on the value can be found in the trusted-proxy caddy documentation

Note that the client_ip is configured to get the value from these headers:

  • Cf-Connecting-Ip - Cloudflare Proxy
  • X-Forwarded-For - Proxy Protocol
  • X-Real-IP

The Caddy web access log also reports the client_ip and not the remote_ip (ie proxy ip)

Why the volume contains a whole dokuwiki installation

Why the volume contains a whole dokuwiki installation, and we do not use symlink as the official image to keep backup data as specified in the oficial backup documentation

Because it's too damn hard to keep the state of an installation.

  • Plugins does not use a version/release system.
  • You then need to back up the lib directory that contains the most code.
  • Configuration file may be scattered around. Example:
  • Identification file are co-located with configuration file in the conf directory.
  • Runtime data are mixed with persistent data into the data directory (ie cache/index/tmp)
  • meta contains persistent (original data) and runtime metadata (ie derived from the text)

If you want to keep the size low, you need to:

Why my sitemap is not generating URL with https?

DokuWiki detects ssl with the is_ssl function.

You should make sure that:

Where is the web access log file?

The access log file:

  • is located at /var/log/caddy/access.log
  • has the Apache Common Log format
  • with the real client_ip (instead of the remote_ip)

Support

How to debug a crashing container

By default, in production mode, we don't allow any error to occur otherwise the script terminate.

If you want to allow the container to get up, you need to set:

Example:

docker run \
  -e DOKU_DOCKER_STRICT=false \
  -e DOKU_DOCKER_SEARCH_INDEX='off'
  ....

How to see the fatal errors?

The errors are available:

  • in the file: /var/log/php/error.log
  • and in the docker logs

What if the taskrunner takes a long time to run?

The taskrunner task may take up to 5 seconds to run because we try to get a lock.

If this behaviour is continuous, it's possible that there is a memory problem. You may confirm that by looking at the error logs

For large wiki, you may want to increase the memory of the default pool to `512Mo.

docker run \
  -e PHP_FPM_PM_WWW_MEMORY_LIMIT=512M

What if I get the Git error Host key verification failed

This error comes from Git when it invokes SSH to connect to your Git repository

By default, SSH will check if the target host is trusted by searching it in the ~/.ssh/known_hosts file. If it can find it, SSH returns the error Host key verification failed.

By default, we update the known_hosts at startup with the GitHub hosts via the ssh known host updater.

If you want to connect to other git provider, you can:

  • mount your own ~/.ssh/known_hosts file
  • or set the environment variable GIT_SSH_COMMAND with the less strict HostKey checking option. Example:
docker \
 -e GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new"

Other related projects