https://github.com/hussainweb/docker-drupal-base
Docker image to run your Drupal projects
https://github.com/hussainweb/docker-drupal-base
apache docker drupal php
Last synced: about 1 month ago
JSON representation
Docker image to run your Drupal projects
- Host: GitHub
- URL: https://github.com/hussainweb/docker-drupal-base
- Owner: hussainweb
- Created: 2019-12-19T20:27:49.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-06-24T12:02:54.000Z (almost 2 years ago)
- Last Synced: 2025-01-06T00:23:10.104Z (over 1 year ago)
- Topics: apache, docker, drupal, php
- Language: Dockerfile
- Homepage: https://hub.docker.com/r/hussainweb/drupal-base
- Size: 61.5 KB
- Stars: 1
- Watchers: 3
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Drupal Base Image for Docker
This image provides a basic runtime for Drupal projects. It's designed for CI but is also suitable for local development environments using `docker-compose`. This image is similar to the [official Drupal image](https://hub.docker.com/_/drupal) but does not include the Drupal core files, allowing you to mount your own codebase.
## Image Variants
This repository contains two main variants of the Drupal base image:
- `apache-bookworm`: Based on Debian Bookworm with Apache.
- `fpm-alpine`: Based on Alpine Linux with PHP-FPM.
- `frankenphp-trixie`: Based on Debian Trixie with FrankenPHP (experimental).
Choose the image that best fits your needs. The Apache image is a good choice for a simple, all-in-one container, while the FPM image is ideal for use with a separate web server like Nginx.
## Supported PHP Versions
This image supports the following PHP versions:
- PHP 8.2
- PHP 8.3
- PHP 8.4
- PHP 8.5 (latest)
Each version is available in all variants (apache-bookworm, apache-trixie, fpm-alpine, frankenphp-trixie).
### Available Tags
- `php8.5`, `latest` - PHP 8.5 with Apache on Debian Trixie
- `php8.5-apache-trixie` - PHP 8.5 with Apache on Debian Trixie
- `php8.5-apache-bookworm` - PHP 8.5 with Apache on Debian Bookworm
- `php8.5-alpine`, `php8.5-fpm-alpine`, `latest-alpine` - PHP 8.5 FPM on Alpine Linux
- `php8.4`, `php8.3`, `php8.2` - Older PHP versions with Apache on Debian Trixie
- `php8.4-alpine`, `php8.3-alpine`, `php8.2-alpine` - Older PHP versions FPM on Alpine Linux
- `php8.5-frankenphp-trixie`, `php8.4-frankenphp-trixie` - FrankenPHP on Debian Trixie
All images support both `linux/amd64` and `linux/arm64` architectures.
## Usage
### Apache
The Apache image is straightforward to use. Mount your Drupal codebase to `/var/www/html` in the container.
Here is an example `docker-compose.yml` snippet:
```yaml
services:
drupal:
image: hussainweb/drupal-base:php8.5
volumes:
- ./path/to/your/drupal/root:/var/www/html
ports:
- "8080:80"
restart: always
```
### FPM-Alpine
The FPM-Alpine image requires a separate web server. The following example uses Nginx.
Here is an example `docker-compose.yml` snippet:
```yaml
services:
drupal:
image: hussainweb/drupal-base:php8.5-alpine
volumes:
- ./path/to/your/drupal/root:/var/www/html
restart: always
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./path/to/your/drupal/root:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- drupal
restart: always
```
#### Nginx Configuration
You will need an `nginx.conf` file in your project root. Here is a production-ready example:
```nginx
server {
listen 80 default_server;
server_name localhost _;
root /var/www/html/web;
index index.php index.html index.htm;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Deny access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Deny access to sensitive files
location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl|svn|git|bzr|hg|CVS)(~|\.sw[op]|\.bak|\.orig|\.save)?$ {
deny all;
}
# Deny access to backup files
location ~ ~$ {
deny all;
access_log off;
log_not_found off;
}
# Theme and frontend assets
location ~* ^/(themes|core)/.*\.(css|js|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot)$ {
access_log off;
}
# Handle PHP files
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass drupal:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTP_PROXY "";
fastcgi_read_timeout 300;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Handle Drupal clean URLs
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Drupal aggregate CSS/JS paths (multisite-safe)
# Required since Drupal 10.1 as aggregate files are created on first request.
# See https://www.drupal.org/node/3301716
location ~* ^/sites/[^/]+/files/(css|js)/ {
try_files $uri /index.php?$query_string;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Image styles (must go through Drupal if missing)
location ~* ^/sites/[^/]+/files/styles/ {
try_files $uri /index.php?$query_string;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# All other static assets
location ~* \.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Cache HTML files
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public";
}
# Deny access to sensitive directories
location ~* ^/(sites/.*/private/|sites/.*/tmp/) {
deny all;
}
}
```
**Note:** Adjust `root` path based on your Drupal installation structure. If your Drupal files are directly in the mounted directory, use `/var/www/html`. If you have a `web` subdirectory (as in Composer-based installs), use `/var/www/html/web`.
**Important:** For image style generation and CSS/JS aggregation to work properly, the Drupal source code must be available in **both** the Nginx and PHP-FPM containers. When Nginx receives a request for a missing image style or aggregate file, it passes the request to Drupal, which generates the file. Nginx then needs filesystem access to serve the generated file on subsequent requests.
- **Using volumes:** Mount your Drupal codebase to both containers (as shown in the docker-compose example above).
- **Using a custom Dockerfile:** If you copy files into the PHP-FPM image instead of mounting them, you must also build a custom Nginx image that contains the same static files (themes, modules, and the `sites/*/files` directory if pre-populated).
### FrankenPHP
The FrankenPHP image uses Caddy as the web server with FrankenPHP for PHP execution. It is configured to serve the Drupal site from `/app/web`.
Here is an example `docker-compose.yml` snippet:
```yaml
services:
drupal:
image: hussainweb/drupal-base:php8.5-frankenphp-trixie
volumes:
- ./path/to/your/drupal/root:/app
ports:
- "8080:80"
restart: always
```
**Note:** Mount your entire Drupal project root to `/app`. The image expects Drupal's `index.php` to be in `/app/web`.
#### Default Caddyfile
The image includes a default Caddyfile optimized for Drupal:
```caddyfile
{
frankenphp
order php_server before file_server
}
:80 {
encode zstd gzip
root * /app/web
php_server
file_server
}
```
#### Custom Caddyfile
To customize the Caddy configuration, mount your own Caddyfile:
```yaml
services:
drupal:
image: hussainweb/drupal-base:php8.5-frankenphp-trixie
volumes:
- ./path/to/your/drupal/root:/app
- ./Caddyfile:/etc/frankenphp/Caddyfile
ports:
- "8080:80"
restart: always
```
Here is an example custom Caddyfile with additional security and caching:
```caddyfile
{
frankenphp
order php_server before file_server
}
:80 {
encode zstd gzip
root * /app/web
# Security: deny access to sensitive files
@sensitive {
path *.engine *.inc *.install *.module *.profile *.po *.sh *.sql *.theme *.twig *.xtmpl *.yml *.yaml
path /composer.json /composer.lock /web.config
path /.* /vendor/*
}
respond @sensitive 403
# Cache static assets
@static {
path *.css *.js *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
php_server
file_server
}
```
#### Enabling HTTPS with FrankenPHP
FrankenPHP supports automatic HTTPS. To enable it, update your Caddyfile:
```caddyfile
{
frankenphp
order php_server before file_server
}
your-domain.com {
encode zstd gzip
root * /app/web
php_server
file_server
}
```
And expose port 443 in your `docker-compose.yml`:
```yaml
services:
drupal:
image: hussainweb/drupal-base:php8.5-frankenphp-trixie
volumes:
- ./path/to/your/drupal/root:/app
- ./Caddyfile:/etc/frankenphp/Caddyfile
- caddy_data:/data
ports:
- "80:80"
- "443:443"
restart: always
volumes:
caddy_data:
```
Caddy will automatically obtain and renew TLS certificates from Let's Encrypt.