diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/ci.yml
similarity index 92%
rename from .github/workflows/docker-publish.yml
rename to .github/workflows/ci.yml
index 07315bf..026ad69 100644
--- a/.github/workflows/docker-publish.yml
+++ b/.github/workflows/ci.yml
@@ -1,8 +1,8 @@
-name: Docker Publish
+name: CI
on:
push:
- tags: [ 'cp*.*.*-rev*' ]
+ tags: [ '*.*.*-r*' ]
pull_request:
branches: [ master ]
@@ -62,11 +62,11 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
- type=match,pattern=cp(\d+\.\d+),group=1
- type=match,pattern=cp\d+\.\d+
- type=match,pattern=cp([^-]+),group=1
- type=match,pattern=cp[^-]+
- type=match,pattern=cp.+
+ type=match,pattern=(\d+\.\d+),group=1
+ type=match,pattern=\d+\.\d+
+ type=match,pattern=([^-]+),group=1
+ type=match,pattern=[^-]+
+ type=match,pattern=.+
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..93d1f86
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+
+## 1.7.1-rc1
+
+* **BREAKING CHANGES**:
+
+ * Migrated to Alpine + Nginx + php-fpm. This allowed to reduce memory usage from ~300MB to ~40MB!
+ * Changed versioning convention from `cpXXX-revYYY` to `CLASSICPRESS_VERSION-rRELEASE_NUMBER`
+ * Migrated from `APACHE_RUN_USER_ID` and `APACHE_RUN_GROUP_ID` to shared between host and container group `press(gid=2048)`.
+ * `wp-config.template.php` now contains `define('WP_AUTO_UPDATE_CORE', false);` which should stop CP from auto-updating (this is added only to new installations, so it may be that you must add it manually to your config)
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 064af22..ef81714 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -4,16 +4,16 @@ The simplest way to build this image locally, it's to use Docker Compose.
To do so, you will need to create 2 files: `CP_DB_PASSWORD.secret` and `DB_ROOT_PASSWORD.secret` (files with `.secret` extension are git-ignored).
```sh
-export UID=$(id -u)
-export GID=$(id -g)
echo "my_secret_password" > secrets/CP_DB_PASSWORD.secret
echo "turbo_secret_password" > secrets/DB_ROOT_PASSWORD.secret
```
+Remamber to have a group `press(gid=2048)` and your user is assigned to it.
+
Now, you simply run:
```sh
docker compose -f docker-compose.dev.yaml up
```
-The container will be accessible via http://localhost:8000
+The container will be accessible via http://localhost:8080
diff --git a/README.md b/README.md
index 02cfd50..d8ca3a6 100644
--- a/README.md
+++ b/README.md
@@ -4,17 +4,25 @@ Quote from [www.classicpress.net](https://www.classicpress.net/):
> ClassicPress is a community-led open source content management system and a fork of WordPress that preserves the TinyMCE classic editor as the default option.
+## Changelog
+
+[Open changelog](https://github.com/marverix/classicpress-docker/blob/master/CHANGELOG.md)
+
## Tags
+
### Convention
-Tagging convention is: `cpXXX-revYYY`
+Tagging convention is: `CLASIC_PRESS_VERSION-rRELEASE`
+
+`CLASIC_PRESS_VERSION` is ClassicPress version, `RELEASE` is Docker Image release number. Eg. `1.7.1-r1`.
-`XXX` is ClassicPress version. `YYY` is Docker Image revision number.
## Basic Information
-* The image is based on [`php:7.4-apache-bullseye`](https://hub.docker.com/_/php?tab=tags&name=7.4-apache-bullseye)
+* The image is based on Alpine 3.16 and php 8.0 (3.16 is a bit old, but it's last version having php8.0 which is required by ClassicPress 1.x)
+* Some code taken from [`TrafeX/docker-php-nginx:2.5.0`](https://github.com/TrafeX/docker-php-nginx) which I highly recommend! Unfortunatelly I coudln't use it (inherit) because Docker has no mechanism to "unexpose" port and remove health check
+* Thanks to Alpine + Nginx + php-fpm, the image is using only around ~40MB of RAM
* Has enabled all required and recommended php extensions for WordPress
-* Has installed [`apache2-mod-security2`](https://github.com/SpiderLabs/ModSecurity) with [enabled OWASP CSR](https://owasp.org/www-project-modsecurity-core-rule-set/)
+* Basic security hardening done
* Support for Docker Secrets via env variables with `_FILE` suffix
Note: Even with basic hardening done, it's highly recommended to not to expose a container directly to the outside world. Consider using a reverse proxy like [traefik](https://doc.traefik.io/traefik/) or [Nginx Proxy Manager](https://nginxproxymanager.com/).
@@ -28,35 +36,22 @@ https://hub.docker.com/r/marverix/classicpress/tags
Good Docker practice is that one service/server == one docker container, this is why you will still need to run separate container
with a database (MySQL/MariaDB).
-### Privilages
-
-Apache server inside is using two environment variables to set privilages:
-
-* `APACHE_RUN_USER_ID`
-* `APACHE_RUN_GROUP_ID`
-
-By default Docker runs everything with _root_ privilages. There are many great articles describing the impications of this solution, like:
+### Write Permission
-* [File Permissions: the painful side of Docker](https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/)
-* [Permission problems in bind mount in Docker Volume](https://techflare.blog/permission-problems-in-bind-mount-in-docker-volume/)
-* [File permissions on Docker volumes](https://ikriv.com/blog/?p=4698)
+This image deals with write access shared between host and the container by group `press` (and user) with ID _2048_. This is why your user running the container must be in this group.
-This is why this image is running the Apache server as `apache:apache`.
-The trick here is, that Apache's user ID (`APACHE_RUN_USER_ID`) and group ID (`APACHE_RUN_GROUP_ID`) are set on fly, to user ID and group ID of the docker container runner. Only downside of this solution is that
-you need to set `UID` and `GID` env variables (for example in `~/.bashrc`) like this:
+If you are running Debian/Ubuntu-based run on your host machine:
```sh
-export UID=$(id -u)
-export GID=$(id -g)
+sudo groupadd -g 2048 press
+sudo usermod $(whoami) -aG press
```
-With this, you can use it in Docker Compose like this:
+Read more:
-```yaml
- environment:
- - "APACHE_RUN_USER_ID=${UID}"
- - "APACHE_RUN_GROUP_ID=${GID}"
-```
+* [File Permissions: the painful side of Docker](https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/)
+* [Permission problems in bind mount in Docker Volume](https://techflare.blog/permission-problems-in-bind-mount-in-docker-volume/)
+* [File permissions on Docker volumes](https://ikriv.com/blog/?p=4698)
### With Docker Compose
@@ -105,8 +100,6 @@ docker-compose -f docker-compose.example.yaml --env-file=myblog-env-example up
--expose 80:80 \
--name myblog \
--volume myblog_data:/data \
- --env APACHE_RUN_USER_ID=$UID \
- --env APACHE_RUN_GROUP_ID=$GID \
--env CP_DB_NAME=myblog_db \
--env CP_DB_USER=myblog_user \
--env CP_DB_PASSWORD=my_secret_passowrd \
diff --git a/classicpress/000-default.conf b/classicpress/000-default.conf
deleted file mode 100644
index c09971e..0000000
--- a/classicpress/000-default.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-
- DocumentRoot /var/www/html
-
- ServerName localhost
- ServerAdmin webmaster@localhost
- ServerSignature Off
-
- ErrorLog ${APACHE_LOG_DIR}/error.log
- CustomLog ${APACHE_LOG_DIR}/access.log combined
-
- AddDefaultCharset UTF-8
-
- SecRuleEngine On
- SecStatusEngine On
-
diff --git a/classicpress/Dockerfile b/classicpress/Dockerfile
index bdcf448..7a36735 100644
--- a/classicpress/Dockerfile
+++ b/classicpress/Dockerfile
@@ -1,8 +1,11 @@
-FROM php:8.1-apache-bullseye
+FROM alpine:3.16
+
+LABEL Maintainer="Marek SierociĆski"
+LABEL Description="ClassicPress image based on trafex/php-nginx"
# Version of ClassicPress
-ARG version=1.5.3
-ARG corerules_version=3.3.4
+ARG version=1.7.1
+# ARG corerules_version=3.3.4
ARG www_dir=/var/www/html
ARG WORKDIR_BUILD=/tmp/build
@@ -13,45 +16,59 @@ ENV WWW_DIR=${www_dir}
ENV DATA_DIR=/data
ENV WP_CONFIG=${DATA_DIR}/wp-config.php
ENV WP_CONTENT=${DATA_DIR}/wp-content
-ENV BACKUP_WP_CONTENT="${WWW_DIR}/../wp-content-backup"
+ENV PRESS_USER=press
+ENV PRESS_HOME=/home/${PRESS_USER}
+ENV BACKUP_WP_CONTENT="${PRESS_HOME}/wp-content-backup"
-ENV APACHE_RUN_USER=apache
-ENV APACHE_RUN_GROUP=www-data
+WORKDIR /var/www/html
-ENV LC_ALL=en_US.UTF-8
-ENV LANG=en_US.UTF-8
-ENV LANGUAGE=en_US.UTF-8
+# Update packages index
+RUN apk update \
+ # Install packages
+ && apk add --no-cache \
+ bash \
+ curl \
+ nginx \
+ php8 \
+ php8-ctype \
+ php8-curl \
+ php8-dom \
+ php8-fpm \
+ php8-gd \
+ php8-intl \
+ php8-mbstring \
+ php8-mysqli \
+ php8-opcache \
+ php8-openssl \
+ php8-phar \
+ php8-session \
+ php8-xml \
+ php8-xmlreader \
+ php8-zlib \
+ supervisor
COPY ./ ${WORKDIR_FILES}/
-# Install packages
-RUN apt-get update \
- && apt-get install -y \
- apt-transport-https lsb-release ca-certificates wget gnupg2 \
- && wget -qO - https://modsecurity.digitalwave.hu/archive.key | apt-key add - \
- && sh -c 'echo "deb http://modsecurity.digitalwave.hu/debian/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/dwmodsec.list' \
- && sh -c 'echo "deb http://modsecurity.digitalwave.hu/debian/ $(lsb_release -sc)-backports main" >> /etc/apt/sources.list.d/dwmodsec.list' \
- && apt-get update \
- && apt-get install -y \
- libapache2-mod-security2 libmodsecurity3 \
- zlib1g-dev libpng16-16 libpng-dev libzip4 libzip-dev locales \
-# Ensure UTF-8
- && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
- && locale-gen \
-# Change working directory
- && mkdir -p ${WORKDIR_DOWNLOADS} \
- && cd ${WORKDIR_DOWNLOADS} \
-# Download ClassicPress
+# Prepare users
+RUN adduser -D -u 2048 press \
+ && addgroup press press \
+ && addgroup press nginx
+
+# Configure services
+RUN cp ${WORKDIR_FILES}/conf/php.ini /etc/php8/conf.d/custom.ini \
+ && cp ${WORKDIR_FILES}/conf/fpm-pool.conf /etc/php8/php-fpm.d/www.conf \
+ && cp ${WORKDIR_FILES}/conf/nginx.conf /etc/nginx/nginx.conf \
+ && cp ${WORKDIR_FILES}/conf/supervisord.conf /etc/supervisord.conf \
+&& rm -rf ${www_dir}/*
+
+# Install ClassicPress
+RUN mkdir -p ${WORKDIR_DOWNLOADS} && cd ${WORKDIR_DOWNLOADS} \
&& wget -qO classicpress.tar.gz https://github.com/ClassicPress/ClassicPress-release/archive/refs/tags/${version}.tar.gz \
-# Download corerules
- && wget -qO corerules.tar.gz https://github.com/coreruleset/coreruleset/archive/refs/tags/v${corerules_version}.tar.gz \
-# Clean www_dir
- && rm -rf ${www_dir}/* \
-# Unpack ClassicPress to www_dir
- && tar -xf classicpress.tar.gz -C ${www_dir} --strip-components=1 \
+ && tar -xf classicpress.tar.gz -C ${www_dir} --strip-components=1
+
+# Setup
# Create /data
- && mkdir ${DATA_DIR} \
- && cd ${DATA_DIR} \
+RUN mkdir ${DATA_DIR} && cd ${DATA_DIR} \
# Move wp-content to /data
&& mv ${www_dir}/wp-content ${WP_CONTENT} \
&& ln -s ${WP_CONTENT} ${www_dir}/wp-content \
@@ -60,53 +77,24 @@ RUN apt-get update \
&& touch ${WP_CONFIG} \
&& ln -s ${WP_CONFIG} ${www_dir}/wp-config.php \
# Copy wp-config.template.php
- && cp ${WORKDIR_FILES}/wp-config.template.php ${www_dir}/../wp-config.template.php \
-# Copy php.ini
- && cp ${WORKDIR_FILES}/php.ini "${PHP_INI_DIR}/php.ini" \
-# Install missing php extensions
- && EXTRA_CFLAGS="-I/usr/src/php" docker-php-ext-install \
- exif gd mysqli zip \
-# Enable apache mod-rewrite
- && a2enmod rewrite \
-# Enable apache mod-headers
- && a2enmod headers \
-# Enable mod-security2
- && a2enmod security2 \
- && cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf \
- && sed -Ei "s/Sec([A-Z][a-z]+)Engine .+/Sec\1Engine On/g" /etc/modsecurity/modsecurity.conf \
- && cp ${WORKDIR_FILES}/security2.conf /etc/apache2/mods-available/security2.conf \
-# Setup mod-security2
- && cd /usr/share/modsecurity-crs \
- && rm -rf ./* \
- && tar -xf ${WORKDIR_DOWNLOADS}/corerules.tar.gz -C ./ --strip-components=1 \
- && mv crs-setup.conf.example crs-setup.conf \
- && mv ./rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example ./rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf \
-# Copy default site conf
- && cp ${WORKDIR_FILES}/000-default.conf /etc/apache2/sites-available/000-default.conf \
-# Copy security conf
- && cp ${WORKDIR_FILES}/security.conf /etc/apache2/conf-available/security.conf \
-# Copy htaccess
- && cp ${WORKDIR_FILES}/htaccess ${DATA_DIR}/.htaccess \
- && ln -s ${DATA_DIR}/.htaccess ${www_dir}/.htaccess \
+ && cp ${WORKDIR_FILES}/wp-config.template.php ${PRESS_HOME}/wp-config.template.php \
# Copy startup script
- && cp ${WORKDIR_FILES}/classicpress.sh /opt/classicpress.sh \
-# Create user
- && useradd -rMUG daemon,www-data apache \
+ && cp ${WORKDIR_FILES}/classicpress.sh ${PRESS_HOME}/classicpress.sh \
+# Privilages
+ && cp ${WORKDIR_FILES}/ch/chmod /bin/schmod \
+ && cp ${WORKDIR_FILES}/ch/chgrp /bin/schgrp \
+ && chmod +s /bin/schmod /bin/schgrp \
+ && chmod +x ${PRESS_HOME}/classicpress.sh \
+ && chown -R ${PRESS_USER}:${PRESS_USER} /data ${www_dir} \
+ && chmod -R 777 /run /var/log \
# Clean
- && apt-get purge -y --auto-remove \
- wget zlib1g-dev \
- && apt-get autoclean \
- && rm -r /var/lib/apt/lists/* \
&& rm -rf /tmp/*
-# Set back www_dir as workdir
-WORKDIR ${www_dir}
+USER press
-# Expose port 80
EXPOSE 80
-# It's important to NOT change user with USER. We want to have root permissions
-# in startup script, so we can dynamcally change UID/GID and ownership.
+HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1/fpm-ping
# Set startup command
-CMD [ "/opt/classicpress.sh" ]
+CMD [ "/home/press/classicpress.sh" ]
diff --git a/classicpress/ch/chgrp b/classicpress/ch/chgrp
new file mode 100755
index 0000000..9901960
Binary files /dev/null and b/classicpress/ch/chgrp differ
diff --git a/classicpress/ch/chmod b/classicpress/ch/chmod
new file mode 100755
index 0000000..553f792
Binary files /dev/null and b/classicpress/ch/chmod differ
diff --git a/classicpress/ch/chown b/classicpress/ch/chown
new file mode 100755
index 0000000..7a19db3
Binary files /dev/null and b/classicpress/ch/chown differ
diff --git a/classicpress/classicpress.sh b/classicpress/classicpress.sh
index d0b4afa..60f55ac 100755
--- a/classicpress/classicpress.sh
+++ b/classicpress/classicpress.sh
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+schgrp -R press /data
+
# ClassicPress Startup Script
TMP_WP_CONFIG=/tmp/wp-config.php
@@ -33,7 +35,6 @@ function store_env() {
sed -i "s/$1/${!1}/g" "${TMP_WP_CONFIG}"
}
-
# Checking wp-config.php
if [ ! -f "${WP_CONFIG}" ]; then
echo "Notice: File ${WP_CONFIG} not found - touching"
@@ -41,8 +42,8 @@ if [ ! -f "${WP_CONFIG}" ]; then
fi
if [ ! -w "${WP_CONFIG}" ]; then
- echo "Error: File ${WP_CONFIG} found, but not writable. Have you mounted the /data as a volume?"
- exit 1
+ echo "Notice: File ${WP_CONFIG} found, but not writable. Fixing"
+ schmod g+w "${WP_CONFIG}"
fi
if [ -s "${WP_CONFIG}" ]; then
@@ -71,7 +72,7 @@ else
random_env "CP_NONCE_SALT"
echo "Preparing wp-config.php ..."
- cp "${WWW_DIR}/../wp-config.template.php" "${TMP_WP_CONFIG}"
+ cp "${PRESS_HOME}/wp-config.template.php" "${TMP_WP_CONFIG}"
store_env "CP_DB_NAME"
store_env "CP_DB_USER"
store_env "CP_DB_PASSWORD"
@@ -99,14 +100,7 @@ else
cp -r "${BACKUP_WP_CONTENT}" "${WP_CONTENT}"
fi
+schmod -R g+w "${WP_CONTENT}"
-# Chanigin ownership
-echo "Changing ownership..."
-sed -Ei "s/$APACHE_RUN_USER:x:[0-9]+:[0-9]+/$APACHE_RUN_USER:x:$APACHE_RUN_USER_ID:$APACHE_RUN_GROUP_ID/g" /etc/passwd
-chown -R ${APACHE_RUN_USER}:${APACHE_RUN_GROUP} ${WWW_DIR} ${DATA_DIR}
-
-
-# Starting apache
-echo "Starting Apache in foreground ..."
-# https://github.com/docker-library/php/blob/master/7.4/bullseye/apache/apache2-foreground
-apache2-foreground
+# Starting
+supervisord
diff --git a/classicpress/conf/fpm-pool.conf b/classicpress/conf/fpm-pool.conf
new file mode 100644
index 0000000..4be2061
--- /dev/null
+++ b/classicpress/conf/fpm-pool.conf
@@ -0,0 +1,56 @@
+[global]
+; Log to stderr
+error_log = /dev/stderr
+
+[www]
+; The address on which to accept FastCGI requests.
+; Valid syntaxes are:
+; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
+; a specific port;
+; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
+; a specific port;
+; 'port' - to listen on a TCP socket to all addresses
+; (IPv6 and IPv4-mapped) on a specific port;
+; '/path/to/unix/socket' - to listen on a unix socket.
+; Note: This value is mandatory.
+listen = /run/php-fpm.sock
+
+; Enable status page
+pm.status_path = /fpm-status
+
+; Ondemand process manager
+pm = ondemand
+
+; The number of child processes to be created when pm is set to 'static' and the
+; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
+; This value sets the limit on the number of simultaneous requests that will be
+; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
+; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
+; CGI. The below defaults are based on a server without much resources. Don't
+; forget to tweak pm.* to fit your needs.
+; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
+; Note: This value is mandatory.
+pm.max_children = 100
+
+; The number of seconds after which an idle process will be killed.
+; Note: Used only when pm is set to 'ondemand'
+; Default Value: 10s
+pm.process_idle_timeout = 10s;
+
+; The number of requests each child process should execute before respawning.
+; This can be useful to work around memory leaks in 3rd party libraries. For
+; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
+; Default Value: 0
+pm.max_requests = 1000
+
+; Make sure the FPM workers can reach the environment variables for configuration
+clear_env = no
+
+; Catch output from PHP
+catch_workers_output = yes
+
+; Remove the 'child 10 said into stderr' prefix in the log and only show the actual message
+decorate_workers_output = no
+
+; Enable ping page to use in healthcheck
+ping.path = /fpm-ping
diff --git a/classicpress/conf/nginx.conf b/classicpress/conf/nginx.conf
new file mode 100644
index 0000000..9962006
--- /dev/null
+++ b/classicpress/conf/nginx.conf
@@ -0,0 +1,161 @@
+worker_processes auto;
+error_log stderr warn;
+pid /run/nginx.pid;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+
+ client_max_body_size 25m;
+
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ # Define custom log format to include reponse times
+ log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for" '
+ '$request_time $upstream_response_time $pipe $upstream_cache_status';
+
+ access_log /dev/stdout main_timed;
+ error_log /dev/stderr notice;
+
+ # Write temporary files to /tmp so they can be created as a non-privileged user
+ client_body_temp_path /tmp/client_temp;
+ proxy_temp_path /tmp/proxy_temp_path;
+ fastcgi_temp_path /tmp/fastcgi_temp;
+ uwsgi_temp_path /tmp/uwsgi_temp;
+ scgi_temp_path /tmp/scgi_temp;
+
+ # Default server definition
+ server {
+ listen [::]:80 default_server;
+ listen 80 default_server;
+ server_name _;
+
+ absolute_redirect off;
+
+ root /var/www/html;
+ index index.php index.html;
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to index.php
+ try_files $uri $uri/ /index.php?q=$uri&$args;
+ }
+
+ # Redirect server error pages to the static page /50x.html
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root /var/lib/nginx/html;
+ }
+
+ # Pass the PHP scripts to PHP-FPM listening on php-fpm.sock
+ location ~ \.php$ {
+ try_files $uri =404;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_pass unix:/run/php-fpm.sock;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param SCRIPT_NAME $fastcgi_script_name;
+ fastcgi_index index.php;
+ include fastcgi_params;
+ }
+
+ location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
+ expires max;
+ log_not_found off;
+ }
+
+ # Deny access to . files, for security
+ location ~ /\. {
+ log_not_found off;
+ deny all;
+ }
+
+ # Allow fpm ping and status from localhost
+ location ~ ^/(fpm-status|fpm-ping)$ {
+ access_log off;
+ allow 127.0.0.1;
+ deny all;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ include fastcgi_params;
+ fastcgi_pass unix:/run/php-fpm.sock;
+ }
+
+ # Global restrictions configuration file.
+ # Designed to be included in any server {} block.
+ location = /favicon.ico {
+ log_not_found off;
+ access_log off;
+ }
+
+ location = /robots.txt {
+ allow all;
+ log_not_found off;
+ access_log off;
+ }
+
+ # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
+ # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
+ location ~ /\. {
+ deny all;
+ }
+
+ # Deny access to any files with a .php extension in the uploads directory
+ # Works in sub-directory installs and also in multisite network
+ # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
+ location ~* /(?:uploads|files)/.*\.php$ {
+ deny all;
+ }
+ }
+
+ gzip on;
+ gzip_proxied any;
+ gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;
+ gzip_vary on;
+ gzip_disable "msie6";
+
+ # Security
+
+ # > Verify that the HTTP headers or any part of the HTTP response do not expose detailed version information
+ # > of system components.
+ # ~ 14.3.3
+ server_tokens off;
+
+ # > Verify that all responses contain a X-Content-Type-Options: nosniff header.
+ # ~ 14.4.4
+ # === https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
+ add_header X-Content-Type-Options "nosniff";
+
+ # > Verify that a suitable Referrer-Policy header is included to avoid exposing sensitive information
+ # > in the URL through the Referer header to untrusted parties.
+ # ~ 14.4.6
+ # === https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
+ add_header Referrer-Policy "strict-origin-when-cross-origin";
+
+ # > Verify that the content of a web application cannot be embedded in a third-party site by default and that
+ # > embedding of the exact resources is only allowed where necessary by using suitable
+ # > Content-Security-Policy: frame-ancestors and X-Frame-Options response headers.
+ # ~ 14.4.7
+ # === https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
+ add_header X-Frame-Options "SAMEORIGIN";
+
+ # > The X-XSS-Protection header has been deprecated by modern browsers and its use can introduce additional security
+ # > issues on the client side. As such, it is recommended to set the header as X-XSS-Protection: 0 in order to disable
+ # > the XSS Auditor, and not allow it to take the default behavior of the browser handling the response.
+ # === https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#x-xss-protection-header
+ add_header X-XSS-Protection "0";
+
+ # > The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types
+ # > advertised in the Content-Type headers should not be changed and be followed. This is a way to opt out of MIME type
+ # > sniffing, or, in other words, to say that the MIME types are deliberately configured.
+ # === https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
+ add_header X-Content-Type-Options "nosniff";
+}
diff --git a/classicpress/php.ini b/classicpress/conf/php.ini
similarity index 99%
rename from classicpress/php.ini
rename to classicpress/conf/php.ini
index 5477fa9..8f666f1 100644
--- a/classicpress/php.ini
+++ b/classicpress/conf/php.ini
@@ -965,7 +965,7 @@ cli_server.color = On
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
-;date.timezone =
+date.timezone = UTC
; https://php.net/date.default-latitude
;date.default_latitude = 31.7667
diff --git a/classicpress/conf/supervisord.conf b/classicpress/conf/supervisord.conf
new file mode 100644
index 0000000..216a387
--- /dev/null
+++ b/classicpress/conf/supervisord.conf
@@ -0,0 +1,23 @@
+[supervisord]
+nodaemon=true
+logfile=/dev/null
+logfile_maxbytes=0
+pidfile=/run/supervisord.pid
+
+[program:php-fpm]
+command=php-fpm8 -F
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+autorestart=false
+startretries=0
+
+[program:nginx]
+command=nginx -g 'daemon off;'
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+autorestart=false
+startretries=0
diff --git a/classicpress/htaccess b/classicpress/htaccess
deleted file mode 100644
index f092a85..0000000
--- a/classicpress/htaccess
+++ /dev/null
@@ -1,7 +0,0 @@
-RewriteEngine On
-RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
-RewriteBase /
-RewriteRule ^index\.php$ - [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteCond %{REQUEST_FILENAME} !-d
-RewriteRule . /index.php [L]
diff --git a/classicpress/security.conf b/classicpress/security.conf
deleted file mode 100644
index faea0f7..0000000
--- a/classicpress/security.conf
+++ /dev/null
@@ -1,54 +0,0 @@
-# Disable access to the entire file system except for the directories that
-# are explicitly allowed later.
-
- AllowOverride None
- Require all denied
-
-
-# ServerTokens
-# This directive configures what you return as the Server HTTP response
-# Header. The default is 'Full' which sends information about the OS-Type
-# and compiled in modules.
-# Set to one of: Full | OS | Minimal | Minor | Major | Prod
-ServerTokens Prod
-
-# Optionally add a line containing the server version and virtual host
-# name to server-generated pages (internal error documents, FTP directory
-# listings, mod_status and mod_info output etc., but not CGI generated
-# documents or custom error documents).
-# Set to "EMail" to also include a mailto: link to the ServerAdmin.
-# Set to one of: On | Off | EMail
-ServerSignature Off
-
-#
-# Allow TRACE method
-#
-# Set to "extended" to also reflect the request body (only for testing and
-# diagnostic purposes).
-#
-# Set to one of: On | Off | extended
-TraceEnable Off
-
-# > Verify that all responses contain a X-Content-Type-Options: nosniff header.
-# ~ 14.4.4
-# === https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
-Header set X-Content-Type-Options: "nosniff"
-
-# > Verify that a suitable Referrer-Policy header is included to avoid exposing sensitive information
-# > in the URL through the Referer header to untrusted parties.
-# ~ 14.4.6
-# === https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
-Header set Referrer-Policy: "strict-origin-when-cross-origin"
-
-# > Verify that the content of a web application cannot be embedded in a third-party site by default and that
-# > embedding of the exact resources is only allowed where necessary by using suitable
-# > Content-Security-Policy: frame-ancestors and X-Frame-Options response headers.
-# ~ 14.4.7
-# === https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
-Header set X-Frame-Options: "SAMEORIGIN"
-
-# > The X-XSS-Protection header has been deprecated by modern browsers and its use can introduce additional security
-# > issues on the client side. As such, it is recommended to set the header as X-XSS-Protection: 0 in order to disable
-# > the XSS Auditor, and not allow it to take the default behavior of the browser handling the response.
-# === https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#x-xss-protection-header
-Header set X-XSS-Protection: "0"
diff --git a/classicpress/security2.conf b/classicpress/security2.conf
deleted file mode 100644
index 7c60582..0000000
--- a/classicpress/security2.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-
- SecDataDir /var/cache/modsecurity
- Include /usr/share/modsecurity-crs/crs-setup.conf
- Include /usr/share/modsecurity-crs/rules/*.conf
-
diff --git a/classicpress/wp-config.template.php b/classicpress/wp-config.template.php
index df1f155..3e958f7 100644
--- a/classicpress/wp-config.template.php
+++ b/classicpress/wp-config.template.php
@@ -18,6 +18,7 @@
$table_prefix = 'CP_DB_TABLE_PREFIX';
define('WP_DEBUG', false);
+define('WP_AUTO_UPDATE_CORE', false); // Lock CP version
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
$_SERVER['HTTPS'] = 'on';
diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml
index 5dca0b8..ca51f96 100644
--- a/docker-compose.dev.yaml
+++ b/docker-compose.dev.yaml
@@ -22,8 +22,6 @@ services:
depends_on:
- mariadb
environment:
- - "APACHE_RUN_USER_ID=${UID}"
- - "APACHE_RUN_GROUP_ID=${GID}"
- "CP_DB_NAME=${CP_DB_NAME}"
- "CP_DB_USER=${CP_DB_USER}"
- "CP_DB_PASSWORD_FILE=/run/secrets/CP_DB_PASSWORD"
diff --git a/docker-compose.example.yaml b/docker-compose.example.yaml
index 6f5d0e1..5e0b5f8 100644
--- a/docker-compose.example.yaml
+++ b/docker-compose.example.yaml
@@ -27,8 +27,6 @@ services:
depends_on:
- mariadb
environment:
- - "APACHE_RUN_USER_ID=${UID}"
- - "APACHE_RUN_GROUP_ID=${GID}"
- "CP_DB_NAME=${MYBLOG}_db"
- "CP_DB_USER=${MYBLOG}_user"
- "CP_DB_PASSWORD_FILE=/run/secrets/MYBLOG_DB_PASSWORD"