Modern, production-minded Drupal boilerplate designed for public/open-source use.
This repository uses the Drupal Recommended Project pattern with:
- Composer-managed Drupal core
- Environment-driven (
12-factor) runtime configuration - Docker local development stack (PHP-FPM + Nginx + MariaDB + Redis)
- Hardened multi-stage production image
- Kubernetes-first Helm chart (Ingress, HPA, PDB, CronJob)
- CI security gates (SAST/SCA/secrets/container scan) and branch-based image tagging
- Safe to publish publicly (no private references, no secrets, no proprietary modules/submodules)
- Secure-by-default deployment posture
- Reproducible build flow with dependency lock + containerized build (commit
composer.lockafter initial dependency resolution) - Scalable cloud-native architecture for multi-pod Drupal workloads
.
├── Dockerfile
├── Makefile
├── docker-compose.yml
├── charts/drupal-boilerplate/ # Helm chart
├── docker/ # Nginx, PHP, observability config
├── web/
│ ├── modules/custom/
│ ├── themes/custom/
│ └── sites/default/settings.php # Env-driven, hardened settings
└── .github/workflows/ # CI, security, image publish
cp .env.example .envmake upCore services:
nginx(http://localhost:8080)php(php-fpm runtime)db(MariaDB)redis
Optional profiles:
make up-devtools # Mailhog + Adminer
make up-observability # Prometheus + Grafana + Redis exporter
make up-tls # Traefik TLS routing for drupal.localhostmake composer-install
make install DRUPAL_INSTALL_ACCOUNT_PASS='change-me-local'Useful commands:
make shell
make drush ARGS="status"
make cron
make down- Foundation:
drupal/core-recommended+drupal/core-composer-scaffold - Contrib modules included for cloud-native storage/cache patterns:
drupal/redisdrupal/flysystemdrupal/flysystem_s3
drush/drushis available in the CLI image target for operational commands.
web/sites/default/settings.php is environment-first:
- Database config from env vars (
DB_*) - Trusted host patterns from
DRUPAL_TRUSTED_HOST_PATTERNS - Reverse proxy config from env vars
- Redis/APCu integration when available
- No secrets stored in repository
- Automated Drupal cron disabled by default (
DRUPAL_DISABLE_POORMANS_CRON=true)
- Multi-stage Docker build:
- build-runtime:
composer install --no-dev --optimize-autoloader - build-cli: includes dev tools (Drush) for ops/cron tasks
- runtime: minimal non-root PHP-FPM image
- build-runtime:
- Hardening:
- non-root user (
uid/gid 10001) - no-new-privileges at runtime (Compose/K8s)
- read-only root filesystem (Compose/K8s)
- explicit writable mounts for
/tmp, private files, and public files
- non-root user (
- Performance:
- OPcache tuned for production (
validate_timestamps=0) - APCu enabled
- Redis extension enabled
- OPcache tuned for production (
helm upgrade --install drupal charts/drupal-boilerplate \
--namespace drupal \
--create-namespacehelm upgrade --install drupal charts/drupal-boilerplate \
--namespace drupal \
--set image.php.tag='sha-<git-sha>' \
--set image.cli.tag='sha-<git-sha>' \
--set secrets.hashSalt='replace-with-secure-random' \
--set secrets.dbPassword='replace-with-db-password'Use object storage for sites/default/files to avoid shared PVC coupling:
helm upgrade --install drupal charts/drupal-boilerplate \
--namespace drupal \
--set env.filesDriver=s3 \
--set env.s3.bucket='drupal-assets' \
--set env.s3.region='us-east-1' \
--set env.s3.endpoint='https://s3.example.com' \
--set secrets.s3AccessKeyId='...' \
--set secrets.s3SecretAccessKey='...'helm upgrade --install drupal charts/drupal-boilerplate \
--namespace drupal \
--set env.filesDriver=pvc \
--set persistence.enabled=true \
--set persistence.size=50Gi- Deployment (Nginx + PHP-FPM pod)
- Service + Ingress
- HorizontalPodAutoscaler
- PodDisruptionBudget
- ConfigMap + Secret templates
- Optional PVC
- CronJob running external
drush cron
This boilerplate disables Drupal automated cron (poormanscron) and runs cron externally with Kubernetes CronJob.
Default schedule:
*/15 * * * *runningvendor/bin/drush cron --yes
GitHub Actions include:
- Composer and YAML lint checks
- Helm lint
- Dependency review (PR)
- Trivy filesystem/config/container scanning
- Gitleaks secret scanning
- SonarCloud static analysis (optional, gated by repository configuration)
- Branch-based container tags (e.g.
main, feature branch names, andsha-*)
The repository includes .github/workflows/sonarcloud.yml and sonar-project.properties.
To enable scanning:
- Create a SonarCloud project.
- Add GitHub repository variables:
SONAR_ORGANIZATIONSONAR_PROJECT_KEY
- Add GitHub repository secret:
SONAR_TOKEN
The SonarCloud workflow runs on push and pull requests, and is skipped automatically when these settings are not configured.
See SECURITY.md for vulnerability reporting and responsible disclosure.
MIT License. See LICENSE.