├── .env ├── .github └── workflows │ └── docker-build-push.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── config ├── fpm-pool.conf ├── my.cnf ├── nginx.conf ├── nginx_includes │ ├── .gitkeep │ └── include.conf ├── php.ini └── supervisord.conf ├── docker-compose.yml ├── entrypoint.sh ├── rootfs.sh ├── rootfs └── .gitkeep ├── wp-config.php └── wp-secrets.php /.env: -------------------------------------------------------------------------------- 1 | # All of these are being read by wp-config.php 2 | DISABLE_WP_CRON=true 3 | DB_NAME=wordpress 4 | DB_USER=wordpress 5 | DB_PASSWORD=wordpress 6 | DB_HOST=mysql 7 | DB_CHARSET=latin1 8 | DB_COLLATE='' 9 | TABLE_PREFIX=wp_ 10 | FS_METHOD=direct 11 | WP_DEBUG=false 12 | WP_DEBUG_DISPLAY=false 13 | EMPTY_TRASH_DAYS=7 14 | WP_POST_REVISIONS=10 15 | 16 | MARIADB_ROOT_PASSWORD=wordpress 17 | MARIADB_DATABASE=wordpress 18 | MARIADB_USER=wordpress 19 | MARIADB_PASSWORD=wordpress 20 | -------------------------------------------------------------------------------- /.github/workflows/docker-build-push.yaml: -------------------------------------------------------------------------------- 1 | name: Docker build and push 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | push: 8 | tags: 9 | 10 | env: 11 | REGISTRY: ghcr.io 12 | IMAGE_NAME: wordpress 13 | USER: nidr0x 14 | 15 | jobs: 16 | build-and-push: 17 | name: Build and push 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout repo 22 | uses: actions/checkout@v4 23 | 24 | - name: Set up QEMU 25 | uses: docker/setup-qemu-action@v3 26 | 27 | - name: Set up Docker Buildx 28 | uses: docker/setup-buildx-action@v3 29 | 30 | - name: Log in to the Container registry 31 | uses: docker/login-action@v3 32 | with: 33 | registry: ${{ env.REGISTRY }} 34 | username: ${{ github.actor }} 35 | password: ${{ secrets.GITHUB_TOKEN }} 36 | 37 | - name: Extract metadata (tags, labels) for Docker 38 | uses: docker/metadata-action@v5 39 | with: 40 | images: ${{ env.REGISTRY }}/${{ env.USER }}/${{ env.IMAGE_NAME }} 41 | 42 | - uses: oprypin/find-latest-tag@v1 43 | with: 44 | repository: nidr0x/docker-production-wordpress 45 | releases-only: true 46 | id: wordpress 47 | 48 | - name: Build Docker image 49 | uses: docker/build-push-action@v6 50 | with: 51 | context: . 52 | push: true 53 | platforms: linux/amd64, linux/386, linux/arm64 54 | tags: | 55 | ${{ env.REGISTRY }}/${{ env.USER }}/${{ env.IMAGE_NAME }}:${{ steps.wordpress.outputs.tag }} 56 | ${{ env.REGISTRY }}/${{ env.USER }}/${{ env.IMAGE_NAME }}:latest 57 | labels: ${{ steps.meta.outputs.labels }} 58 | cache-from: type=gha 59 | cache-to: type=gha,mode=max 60 | 61 | image-security: 62 | name: Image security scan (Trivy) 63 | runs-on: ubuntu-latest 64 | needs: build-and-push 65 | strategy: 66 | matrix: 67 | platforms: [linux/amd64, linux/386, linux/arm64] 68 | 69 | steps: 70 | - name: Run Trivy vulnerability scanner 71 | uses: aquasecurity/trivy-action@0.20.0 72 | with: 73 | image-ref: "${{ env.REGISTRY }}/${{ env.USER }}/${{ env.IMAGE_NAME }}:${{ steps.wordpress.outputs.tag }}" 74 | env: 75 | TRIVY_PLATFORM: ${{ matrix.platforms }} 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | ### macOS Patch ### 30 | # iCloud generated files 31 | *.icloud 32 | 33 | ### Vim ### 34 | # Swap 35 | [._]*.s[a-v][a-z] 36 | !*.svg # comment out if you don't need vector files 37 | [._]*.sw[a-p] 38 | [._]s[a-rt-v][a-z] 39 | [._]ss[a-gi-z] 40 | [._]sw[a-p] 41 | 42 | # Session 43 | Session.vim 44 | Sessionx.vim 45 | 46 | # Temporary 47 | .netrwhist 48 | *~ 49 | # Auto-generated tag files 50 | tags 51 | # Persistent undo 52 | [._]*.un~ 53 | 54 | # Other stuff 55 | config/nginx_includes/*.conf 56 | letsencrypt/ 57 | wp-content/ 58 | images/ 59 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM curlimages/curl:8.13.0 AS download 2 | ENTRYPOINT [] 3 | USER root 4 | 5 | ENV WPCLI_DOWNLOAD_SHA256=a39021ac809530ea607580dbf93afbc46ba02f86b6cffd03de4b126ca53079f6 6 | ENV WPCLI_VERSION=2.11.0 7 | 8 | RUN curl -sfo /tmp/wp -L https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar \ 9 | && echo "$WPCLI_DOWNLOAD_SHA256 /tmp/wp" | sha256sum -c - \ 10 | && chmod +x /tmp/wp 11 | 12 | RUN set -x \ 13 | && curl -f https://api.wordpress.org/secret-key/1.1/salt/ >> /tmp/wp-secrets.php 14 | 15 | FROM public.ecr.aws/docker/library/alpine:3.21 16 | 17 | LABEL Maintainer="Carlos R " \ 18 | Description="Slim WordPress image using Alpine Linux" 19 | 20 | ENV WP_VERSION=6.8.1 21 | ENV WP_LOCALE=en_US 22 | 23 | ARG UID=82 24 | ARG GID=82 25 | 26 | RUN adduser -u $UID -D -S -G www-data www-data \ 27 | && apk add --no-cache \ 28 | php84 \ 29 | php84-fpm \ 30 | php84-mysqli \ 31 | php84-json \ 32 | php84-openssl \ 33 | php84-curl \ 34 | php84-simplexml \ 35 | php84-ctype \ 36 | php84-mbstring \ 37 | php84-gd \ 38 | php84-exif \ 39 | nginx \ 40 | supervisor \ 41 | php84-zlib \ 42 | php84-xml \ 43 | php84-phar \ 44 | php84-intl \ 45 | php84-dom \ 46 | php84-xmlreader \ 47 | php84-zip \ 48 | php84-opcache \ 49 | php84-fileinfo \ 50 | php84-iconv \ 51 | less 52 | 53 | RUN { \ 54 | echo 'opcache.memory_consumption=128'; \ 55 | echo 'opcache.interned_strings_buffer=8'; \ 56 | echo 'opcache.max_accelerated_files=4000'; \ 57 | echo 'opcache.revalidate_freq=2'; \ 58 | echo 'opcache.fast_shutdown=1'; \ 59 | } > /etc/php84/conf.d/opcache-recommended.ini 60 | 61 | VOLUME /var/www/wp-content 62 | 63 | WORKDIR /usr/src 64 | 65 | RUN set -x \ 66 | && mkdir /usr/src/wordpress \ 67 | && chown -R $UID:$GID /usr/src/wordpress \ 68 | && sed -i s/';cgi.fix_pathinfo=1/cgi.fix_pathinfo=0'/g /etc/php84/php.ini \ 69 | && sed -i s/'expose_php = On/expose_php = Off'/g /etc/php84/php.ini \ 70 | && ln -s /usr/sbin/php-fpm84 /usr/sbin/php-fpm \ 71 | && ln -s /usr/bin/php84 /usr/bin/php 72 | 73 | COPY config/nginx.conf /etc/nginx/nginx.conf 74 | COPY config/fpm-pool.conf /etc/php84/php-fpm.d/zzz_custom_fpm_pool.conf 75 | COPY config/php.ini /etc/php84/conf.d/zzz_custom_php.ini 76 | COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf 77 | COPY config/nginx_includes/* /etc/nginx/includes/ 78 | COPY --chown=${UID} wp-config.php /usr/src/wordpress 79 | COPY rootfs.sh /usr/local/bin/ 80 | RUN chmod +x /usr/local/bin/rootfs.sh 81 | COPY --from=download --chown=${UID} /tmp/wp /usr/local/bin/wp 82 | COPY --from=download --chown=${UID} /tmp/wp-secrets.php /usr/src/wordpress/wp-secrets.php 83 | 84 | RUN set -x \ 85 | && chown -R $UID:$GID /etc/nginx \ 86 | && chown -R $UID:$GID /var/lib/nginx \ 87 | && chmod -R g+w /etc/nginx \ 88 | && chmod g+wx /var/log/ \ 89 | && ln -sf /dev/stderr /var/lib/nginx/logs/error.log \ 90 | && deluser nginx \ 91 | && rm -rf /tmp/* \ 92 | && chmod 660 /usr/src/wordpress/wp-config.php \ 93 | && sed -i '1s/^/> /usr/src/wordpress/wp-secrets.php 6 | 7 | exec "$@" 8 | -------------------------------------------------------------------------------- /rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | src_dir="/data" 5 | dst_dir="/usr/src/wordpress" 6 | 7 | if [ ! "$(ls -A $src_dir)" ]; then 8 | exit 0 9 | fi 10 | 11 | mkdir -p $dst_dir 12 | 13 | for file in $src_dir/*; do 14 | filename=$(basename $file) 15 | if [ ! -L "$dst_dir/$filename" ] || [ "$(readlink "$dst_dir/$filename")" != "$file" ]; then 16 | ln -sf $file $dst_dir/$filename 17 | fi 18 | done 19 | -------------------------------------------------------------------------------- /rootfs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nidr0x/docker-production-wordpress/42ae6d6912d3f653b1c70bfde300f70cdc1ce39b/rootfs/.gitkeep -------------------------------------------------------------------------------- /wp-config.php: -------------------------------------------------------------------------------- 1 | $value) { 12 | $capitalized = strtoupper($key); 13 | if (!defined($capitalized)) { 14 | define($capitalized, $value); 15 | } 16 | } 17 | 18 | if (!defined('ABSPATH')) { 19 | define('ABSPATH', dirname(__FILE__) . '/'); 20 | } 21 | 22 | require_once(ABSPATH . 'wp-secrets.php'); 23 | require_once(ABSPATH . 'wp-settings.php'); 24 | @ini_set('display_errors', 0); 25 | -------------------------------------------------------------------------------- /wp-secrets.php: -------------------------------------------------------------------------------- 1 |