├── .circleci └── config.yml ├── .gitignore ├── README.md ├── build.sh ├── caddy ├── .dockerignore ├── Dockerfile ├── VERSION ├── scripts │ ├── build.sh │ └── entrypoint.sh └── templates │ ├── Caddyfile │ └── xenforo.Caddyfile ├── examples ├── .env.default ├── .gitignore ├── docker-compose.yml └── src │ ├── index.php │ ├── internal_data │ └── index.html │ ├── js │ └── index.html │ ├── library │ └── index.html │ └── styles │ └── index.html ├── nginx ├── Dockerfile ├── VERSION ├── docker-entrypoint.sh └── templates │ ├── default.conf │ ├── nginx.conf │ └── php_fpm_params ├── php-apache ├── .dockerignore ├── Dockerfile ├── VERSION ├── apache2 │ ├── conf-available │ │ └── xfrocks.conf │ └── sites-available │ │ ├── 000-default.conf │ │ └── default-ssl.conf └── tmp │ ├── build.sh │ └── build_apache.sh ├── php-fpm ├── .dockerignore ├── Dockerfile ├── VERSION ├── build.sh └── build_fpm.sh └── tests ├── exif ├── small.jpg └── test.php ├── gd └── test.php ├── gmp └── test.php ├── iconv └── test.php ├── imagick └── test.php ├── memcached └── test.php ├── mysqli └── test.php ├── opcache └── test.php ├── pcntl └── test.php ├── php.ini ├── redis └── test.php ├── run.sh ├── soap └── test.php ├── sockets └── test.php └── zip └── test.php /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: docker:git 6 | environment: 7 | PUSH: 'yes' 8 | 9 | jobs: 10 | build_nginx: 11 | <<: *defaults 12 | steps: 13 | - checkout 14 | - setup_remote_docker 15 | - run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_TOKEN 16 | - run: ./build.sh nginx/ 17 | - store_artifacts: 18 | path: ./nginx/build.log 19 | 20 | build_php_apache: 21 | <<: *defaults 22 | steps: 23 | - checkout 24 | - setup_remote_docker 25 | - run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_TOKEN 26 | - run: ./build.sh php-apache/ 27 | - store_artifacts: 28 | path: ./php-apache/build.log 29 | - store_artifacts: 30 | path: ./php-apache/test.log 31 | build_php_fpm: 32 | <<: *defaults 33 | steps: 34 | - checkout 35 | - setup_remote_docker 36 | - run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_TOKEN 37 | - run: ./build.sh php-fpm/ 38 | - store_artifacts: 39 | path: ./php-fpm/build.log 40 | - store_artifacts: 41 | path: ./php-fpm/test.log 42 | 43 | workflows: 44 | version: 2 45 | build_all: 46 | jobs: 47 | - build_nginx 48 | - build_php_apache 49 | - build_php_fpm 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tests/Dockerfile 2 | *.log 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker pull xfrocks/xenforo 2 | Docker containers to develop and run XenForo. 3 | 4 | [![CircleCI](https://circleci.com/gh/xfrocks/docker-xenforo.svg?style=svg)](https://circleci.com/gh/xfrocks/docker-xenforo) 5 | [![Docker](https://img.shields.io/docker/pulls/xfrocks/xenforo.svg)](https://hub.docker.com/r/xfrocks/xenforo) 6 | 7 | Installed extensions (other than the default ones): 8 | * apcu 9 | * exif 10 | * gd 11 | * gmp 12 | * imagick 13 | * memcached 14 | * mysqli 15 | * opcache 16 | * pcntl 17 | * redis 18 | * soap 19 | * sockets 20 | * xdebug (installed but disabled on php-fpm) 21 | * zip 22 | 23 | List of all extensions on php-fpm (according to `php -m`): 24 | apcu 25 | Core 26 | ctype 27 | curl 28 | date 29 | dom 30 | exif 31 | fileinfo 32 | filter 33 | ftp 34 | gd 35 | gmp 36 | hash 37 | iconv 38 | igbinary 39 | json 40 | libxml 41 | mbstring 42 | memcached 43 | mysqli 44 | mysqlnd 45 | openssl 46 | pcntl 47 | pcre 48 | PDO 49 | pdo_sqlite 50 | Phar 51 | posix 52 | readline 53 | redis 54 | Reflection 55 | session 56 | SimpleXML 57 | soap 58 | sockets 59 | sodium 60 | SPL 61 | sqlite3 62 | standard 63 | tokenizer 64 | xml 65 | xmlreader 66 | xmlwriter 67 | Zend OPcache 68 | zip 69 | zlib 70 | Zend OPcache 71 | 72 | ## Development 73 | 74 | Sample `docker-compose.yml` using Apache: 75 | 76 | ```yaml 77 | version: "2" 78 | 79 | services: 80 | php: 81 | image: xfrocks/xenforo:php-apache 82 | ports: 83 | - "8080:80" 84 | links: 85 | - mysql 86 | volumes: 87 | - .:/var/www/html/ 88 | 89 | mysql: 90 | image: mysql 91 | environment: 92 | MYSQL_RANDOM_ROOT_PASSWORD: "yes" 93 | MYSQL_DATABASE: database 94 | MYSQL_USER: user 95 | MYSQL_PASSWORD: password 96 | ports: 97 | - "3306:3306" 98 | volumes: 99 | - ./internal_data/mysql:/var/lib/mysql 100 | ``` 101 | 102 | ### Friendly URLs 103 | 104 | The apache image doesn't have mod_rewrite enabled, use FallbackResource in `.htaccess` if you need XenForo's friendly URLs: 105 | 106 | ``` 107 | FallbackResource /index.php 108 | ``` 109 | 110 | ### Locale 111 | 112 | The apache image has `locales-all` installed for easy development but it's not included in the fpm image. 113 | Click [here](https://github.com/gliderlabs/docker-alpine/issues/144) for installation instructions. 114 | 115 | ## Production 116 | It's recommended to use the fpm image with nginx for better performance in production. 117 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | _filter="$1" 4 | _test="${TEST:-yes}" 5 | _push="$PUSH" 6 | 7 | set -e 8 | 9 | DIR=$( pwd ) 10 | TESTS_DIR="$DIR/tests" 11 | 12 | EXT_INSTALL="exif gd gmp mysqli opcache pcntl soap sockets zip" 13 | PECL_INSTALL="apcu igbinary imagick memcached redis xdebug" 14 | 15 | for d in */ ; do 16 | cd "$DIR/$d" 17 | if [ ! -f Dockerfile ]; then 18 | continue 19 | fi 20 | if [ ! -z "$_filter" -a "x$d" != "x$_filter" ]; then 21 | echo "Skipped $d (_filter == $_filter)" >&2 22 | continue 23 | fi 24 | 25 | echo "Building $d..." 26 | 27 | IS_PHP=0 28 | case $d in 29 | php-* ) IS_PHP=1 30 | esac 31 | 32 | VERSION="$( head -n 1 "VERSION" )" 33 | TAG="xfrocks/xenforo:${d%?}" 34 | if [ "x$CIRCLE_BRANCH" != 'xmaster' ]; then 35 | TAG="$TAG-$CIRCLE_BRANCH" 36 | fi 37 | TAG_WITH_VERSION="$TAG-$VERSION" 38 | 39 | docker build \ 40 | --build-arg DOCKER_XENFORO_PHP_EXT_INSTALL="$EXT_INSTALL" \ 41 | --build-arg DOCKER_XENFORO_PHP_PECL_INSTALL="$PECL_INSTALL" \ 42 | -t "$TAG" \ 43 | -t "$TAG_WITH_VERSION" \ 44 | . > build.log 45 | 46 | if [ "$IS_PHP" -gt 0 ]; then 47 | if [ "x$_test" = 'xyes' ]; then 48 | printf "Testing... " 49 | if (export IMAGE_TAG_FOR_TESTING=$TAG_WITH_VERSION && cd $TESTS_DIR && ./run.sh) >test.log; then 50 | echo "OK" 51 | else 52 | echo "failed" 53 | exit 1 54 | fi 55 | else 56 | echo "Skipped testing (TEST == $_test)" >&2 57 | fi 58 | fi 59 | 60 | if [ "x$_push" = 'xyes' ]; then 61 | echo "Pushing..." 62 | ( \ 63 | docker push "$TAG" && \ 64 | docker push "$TAG_WITH_VERSION" \ 65 | ) > push.log 66 | else 67 | echo 'Skipped pushing, export PUSH=yes before building to do it' >&2 68 | fi 69 | done 70 | -------------------------------------------------------------------------------- /caddy/.dockerignore: -------------------------------------------------------------------------------- 1 | build.log 2 | Dockerfile 3 | VERSION 4 | -------------------------------------------------------------------------------- /caddy/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://hub.docker.com/_/golang/ 2 | FROM golang:1.13.5-alpine3.10 as builder 3 | 4 | RUN apk add --no-cache git gcc musl-dev 5 | 6 | COPY . /opt 7 | RUN /opt/scripts/build.sh 8 | 9 | FROM alpine:3.10 10 | COPY --from=builder /install/caddy /usr/bin/caddy 11 | 12 | RUN set -ex; \ 13 | apk add --no-cache openssh-client git; \ 14 | /usr/bin/caddy --version; \ 15 | /usr/bin/caddy --plugins 16 | 17 | EXPOSE 80 443 18 | VOLUME /root/.caddy /root/cache /var/www/html 19 | WORKDIR /var/www/html 20 | 21 | COPY . /opt 22 | 23 | ENTRYPOINT ["/opt/scripts/entrypoint.sh"] 24 | CMD ["-agree=true", "-log", "stdout"] 25 | -------------------------------------------------------------------------------- /caddy/VERSION: -------------------------------------------------------------------------------- 1 | 1.0.4 2 | -------------------------------------------------------------------------------- /caddy/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # https://github.com/caddyserver/caddy/releases 4 | VERSION='1.0.4' 5 | 6 | # https://github.com/abiosoft/caddy-docker/blob/master/builder/builder.sh 7 | PLUGINS='cache cors expires realip' 8 | TELEMETRY='true' 9 | IMPORT="github.com/caddyserver/caddy" 10 | 11 | # version <1.0.1 needs to use old import path 12 | new_import=true 13 | if [ "$(echo $VERSION | cut -c1)" -eq 0 ] 2>/dev/null || [ "$VERSION" = "1.0.0" ]; then 14 | IMPORT="github.com/mholt/caddy" && new_import=false 15 | fi 16 | 17 | # add `v` prefix for version numbers 18 | [ "$(echo $VERSION | cut -c1)" -ge 0 ] 2>/dev/null && VERSION="v$VERSION" 19 | 20 | stage() { 21 | STAGE="$1" 22 | echo 23 | echo starting stage: $STAGE 24 | } 25 | 26 | end_stage() { 27 | if [ $? -ne 0 ]; then 28 | >&2 echo error at \'$STAGE\' 29 | exit 1 30 | fi 31 | echo finished stage: $STAGE ✓ 32 | echo 33 | } 34 | 35 | use_new_import() ( 36 | cd $1 37 | find . -name '*.go' | while read -r f; do 38 | sed -i.bak 's/\/mholt\/caddy/\/caddyserver\/caddy/g' $f && rm $f.bak 39 | done 40 | ) 41 | 42 | get_package() { 43 | # go module require special dns handling 44 | if $go_mod && [ -f /dnsproviders/$1/$1.go ]; then 45 | mkdir -p /caddy/dnsproviders/$1 46 | cp -r /dnsproviders/$1/$1.go /caddy/dnsproviders/$1/$1.go 47 | echo "caddy/dnsproviders/$1" 48 | else 49 | GO111MODULE=off GOOS=linux GOARCH=amd64 caddyplug package $1 2> /dev/null 50 | fi 51 | } 52 | 53 | dns_plugins() { 54 | git clone https://github.com/caddyserver/dnsproviders /dnsproviders 55 | # temp hack for repo rename 56 | if $new_import; then use_new_import /dnsproviders; fi 57 | } 58 | 59 | plugins() { 60 | mkdir -p /plugins 61 | for plugin in $(echo $PLUGINS | tr "," " "); do \ 62 | import_package=$(get_package $plugin) 63 | $go_mod || go get -v "$import_package" ; # not needed for modules 64 | $go_mod && package="main" || package="caddyhttp" 65 | printf "package $package\nimport _ \"$import_package\"" > \ 66 | /plugins/$plugin.go ; \ 67 | done 68 | } 69 | 70 | module() { 71 | mkdir -p /caddy 72 | cd /caddy # build dir 73 | 74 | # setup module 75 | go mod init caddy 76 | go get -v $IMPORT@$VERSION 77 | 78 | # plugins 79 | cp -r /plugins/. . 80 | 81 | # temp hack for repo rename 82 | go get -v -d # download possible plugin deps 83 | if $new_import; then use_new_import /go/pkg/mod; fi 84 | 85 | # main and telemetry 86 | cat > main.go < "$run_file.disablestats.go" <&2 23 | fi 24 | 25 | echo "Executing $@..." >&2 26 | exec "$@" 27 | -------------------------------------------------------------------------------- /caddy/templates/Caddyfile: -------------------------------------------------------------------------------- 1 | * 2 | 3 | errors stdout 4 | log stdout 5 | realip { 6 | from 10.0.0.0/8 7 | from 172.16.0.0/12 8 | from 192.168.0.0/16 9 | } 10 | -------------------------------------------------------------------------------- /caddy/templates/xenforo.Caddyfile: -------------------------------------------------------------------------------- 1 | 2 | status 403 /internal_data 3 | status 403 /library 4 | 5 | header /js { 6 | Cache-Control "max-age=31536000" 7 | } 8 | 9 | header /styles { 10 | Cache-Control "max-age=31536000" 11 | } 12 | 13 | rewrite { 14 | to {path} {path}/ /index.php 15 | } 16 | fastcgi / %_phpFastcgiEndpoint% php 17 | -------------------------------------------------------------------------------- /examples/.env.default: -------------------------------------------------------------------------------- 1 | CLOUDFLARE_API_KEY= 2 | CLOUDFLARE_EMAIL= 3 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | /.data/ 2 | /.env 3 | -------------------------------------------------------------------------------- /examples/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | src: 5 | image: alpine 6 | command: ["uptime"] 7 | volumes: 8 | - ./src/:/var/www/html/ 9 | 10 | php-apache: 11 | image: xfrocks/xenforo:php-apache 12 | environment: 13 | - VIRTUAL_HOST=apache.local.xfrocks.com 14 | ports: 15 | - "4433:443" 16 | volumes_from: 17 | - src 18 | 19 | php-fpm: 20 | image: xfrocks/xenforo:php-fpm 21 | volumes_from: 22 | - src 23 | 24 | nginx: 25 | image: xfrocks/xenforo:nginx 26 | environment: 27 | - NGINX_ACCESS_LOG_FORMAT=timed 28 | - NGINX_FAST_CGI_PASS=php-fpm:9000 29 | - VIRTUAL_HOST=nginx.local.xfrocks.com 30 | links: 31 | - php-fpm 32 | volumes_from: 33 | - src 34 | 35 | caddy: 36 | image: xfrocks/xenforo:caddy 37 | environment: 38 | - CADDY_PHP_FASTCGI_ENDPOINT=php-fpm:9000 39 | - VIRTUAL_HOST=caddy.local.xfrocks.com 40 | - VIRTUAL_PORT=2015 41 | links: 42 | - php-fpm 43 | - proxy 44 | volumes: 45 | - ./.data/caddy:/root/.caddy 46 | volumes_from: 47 | - src 48 | ports: 49 | - "2015" 50 | - "443:443" 51 | 52 | proxy: 53 | image: jwilder/nginx-proxy 54 | ports: 55 | - "80:80" 56 | volumes: 57 | - /var/run/docker.sock:/tmp/docker.sock:ro 58 | -------------------------------------------------------------------------------- /examples/src/index.php: -------------------------------------------------------------------------------- 1 | "$NGINX_CONF_PATH" 30 | 31 | if [ -f "$DEFAULT_CONF_PATH" ]; then 32 | unlink "$DEFAULT_CONF_PATH" 33 | fi 34 | 35 | if [ ! -z "$NGINX_FAST_CGI_PASS" ]; then 36 | PHP_FPM_PARAMS="$( cat "$PHP_FPM_PARAMS_TEMPLATE_PATH" )" 37 | 38 | PHP_FPM_PARAMS="$( echo "$PHP_FPM_PARAMS" | sed -e "s|^\(\s*fastcgi_pass.*\) 127.0.0.1:9000;$|\1 $NGINX_FAST_CGI_PASS;|" )" 39 | echo "$PHP_FPM_PARAMS" | grep 'fastcgi_pass' | xargs 40 | 41 | echo "$PHP_FPM_PARAMS" > "$PHP_FPM_PARAMS_PATH" 42 | 43 | DEFAULT_CONF="$( cat "$DEFAULT_CONF_TEMPLATE_PATH" )" 44 | 45 | # TODO: re-configure default.conf? 46 | 47 | echo "$DEFAULT_CONF" > "$DEFAULT_CONF_PATH" 48 | fi 49 | 50 | echo "Executing $@..." 51 | exec "$@" -------------------------------------------------------------------------------- /nginx/templates/default.conf: -------------------------------------------------------------------------------- 1 | # https://github.com/xfrocks/docker-xenforo/blob/master/nginx/templates/nginx.conf 2 | 3 | server { 4 | listen 80 default_server; 5 | server_name dev.local.xfrocks.com; 6 | 7 | root /var/www/html/; 8 | 9 | location / { 10 | index index.php index.html index.htm; 11 | try_files $uri $uri/ /index.php?$uri&$args; 12 | } 13 | 14 | location /internal_data/ { 15 | internal; 16 | deny all; 17 | } 18 | 19 | location /library/ { 20 | internal; 21 | deny all; 22 | } 23 | 24 | # static files 25 | location ~ ^/(js|styles)/ { 26 | expires 1y; 27 | access_log off; 28 | add_header Cache-Control "public"; 29 | } 30 | 31 | location ~ \.php$ { 32 | include /etc/nginx/php_fpm_params; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nginx/templates/nginx.conf: -------------------------------------------------------------------------------- 1 | # https://github.com/xfrocks/docker-xenforo/blob/master/nginx/templates/nginx.conf 2 | 3 | user nginx; 4 | worker_processes auto; 5 | 6 | error_log /var/log/nginx/error.log warn; 7 | pid /var/run/nginx.pid; 8 | 9 | events { 10 | multi_accept on; 11 | use epoll; 12 | worker_connections 1024; 13 | } 14 | 15 | http { 16 | include /etc/nginx/mime.types; 17 | default_type application/octet-stream; 18 | server_tokens off; 19 | 20 | # https://philio.me/showing-the-correct-client-ip-in-logs-and-scripts-when-using-nginx-behind-a-reverse-proxy/ 21 | set_real_ip_from 192.168.0.0/16; 22 | set_real_ip_from 172.16.0.0/12; 23 | set_real_ip_from 127.0.0.0/8; 24 | set_real_ip_from 10.0.0.0/8; 25 | real_ip_header X-Forwarded-For; 26 | real_ip_recursive on; 27 | 28 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 29 | '$status $body_bytes_sent "$http_referer" ' 30 | '"$http_user_agent" "$http_x_forwarded_for"'; 31 | log_format timed '$remote_addr - $remote_user [$time_local] "$request" ' 32 | '$upstream_response_time $request_time ' 33 | '$status $body_bytes_sent "$http_referer" ' 34 | '"$http_user_agent" "$http_x_forwarded_for"'; 35 | access_log off; 36 | 37 | sendfile on; 38 | tcp_nopush on; 39 | tcp_nodelay on; 40 | keepalive_timeout 30; 41 | reset_timedout_connection on; 42 | 43 | # https://mattstauffer.co/blog/enabling-gzip-on-nginx-servers-including-laravel-forge 44 | gzip on; 45 | gzip_comp_level 5; 46 | gzip_min_length 10240; 47 | gzip_vary on; 48 | gzip_types 49 | application/atom+xml 50 | application/javascript 51 | application/json 52 | application/rss+xml 53 | application/vnd.ms-fontobject 54 | application/x-font-ttf 55 | application/x-web-app-manifest+json 56 | application/xhtml+xml 57 | application/xml 58 | font/opentype 59 | image/svg+xml 60 | image/x-icon 61 | text/css 62 | text/plain 63 | text/x-component; 64 | 65 | include /etc/nginx/conf.d/*.conf; 66 | } 67 | -------------------------------------------------------------------------------- /nginx/templates/php_fpm_params: -------------------------------------------------------------------------------- 1 | include /etc/nginx/fastcgi_params; 2 | fastcgi_pass 127.0.0.1:9000; 3 | fastcgi_index index.php; 4 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; 5 | 6 | # https://httpoxy.org/ 7 | fastcgi_param HTTP_PROXY ""; -------------------------------------------------------------------------------- /php-apache/.dockerignore: -------------------------------------------------------------------------------- 1 | *.log 2 | Dockerfile 3 | VERSION 4 | -------------------------------------------------------------------------------- /php-apache/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://hub.docker.com/_/php/ 2 | FROM php:8.2.7-apache-bookworm 3 | 4 | ARG DOCKER_XENFORO_PHP_EXT_INSTALL 5 | ARG DOCKER_XENFORO_PHP_PECL_INSTALL 6 | 7 | # https://hub.docker.com/_/composer/ 8 | COPY --from=composer:2.0.7 /usr/bin/composer /usr/bin/composer 9 | ENV COMPOSER_ALLOW_SUPERUSER 1 10 | ENV COMPOSER_HOME /tmp 11 | ENV COMPOSER_VERSION 2.0.7 12 | 13 | COPY tmp /tmp 14 | RUN /tmp/build.sh 15 | 16 | COPY apache2 /etc/apache2 17 | -------------------------------------------------------------------------------- /php-apache/VERSION: -------------------------------------------------------------------------------- 1 | 8.2.7 2 | -------------------------------------------------------------------------------- /php-apache/apache2/conf-available/xfrocks.conf: -------------------------------------------------------------------------------- 1 | ServerAdmin webmaster@localhost 2 | DocumentRoot /var/www/html 3 | 4 | ErrorLog ${APACHE_LOG_DIR}/error.log 5 | CustomLog ${APACHE_LOG_DIR}/access.log combined 6 | 7 | RemoteIPHeader X-Forwarded-For 8 | # https://tools.ietf.org/html/rfc1918#section-3 9 | RemoteIPTrustedProxy 10.0.0.0/8 10 | RemoteIPTrustedProxy 172.16.0.0/12 11 | RemoteIPTrustedProxy 192.168.0.0/16 12 | -------------------------------------------------------------------------------- /php-apache/apache2/sites-available/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | Include conf-available/xfrocks.conf 3 | 4 | -------------------------------------------------------------------------------- /php-apache/apache2/sites-available/default-ssl.conf: -------------------------------------------------------------------------------- 1 | 2 | Include conf-available/xfrocks.conf 3 | 4 | SSLEngine on 5 | SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem 6 | SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key 7 | 8 | -------------------------------------------------------------------------------- /php-apache/tmp/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | RUN_PACKAGES="" 6 | TMP_PACKAGES="" 7 | TMP_PACKAGES="$TMP_PACKAGES libfreetype6-dev" # gd 8 | RUN_PACKAGES="$RUN_PACKAGES libgd3" # gd 9 | TMP_PACKAGES="$TMP_PACKAGES libgd-dev" # gd 10 | RUN_PACKAGES="$RUN_PACKAGES libgmp10" # gmp 11 | TMP_PACKAGES="$TMP_PACKAGES libgmp-dev" # gmp 12 | TMP_PACKAGES="$TMP_PACKAGES libjpeg62-turbo-dev" # gd 13 | RUN_PACKAGES="$RUN_PACKAGES libmagickwand-6.q16" # imagick 14 | TMP_PACKAGES="$TMP_PACKAGES libmagickwand-6.q16-dev" # imagick 15 | TMP_PACKAGES="$TMP_PACKAGES libmemcached-dev" # memcached 16 | RUN_PACKAGES="$RUN_PACKAGES libmemcachedutil2" # memcached 17 | TMP_PACKAGES="$TMP_PACKAGES libpng-dev" # gd 18 | RUN_PACKAGES="$RUN_PACKAGES libssl-dev" 19 | RUN_PACKAGES="$RUN_PACKAGES libwebp7" # gd 20 | TMP_PACKAGES="$TMP_PACKAGES libwebp-dev" # gd 21 | RUN_PACKAGES="$RUN_PACKAGES libxml2-dev" # soap 22 | RUN_PACKAGES="$RUN_PACKAGES libxpm4" # gd 23 | TMP_PACKAGES="$TMP_PACKAGES libxpm-dev" # gd 24 | RUN_PACKAGES="$RUN_PACKAGES libzip4" # zip 25 | TMP_PACKAGES="$TMP_PACKAGES libzip-dev" # zip 26 | RUN_PACKAGES="$RUN_PACKAGES locales-all" 27 | RUN_PACKAGES="$RUN_PACKAGES default-mysql-client" 28 | TMP_PACKAGES="$TMP_PACKAGES git" 29 | RUN_PACKAGES="$RUN_PACKAGES unzip" 30 | eval "apt-get update && apt-get install --no-install-recommends -y $TMP_PACKAGES $RUN_PACKAGES" 31 | 32 | case "$DOCKER_XENFORO_PHP_EXT_INSTALL" in 33 | *gd*) 34 | echo 'Preparing module: gd...' 35 | docker-php-ext-configure gd \ 36 | --enable-gd \ 37 | --with-freetype \ 38 | --with-jpeg \ 39 | --with-webp \ 40 | --with-xpm 41 | ;; 42 | esac 43 | 44 | # for improved ASLR and optimizations 45 | # https://github.com/docker-library/php/issues/105#issuecomment-278114879 46 | export CFLAGS="$PHP_CFLAGS" CPPFLAGS="$PHP_CPPFLAGS" LDFLAGS="$PHP_LDFLAGS" 47 | 48 | docker-php-source extract 49 | eval "docker-php-ext-install $DOCKER_XENFORO_PHP_EXT_INSTALL" 50 | eval "pecl install $DOCKER_XENFORO_PHP_PECL_INSTALL" 51 | eval "docker-php-ext-enable $DOCKER_XENFORO_PHP_PECL_INSTALL" 52 | /tmp/build_apache.sh 53 | docker-php-source delete 54 | 55 | # clean up 56 | pecl clear-cache 57 | rm -rf /tmp/* /var/lib/apt/lists/* 58 | eval apt-mark manual "$RUN_PACKAGES" 59 | eval "apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $TMP_PACKAGES" 60 | -------------------------------------------------------------------------------- /php-apache/tmp/build_apache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # remote ip (`X-Forwarded-For` header etc.) 6 | a2enmod remoteip 7 | 8 | # tls 9 | openssl req \ 10 | -days 365 \ 11 | -keyout /etc/ssl/private/ssl-cert-snakeoil.key \ 12 | -newkey rsa:4096 \ 13 | -nodes \ 14 | -out /etc/ssl/certs/ssl-cert-snakeoil.pem \ 15 | -subj "/C=VN/ST=Hanoi/O=xfrocks/CN=php-apache" \ 16 | -x509 17 | a2enmod ssl 18 | a2ensite default-ssl 19 | -------------------------------------------------------------------------------- /php-fpm/.dockerignore: -------------------------------------------------------------------------------- 1 | *.log 2 | Dockerfile 3 | VERSION 4 | -------------------------------------------------------------------------------- /php-fpm/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://hub.docker.com/_/php/ 2 | FROM php:8.2.7-fpm-alpine3.18 3 | 4 | ARG DOCKER_XENFORO_PHP_EXT_INSTALL 5 | ARG DOCKER_XENFORO_PHP_PECL_INSTALL 6 | 7 | COPY . /tmp/. 8 | RUN /tmp/build.sh 9 | -------------------------------------------------------------------------------- /php-fpm/VERSION: -------------------------------------------------------------------------------- 1 | 8.2.7 2 | -------------------------------------------------------------------------------- /php-fpm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | RUN_PACKAGES="" 6 | TMP_PACKAGES="" 7 | TMP_PACKAGES="$TMP_PACKAGES autoconf" 8 | RUN_PACKAGES="$RUN_PACKAGES bash" 9 | RUN_PACKAGES="$RUN_PACKAGES cyrus-sasl-dev" # memcached 10 | TMP_PACKAGES="$TMP_PACKAGES freetype-dev" # gd 11 | TMP_PACKAGES="$TMP_PACKAGES g++" 12 | RUN_PACKAGES="$RUN_PACKAGES gd" # gd 13 | TMP_PACKAGES="$TMP_PACKAGES gd-dev" # gd 14 | TMP_PACKAGES="$TMP_PACKAGES git" 15 | RUN_PACKAGES="$RUN_PACKAGES gmp" # gmp 16 | TMP_PACKAGES="$TMP_PACKAGES gmp-dev" # gmp 17 | RUN_PACKAGES="$RUN_PACKAGES imagemagick" # imagick 18 | TMP_PACKAGES="$TMP_PACKAGES imagemagick-dev" # imagick 19 | TMP_PACKAGES="$TMP_PACKAGES libjpeg-turbo-dev" # gd 20 | RUN_PACKAGES="$RUN_PACKAGES libltdl" # gd? 21 | RUN_PACKAGES="$RUN_PACKAGES libmemcached" # memcached 22 | TMP_PACKAGES="$TMP_PACKAGES libmemcached-dev" # memcached 23 | TMP_PACKAGES="$TMP_PACKAGES libpng-dev" # gd 24 | TMP_PACKAGES="$TMP_PACKAGES libtool" 25 | RUN_PACKAGES="$RUN_PACKAGES libwebp" # gd 26 | TMP_PACKAGES="$TMP_PACKAGES libwebp-dev" # gd 27 | RUN_PACKAGES="$RUN_PACKAGES libxml2-dev" # soap 28 | RUN_PACKAGES="$RUN_PACKAGES libxpm" # gd 29 | TMP_PACKAGES="$TMP_PACKAGES libxpm-dev" # gd 30 | RUN_PACKAGES="$RUN_PACKAGES libzip" # zip 31 | TMP_PACKAGES="$TMP_PACKAGES libzip-dev" # zip 32 | TMP_PACKAGES="$TMP_PACKAGES linux-headers" 33 | TMP_PACKAGES="$TMP_PACKAGES make" 34 | eval "apk add --update --no-cache $TMP_PACKAGES $RUN_PACKAGES" 35 | 36 | case "$DOCKER_XENFORO_PHP_EXT_INSTALL" in 37 | *gd*) 38 | echo 'Preparing module: gd...' 39 | docker-php-ext-configure gd \ 40 | --enable-gd \ 41 | --with-freetype \ 42 | --with-jpeg \ 43 | --with-webp \ 44 | --with-xpm 45 | ;; 46 | esac 47 | 48 | # for improved ASLR and optimizations 49 | # https://github.com/docker-library/php/issues/105#issuecomment-278114879 50 | export CFLAGS="$PHP_CFLAGS" CPPFLAGS="$PHP_CPPFLAGS" LDFLAGS="$PHP_LDFLAGS" 51 | 52 | docker-php-source extract 53 | eval "docker-php-ext-install $DOCKER_XENFORO_PHP_EXT_INSTALL" 54 | eval "pecl install $DOCKER_XENFORO_PHP_PECL_INSTALL" 55 | eval "docker-php-ext-enable $DOCKER_XENFORO_PHP_PECL_INSTALL" 56 | /tmp/build_fpm.sh 57 | docker-php-source delete 58 | 59 | # clean up 60 | pecl clear-cache 61 | eval "apk del $TMP_PACKAGES" 62 | rm -rf /tmp/* /var/cache/apk/* 63 | -------------------------------------------------------------------------------- /php-fpm/build_fpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # xdebug: installed but disabled on php-fpm 6 | sed -i'' 's/^/;/' /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 7 | -------------------------------------------------------------------------------- /tests/exif/small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfrocks/docker-xenforo/7d576fe132614633132db32fd8bf6b3a9d47b585/tests/exif/small.jpg -------------------------------------------------------------------------------- /tests/exif/test.php: -------------------------------------------------------------------------------- 1 | destroy(); 5 | -------------------------------------------------------------------------------- /tests/memcached/test.php: -------------------------------------------------------------------------------- 1 | connect($host); -------------------------------------------------------------------------------- /tests/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | DIR=$( pwd ) 6 | NETWORK="docker-xenforo-test" 7 | 8 | { 9 | docker network create "$NETWORK" || true 10 | } &> /dev/null 11 | 12 | 13 | 14 | CONTAINER_ID_MYSQL="$( docker ps -qf "name=$NETWORK-mysql" )" 15 | if [ -z "$CONTAINER_ID_MYSQL" ]; then 16 | MYSQL_ATTEMPT="$( 17 | docker run --network "$NETWORK" \ 18 | --name "$NETWORK-mysql" \ 19 | -e MYSQL_RANDOM_ROOT_PASSWORD=1 \ 20 | -e MYSQL_USER=user \ 21 | -e MYSQL_PASSWORD=password \ 22 | -e MYSQL_DATABASE=db \ 23 | -d mysql:5.7 2>&1 \ 24 | || docker restart "$NETWORK-mysql" \ 25 | )" 26 | echo 'Waiting for mysql...' 27 | sleep 5 28 | 29 | CONTAINER_ID_MYSQL="$( docker ps -qf name="$NETWORK-mysql" )" 30 | if [ -z "$CONTAINER_ID_MYSQL" ]; then 31 | echo "$MYSQL_ATTEMPT" 32 | echo 'Cannot start mysql container' 33 | exit 1 34 | fi 35 | fi 36 | CONTAINER_HOSTNAME_MYSQL="$( docker inspect --format '{{.Config.Hostname}}' "$CONTAINER_ID_MYSQL" )" 37 | 38 | 39 | 40 | CONTAINER_ID_REDIS="$( docker ps -qf "name=$NETWORK-redis" )" 41 | if [ -z "$CONTAINER_ID_REDIS" ]; then 42 | REDIS_ATTEMPT="$( 43 | docker run --network "$NETWORK" \ 44 | --name "$NETWORK-redis" \ 45 | -d redis 2>&1 \ 46 | || docker restart "$NETWORK-redis" 47 | )" 48 | 49 | CONTAINER_ID_REDIS="$( docker ps -qf name="$NETWORK-redis" )" 50 | if [ -z "$CONTAINER_ID_REDIS" ]; then 51 | echo "$REDIS_ATTEMPT" 52 | echo 'Cannot start redis container' 53 | exit 1 54 | fi 55 | fi 56 | CONTAINER_HOSTNAME_REDIS="$( docker inspect --format '{{.Config.Hostname}}' "$CONTAINER_ID_REDIS" )" 57 | 58 | 59 | 60 | cd "$DIR" 61 | { \ 62 | echo "FROM $IMAGE_TAG_FOR_TESTING"; \ 63 | echo "COPY . /tests"; \ 64 | } > Dockerfile 65 | IMAGE_TAG_TMP="$IMAGE_TAG_FOR_TESTING-tmp" 66 | docker build -t "$IMAGE_TAG_TMP" . 67 | CONTAINER_ID_TARGET="$( docker run \ 68 | --network "$NETWORK" \ 69 | -e IMAGE_TAG_FOR_TESTING="$IMAGE_TAG_FOR_TESTING" \ 70 | -e MYSQL="$CONTAINER_HOSTNAME_MYSQL" \ 71 | -e REDIS="$CONTAINER_HOSTNAME_REDIS" \ 72 | -d "$IMAGE_TAG_TMP" 73 | )" 74 | docker exec "$CONTAINER_ID_TARGET" ls -al 75 | 76 | 77 | 78 | for d in */ ; do 79 | if [ -f "$DIR/$d/test.php" ]; then 80 | echo "Testing $d..." 81 | docker exec "$CONTAINER_ID_TARGET" php -c /tests/php.ini "/tests/${d}test.php" 82 | fi 83 | done 84 | 85 | 86 | 87 | echo 'Cleaning up...' 88 | { 89 | docker stop "$CONTAINER_ID_MYSQL" "$CONTAINER_ID_REDIS" "$CONTAINER_ID_TARGET" 90 | docker rm -f "$CONTAINER_ID_MYSQL" "$CONTAINER_ID_REDIS" "$CONTAINER_ID_TARGET" 91 | docker network rm "$NETWORK" || true 92 | } &> /dev/null 93 | echo 'All done!' 94 | -------------------------------------------------------------------------------- /tests/soap/test.php: -------------------------------------------------------------------------------- 1 | open(dirname($argv[0]) . '/a.zip'); 5 | assert($opened); 6 | 7 | exit(0); --------------------------------------------------------------------------------