This repository contains the Dokuwiki in Docker
image.
Get a Dokuwiki installation with a website in a single line of command.
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
The table of content (TOC) is available on GitHub at the right corner of this document.
You got out of the box:
- Website instance
- You can:
- Nice URL rewrite
- Automatic Search Index Update
- Automatic Plugins Installation
- SEO Ready: SiteMap Enabled by default to 5 days
- Healthcheck Endpoint
- Metrics Endpoint
- Last Patches
- Dev Mode
- Proxy Ready (to report the real ip behind a proxy)
- Maintenance Ready
- Out-of-Memory error protection with a Dedicated Pages Processing Pool and max request configuration
- Crawl/Scan protection with rate limiting
- Git Ready with 2 mode of developments:
- Request Performance:
- Php Fpm - php instance pooling
- OpCache - php compilation cache
- Pages and Media Thread Pool - dedicated pool separated between pages and media requests
Max and average request durations of Combostrap from the monitoring dashboard
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
topublic
: the policy appliedDOKU_DOCKER_ADMIN_NAME
to the user admin nameDOKU_DOCKER_ADMIN_PASSWORD
to the user admin passwordDOKU_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:
- publish the ComboStrap default install website
- and configure it with the admin user:
- name
admin
- password
welcome
- email
admin@example.com
- name
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.
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
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 theping.path
andping.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
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
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 ....
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
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_MIN_SPARE_SERVERS=1 # the minimum number of thread in idle
PHP_FPM_PM_PAGES_MAX_SPARE_SERVERS=1 # 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=1
PHP_FPM_PM_WWW_MAX_SPARE_SERVERS=1
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.
The total memory is memory taken by the php code:
- at rest
- at request time
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)
The memory limit
is the memory that the php request will use.
The default value is defined by pool:
128Mo
for the pages pool (the default dokuwiki value is 256M)384Mo
for the default pool (due to the dokuwiki task runner that needs to load index)
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:
Why? Because dokuwiki loads the images and index in memory for processing.
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.
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
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
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
.
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
todokudata
- set the
savedir
configuration todokudata
in yourconf/local.php
file
$conf['savedir'] = './dokudata';
- set the environment
DOKU_DOCKER_SAVE_DIR
todokudata
in adocker 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.
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
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.
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.
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.
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:
- A value of '0s' means 'off'.
- Php-Fpm request slow log documentation
The slow request and their trace will be logged into the file /var/log/php-fpm/pages.slow.log
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:
- mount a volume:
- to speed up the download of your site
- to keep the search index between restart
- increase the default memory limit of the default pool
- to avoid the memory error on index building of the task runner
- disable search index update/
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
)
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
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
In this mode, you would:
- run DokuWiki Docker locally with a volume mount
- push your changes to your Git Repository
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
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
, nothttps://
- Mount the private SSH key with a standard default name (ie for instance
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
You can get the php-fpm metrics on the status page for the 2 pools at:
localhost/php-fpm/pages/status
for thepages
poollocalhost/php-fpm/www/status
for thedefault
pool
You can extract them
- via curl
- via an Prometheus exporter
And graph them
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
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
We have created a new relic dashboard that you can get here.
It's based on:
- the prometheus exporter metrics
- a
service
label that contains the name of your Combostrap Dokuwiki Docker instance. The kubernetes prometheus operator add it automatically
Example of graph: the max and average request durations of https://combostrap.com
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 usedlatest
is the version of this image
Dokuwiki is installed if not found on the volume. See how to choose the installed dokuwiki version
All images contain :
- Php-fpm for php execution
- Opcache for php cache compilation
- Caddy as webserver
- Supervisor as process manager
The list of Docker images is available on GitHub
If you want to contribute to this image, check the dev page that explains how to start the image to develop the script.
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 ProxyX-Forwarded-For
- Proxy ProtocolX-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, 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:
- perform cleanup administrative task.
- or to create a site without any volume.
DokuWiki detects ssl with the is_ssl function.
You should make sure that:
- the trusted proxy conf is not empty (By default, it's not)
- the
HTTP_X_FORWARDED_PROTO
header is forwarded if you use a proxy. This image do it for all proxy in a private range.
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 theremote_ip
)
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:
- strict to
false
- eventually disable the search index update
Example:
docker run \
-e DOKU_DOCKER_STRICT=false \
-e DOKU_DOCKER_SEARCH_INDEX='off'
....
The errors are available:
- in the file:
/var/log/php/error.log
- and in the docker logs
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
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"