{"id":49760372,"url":"https://github.com/softcreatrmedia/frankenphp-woltlab-suite","last_synced_at":"2026-05-15T09:01:15.169Z","repository":{"id":356616822,"uuid":"1232914488","full_name":"SoftCreatRMedia/frankenphp-woltlab-suite","owner":"SoftCreatRMedia","description":"WoltLab Suite on FrankenPHP","archived":false,"fork":false,"pushed_at":"2026-05-08T21:11:20.000Z","size":34,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T07:36:00.548Z","etag":null,"topics":["caddy","caddy-server","docker","docker-compose","frankenphp","php","webserver","woltlab","woltlab-suite"],"latest_commit_sha":null,"homepage":"https://softcreatr.dev","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SoftCreatRMedia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T12:02:54.000Z","updated_at":"2026-05-08T21:11:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SoftCreatRMedia/frankenphp-woltlab-suite","commit_stats":null,"previous_names":["softcreatrmedia/frankenphp-woltlab-suite"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SoftCreatRMedia/frankenphp-woltlab-suite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SoftCreatRMedia%2Ffrankenphp-woltlab-suite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SoftCreatRMedia%2Ffrankenphp-woltlab-suite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SoftCreatRMedia%2Ffrankenphp-woltlab-suite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SoftCreatRMedia%2Ffrankenphp-woltlab-suite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SoftCreatRMedia","download_url":"https://codeload.github.com/SoftCreatRMedia/frankenphp-woltlab-suite/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SoftCreatRMedia%2Ffrankenphp-woltlab-suite/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33015817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caddy","caddy-server","docker","docker-compose","frankenphp","php","webserver","woltlab","woltlab-suite"],"created_at":"2026-05-11T05:15:14.402Z","updated_at":"2026-05-14T08:01:24.567Z","avatar_url":"https://github.com/SoftCreatRMedia.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WoltLab Suite on FrankenPHP\n\nProduction-ready Docker image for WoltLab Suite Core on FrankenPHP and Caddy.\n\nThis image is intentionally small in scope:\n\n- FrankenPHP + Caddy in one application container\n- MariaDB as a separate service\n- SSL, HTTP/1.1, HTTP/2, and HTTP/3 through Caddy\n- WoltLab-compatible generic URL rewrites\n\n## Supported Images\n\n| WoltLab Suite | PHP | Default WSC Patch | Tag          |\n|---------------|-----|-------------------|--------------|\n| 6.2           | 8.4 | 6.2.3             | `6.2-php8.4` |\n| 6.1           | 8.3 | 6.1.19            | `6.1-php8.3` |\n| 6.0           | 8.3 | 6.0.25            | `6.0-php8.3` |\n\nThe WoltLab patch version is a build argument and runtime download variable, so newer patch releases do not require a Dockerfile change.\n\n## Manual Setup\n\nThis repository is primarily a Docker package. For administrators who want to set up the same stack directly on a host, see [manual/README.md](manual/README.md).\n\nThe `manual/` directory is intentionally excluded from the Docker build context and is not copied into release images.\n\n## Quick Start\n\nBuild locally:\n\n```sh\ncp .env.example .env\ndocker compose up -d --build\n```\n\nOpen:\n\n```text\nhttps://localhost/install.php\n```\n\nDatabase values for the installer:\n\n```text\nHost: db\nDatabase: generated in the wsc-secrets Docker volume\nUser: generated in the wsc-secrets Docker volume\nPassword: generated in the wsc-secrets Docker volume\n```\n\nThe compose file exposes these values to the WoltLab installer through `WCFSETUP_DBHOST`, `WCFSETUP_DBNAME_FILE`, `WCFSETUP_DBUSER_FILE`, and `WCFSETUP_DBPASSWORD_FILE`, matching the setup variables used by `wsc-dockerized` while avoiding a plaintext default password in the compose file.\n\nIf `MYSQL_DATABASE`, `MYSQL_USER`, or `MYSQL_PASSWORD` are empty or missing, `credential-init` generates random values once and stores them in the `wsc-secrets` Docker volume. To provide fixed values, set them before the first `docker compose up`. Existing MariaDB volumes keep their initial credentials.\n\n## Using Prebuilt GHCR Images\n\nPrebuilt multi-architecture images are published to:\n\n```text\nghcr.io/softcreatrmedia/frankenphp-woltlab-suite\n```\n\nAvailable tags:\n\n| WoltLab Suite | PHP | Tags                          |\n|---------------|-----|-------------------------------|\n| 6.2           | 8.4 | `6.2-php8.4`, `6.2.3-php8.4`  |\n| 6.1           | 8.3 | `6.1-php8.3`, `6.1.19-php8.3` |\n| 6.0           | 8.3 | `6.0-php8.3`, `6.0.25-php8.3` |\n\nUse `compose.prebuilt.yaml` to disable local builds and pull from GHCR:\n\n```sh\ncp .env.example .env\ndocker compose -f compose.yaml -f compose.prebuilt.yaml pull\ndocker compose -f compose.yaml -f compose.prebuilt.yaml up -d\n```\n\nSelect a different prebuilt variant by changing `WSC_TAG` in `.env`:\n\n```env\nWSC_TAG=6.1-php8.3\n```\n\nOverride `WSC_PREBUILT_IMAGE` only when using a fork or private registry:\n\n```env\nWSC_PREBUILT_IMAGE=ghcr.io/your-org/frankenphp-woltlab-suite\n```\n\n## Building\n\nBuild the default WSC 6.2 / PHP 8.4 image:\n\n```sh\ndocker build \\\n  --build-arg PHP_VERSION=8.4 \\\n  --build-arg WSC_REF=6.2.3 \\\n  -t frankenphp-woltlab-suite:6.2-php8.4 .\n```\n\nBuild all supported variants:\n\n```sh\ndocker buildx bake\n```\n\nBuild one variant:\n\n```sh\ndocker buildx bake wsc61_php83\n```\n\n## Runtime Configuration\n\nCommon environment variables:\n\n| Variable                            | Default                                           | Purpose                                                                                                                                     |\n|-------------------------------------|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|\n| `SERVER_NAME`                       | `localhost`                                       | Caddy site address. Use your domain in production.                                                                                          |\n| `WSC_REF`                           | `6.2.3`                                           | WoltLab/WCF tag or branch used when building the installer.                                                                                 |\n| `WCFSETUP_DBHOST`                   | `db`                                              | Database host passed to the WoltLab installer.                                                                                              |\n| `WCFSETUP_DBNAME_FILE`              | `/run/wsc-secrets/db-name`                        | File containing the database name for the WoltLab installer.                                                                                |\n| `WCFSETUP_DBUSER_FILE`              | `/run/wsc-secrets/db-user`                        | File containing the database user for the WoltLab installer.                                                                                |\n| `WCFSETUP_DBPASSWORD_FILE`          | `/run/wsc-secrets/db-password`                    | File containing the database password for the WoltLab installer.                                                                            |\n| `MYSQL_INNODB_BUFFER_POOL_SIZE`     | `1G`                                              | MariaDB InnoDB buffer pool size. Lower this only on very small servers.                                                                     |\n| `PHP_MEMORY_LIMIT`                  | `512M`                                            | PHP memory limit.                                                                                                                           |\n| `PHP_UPLOAD_MAX_FILESIZE`           | `64M`                                             | Maximum upload file size.                                                                                                                   |\n| `PHP_POST_MAX_SIZE`                 | `64M`                                             | Maximum POST body size.                                                                                                                     |\n| `PHP_DISABLE_FUNCTIONS`             | `exec,passthru,shell_exec,system,proc_open,popen` | PHP functions disabled by default to reduce command-execution risk. Set to an empty value only if a trusted plugin requires one of them.    |\n| `PHP_OPCACHE_VALIDATE_TIMESTAMPS`   | `0`                                               | Disable timestamp checks for production performance. Restart `wsc` after package updates that change PHP files.                             |\n| `PHP_OPCACHE_MEMORY_CONSUMPTION`    | `256`                                             | OPcache shared memory size in MB.                                                                                                           |\n| `PHP_OPCACHE_MAX_ACCELERATED_FILES` | `20000`                                           | Maximum number of cached PHP files.                                                                                                         |\n| `FRANKENPHP_NUM_THREADS`            | `1`                                               | FrankenPHP PHP thread count. Keep this at `1` unless you have tested installation, package updates, and style rebuilds with a higher value. |\n| `FRANKENPHP_MAX_THREADS`            | `1`                                               | FrankenPHP maximum PHP thread count. Keep this aligned with `FRANKENPHP_NUM_THREADS` by default.                                            |\n| `FRANKENPHP_CONFIG`                 | empty                                             | Extra FrankenPHP global config.                                                                                                             |\n| `CADDY_GLOBAL_OPTIONS`              | empty                                             | Extra Caddy global options.                                                                                                                 |\n| `CADDY_SERVER_EXTRA_DIRECTIVES`     | empty                                             | Extra Caddy site directives, for example a custom `tls` directive.                                                                          |\n| `CERTBOT_CERT_NAME`                 | empty                                             | Certificate directory name below `/etc/letsencrypt/live` when using `compose.certbot.yaml`.                                                 |\n| `MYSQL_MAX_CONNECTIONS`             | `300`                                             | MariaDB connection limit.                                                                                                                   |\n| `MYSQL_TABLE_OPEN_CACHE`            | `4000`                                            | MariaDB table cache size.                                                                                                                   |\n| `MYSQL_THREAD_CACHE_SIZE`           | `64`                                              | MariaDB thread cache size.                                                                                                                  |\n\nThe application volume is `/app/public`. The image builds a WoltLab installer from the selected `WoltLab/WCF` GitHub tag or branch and stores it in `/usr/src/woltlab`. If `/app/public` is empty, the entrypoint copies that prebuilt installer into the volume.\n\n## Hardened Runtime\n\nThe default compose file runs the application container with a hardened profile:\n\n- non-root `www-data` user\n- read-only root filesystem\n- `no-new-privileges`\n- all Linux capabilities dropped except `NET_BIND_SERVICE`\n- tmpfs-backed `/tmp` with `noexec,nosuid`\n- writable mounts only for `/app/public`, `/data`, and `/config`\n\n### SSL / Certbot Certificate\n\nThe default Caddy behavior is usually enough for public DNS names: set `SERVER_NAME` to the domain and Caddy will request and renew the certificate itself. Use Certbot only if you want the host to manage certificates, or if you need a certificate type that Caddy cannot request for you.\n\nTo request a new certificate on the host, stop anything that is using ports 80 or 443 and run Certbot in standalone mode:\n\n```sh\napt-get update\napt-get install -y certbot\n\ndocker compose -f compose.yaml down\ncertbot certonly --standalone -d example.com\n```\n\nThen copy the host-managed certificate into a Docker volume at startup and tell Caddy to use it:\n\n```env\nSERVER_NAME=example.com\nCERTBOT_CERT_NAME=example.com\nCADDY_SERVER_EXTRA_DIRECTIVES=tls /certs/fullchain.pem /certs/privkey.pem\n```\n\n```sh\ndocker compose -f compose.yaml -f compose.certbot.yaml up -d --build\n```\n\nWhen using GHCR images, include `compose.prebuilt.yaml` and omit `--build`:\n\n```sh\ndocker compose -f compose.yaml -f compose.prebuilt.yaml -f compose.certbot.yaml up -d\n```\n\nFor an IP address certificate, set both `SERVER_NAME` and `CERTBOT_CERT_NAME` to the IP address. Set `CADDY_GLOBAL_OPTIONS` to `default_sni \u003cip-address\u003e` as well, because many clients omit SNI when connecting directly to an IP address.\n\nAfter Certbot renews a host-managed certificate, refresh the Docker copy and restart Caddy:\n\n```sh\ndocker compose -f compose.yaml -f compose.certbot.yaml run --rm certbot-cert-init\ndocker compose -f compose.yaml -f compose.certbot.yaml restart wsc\n```\n\n## HTTP/3\n\nExpose UDP 443 as well as TCP 443:\n\n```yaml\nports:\n  - \"443:443/tcp\"\n  - \"443:443/udp\"\n```\n\nCaddy will advertise HTTP/3 automatically when TLS is active.\n\n## URL Rewrites\n\nThe Caddyfile implements the common WoltLab rewrite pattern:\n\n```text\n/app/path -\u003e /app/index.php?path if /app/index.php exists\n/foo/bar  -\u003e /index.php?foo/bar\n```\n\nExisting files and directories are served directly.\n\nAfter installation, enable WoltLab's matching application setting in:\n\n```text\nACP -\u003e Configuration -\u003e Options -\u003e General -\u003e Enable URL rewrite\n```\n\nYou can validate the ACP system check and rewritten ACP routes with:\n\n```sh\nWSC_BASE_URL=https://example.com \\\nWSC_ADMIN_USER=admin \\\nWSC_ADMIN_PASSWORD='change-me' \\\nWSC_ENABLE_URL_REWRITE=1 \\\nnpm run verify:production\n```\n\n## Security Notes\n\nThe bundled Caddyfile:\n\n- hides the `Server` header\n- disables `expose_php`\n- denies dotfiles except `/.well-known/*`\n- denies common archive, backup, config, SQL, key, certificate, shell, and template files\n- denies direct access to `/vendor/*`\n- denies direct access to selected non-public PHP paths\n- sends long-lived immutable cache headers for static assets\n\nWorker mode is not enabled. WoltLab Suite has not been audited for a persistent PHP worker lifecycle, and classic request isolation is the safer production default.\n\n## Backups\n\nCreate a database, application volume, and generated-secrets backup:\n\n```sh\nscripts/backup.sh\n```\n\nRestore on a clean deployment:\n\n```sh\nscripts/restore.sh backups/\u003ctimestamp\u003e\n```\n\nIf you restore a deployment that uses additional compose overlays, pass the same compose files through `COMPOSE_ARGS`:\n\n```sh\nCOMPOSE_ARGS=\"-f compose.yaml -f compose.certbot.yaml\" \\\nscripts/restore.sh backups/\u003ctimestamp\u003e\n```\n\n## Updating WoltLab\n\nUse WoltLab's built-in package updater for installed communities. The image bootstraps new installations only; it does not overwrite an existing `/app/public` volume.\n\nFor new images on a newer patch release:\n\n```sh\nWSC_REF=6.2.4 docker compose up -d --build\n```\n\n`WSC_REF` accepts a tag such as `6.2.3` or a branch such as `6.2`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftcreatrmedia%2Ffrankenphp-woltlab-suite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoftcreatrmedia%2Ffrankenphp-woltlab-suite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftcreatrmedia%2Ffrankenphp-woltlab-suite/lists"}