Skip to content

Deploying Drupal

Introduction

Drupal is one of the world’s most powerful and flexible open-source content management systems (CMS), powering millions of websites and applications globally. Created in 2001, Drupal has evolved into a robust enterprise-grade platform trusted by organizations like NASA, Tesla, The Economist, and numerous government agencies.

Drupal is renowned for:

  • Enterprise-Grade Flexibility: Build everything from simple blogs to complex enterprise applications
  • Powerful Content Architecture: Structured content types, taxonomies, and advanced content modeling
  • Extensive Module Ecosystem: Over 48,000 contributed modules for virtually any functionality
  • Security Focus: Dedicated security team and regular updates make it ideal for high-security requirements
  • Multilingual Support: Built-in multilingual capabilities for global audiences
  • API-First Architecture: Headless/decoupled capabilities with robust REST and JSON:API support
  • Scalability: Powers high-traffic sites handling millions of visitors
  • Accessibility: Strong commitment to WCAG and accessibility standards
  • Community: Large, active community with regular contributions and support

Common use cases include corporate websites, e-commerce platforms, government portals, educational institutions, news publications, community forums, and headless CMS implementations.

This comprehensive guide walks you through deploying Drupal on Klutch.sh using Docker, including detailed installation steps, database configuration, sample Dockerfile, persistent storage setup, and production-ready best practices.

Prerequisites

Before you begin, ensure you have the following:

  • A Klutch.sh account
  • A GitHub account with a repository for your Drupal project
  • Docker installed locally for testing (optional but recommended)
  • Basic understanding of Docker, PHP, and content management systems
  • A database (MySQL, MariaDB, or PostgreSQL) - you can deploy one on Klutch.sh following our database guides

Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your Drupal deployment project:

Terminal window
mkdir drupal-klutch
cd drupal-klutch
git init

Step 2: Create the Dockerfile

Create a Dockerfile in your project root directory. This will define your Drupal container configuration:

# Use Drupal 10 with Apache
# For production, consider pinning to a specific version (e.g., drupal:10.2.3-apache)
FROM drupal:10-apache
# Install additional PHP extensions commonly needed for Drupal
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libpq-dev \
git \
unzip \
&& docker-php-ext-configure gd --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd pdo pdo_mysql pdo_pgsql opcache \
&& rm -rf /var/lib/apt/lists/*
# Install Composer (consider pinning to specific version for production, e.g., composer:2.6)
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Set recommended PHP.ini settings for Drupal
RUN { \
echo 'memory_limit=256M'; \
echo 'upload_max_filesize=64M'; \
echo 'post_max_size=64M'; \
echo 'max_execution_time=300'; \
echo 'opcache.memory_consumption=128'; \
echo 'opcache.interned_strings_buffer=8'; \
echo 'opcache.max_accelerated_files=4000'; \
echo 'opcache.revalidate_freq=60'; \
echo 'opcache.fast_shutdown=1'; \
} > /usr/local/etc/php/conf.d/drupal-recommended.ini
# Set working directory
WORKDIR /var/www/html
# Copy custom modules, themes, and configuration if you have them
# COPY ./modules/custom /var/www/html/modules/custom
# COPY ./themes/custom /var/www/html/themes/custom
# COPY ./config /var/www/html/config
# Set proper permissions
RUN chown -R www-data:www-data /var/www/html
# Expose port 80
EXPOSE 80

Note: Drupal 10 is the latest major version with significant improvements. You can also use drupal:9-apache for Drupal 9 or specify a specific version like drupal:10.2-apache.

Step 3: Create a Settings File Template (Optional)

Create a settings.local.php file that can be used for environment-specific configuration. This file should be referenced in your main settings.php:

<?php
/**
* settings.local.php - Environment-specific settings
* This file is loaded by settings.php when present
*/
// Database configuration (use environment variables for security)
// IMPORTANT: Always set these environment variables in production
if (!getenv('DRUPAL_DB_NAME') || !getenv('DRUPAL_DB_USER') || !getenv('DRUPAL_DB_PASSWORD')) {
// Use defaults for local development only
$databases['default']['default'] = [
'database' => getenv('DRUPAL_DB_NAME') ?: 'drupal',
'username' => getenv('DRUPAL_DB_USER') ?: 'drupal',
'password' => getenv('DRUPAL_DB_PASSWORD') ?: 'drupal',
'host' => getenv('DRUPAL_DB_HOST') ?: 'localhost',
'port' => getenv('DRUPAL_DB_PORT') ?: '3306',
'driver' => getenv('DRUPAL_DB_DRIVER') ?: 'mysql',
'prefix' => '',
'collation' => 'utf8mb4_general_ci',
];
} else {
// Production configuration
$databases['default']['default'] = [
'database' => getenv('DRUPAL_DB_NAME'),
'username' => getenv('DRUPAL_DB_USER'),
'password' => getenv('DRUPAL_DB_PASSWORD'),
'host' => getenv('DRUPAL_DB_HOST'),
'port' => getenv('DRUPAL_DB_PORT') ?: '3306',
'driver' => getenv('DRUPAL_DB_DRIVER') ?: 'mysql',
'prefix' => '',
'collation' => 'utf8mb4_general_ci',
];
}
// Trusted host patterns (security)
$settings['trusted_host_patterns'] = [
'^example-app\.klutch\.sh$',
'^.*\.klutch\.sh$',
];
// File paths
$settings['file_public_path'] = 'sites/default/files';
$settings['file_private_path'] = 'sites/default/files/private';
$settings['file_temp_path'] = '/tmp';
// Hash salt (REQUIRED for production - use a unique random value)
// Generate with: openssl rand -base64 32
$settings['hash_salt'] = getenv('DRUPAL_HASH_SALT') ?: '';
if (empty($settings['hash_salt']) && getenv('DRUPAL_ENV') === 'production') {
throw new \Exception('DRUPAL_HASH_SALT environment variable must be set for production.');
}
// Disable CSS/JS aggregation for development, enable for production
$config['system.performance']['css']['preprocess'] = getenv('DRUPAL_ENV') === 'production';
$config['system.performance']['js']['preprocess'] = getenv('DRUPAL_ENV') === 'production';
// Error reporting
if (getenv('DRUPAL_ENV') === 'development') {
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
$config['system.logging']['error_level'] = 'verbose';
}

Step 4: Create Docker Compose for Local Development (Optional)

For local development, you can use Docker Compose to run Drupal with a database. Create a docker-compose.yml file:

version: '3.8'
services:
drupal:
build: .
ports:
- "8080:80"
environment:
DRUPAL_DB_HOST: mysql
DRUPAL_DB_NAME: drupal
DRUPAL_DB_USER: drupal
DRUPAL_DB_PASSWORD: drupal_password
DRUPAL_HASH_SALT: local-development-hash-salt
DRUPAL_ENV: development
volumes:
- drupal_modules:/var/www/html/modules
- drupal_themes:/var/www/html/themes
- drupal_sites:/var/www/html/sites
depends_on:
- mysql
mysql:
# Consider pinning to specific version for consistency (e.g., mysql:8.0.35)
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: drupal
MYSQL_USER: drupal
MYSQL_PASSWORD: drupal_password
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
volumes:
drupal_modules:
drupal_themes:
drupal_sites:
mysql_data:

Note: Docker Compose is only for local development. Klutch.sh does not support Docker Compose for deployment.

Step 5: Test Locally (Optional)

Before deploying to Klutch.sh, you can test your Drupal setup locally:

Terminal window
# Build and start the containers
docker-compose up -d
# Wait for MySQL to be ready (about 30 seconds)
sleep 30
# Access Drupal at http://localhost:8080
# Follow the installation wizard:
# 1. Choose installation profile (Standard, Minimal, or Demo)
# 2. Database settings will be auto-configured from environment variables
# 3. Complete site information (site name, email, admin account)
# View logs
docker-compose logs -f drupal
# Stop and remove containers when done testing
docker-compose down

Step 6: Create .dockerignore File

Create a .dockerignore file to exclude unnecessary files from your Docker build:

.git
.gitignore
docker-compose.yml
README.md
.env
.env.local
node_modules
sites/default/files/*
sites/simpletest

Step 7: Push to GitHub

Commit your Dockerfile and configuration files to your GitHub repository:

Terminal window
git add Dockerfile settings.local.php .dockerignore
git commit -m "Add Drupal Dockerfile and configuration"
git remote add origin https://github.com/yourusername/drupal-klutch.git
git push -u origin main

Note: The docker-compose.yml file is excluded from the commit since it’s only for local development. Klutch.sh does not support Docker Compose.


Database Configuration

Drupal requires a database to store content, configuration, and user data. You can use MySQL, MariaDB, or PostgreSQL. We recommend deploying a separate database on Klutch.sh.

Option 1: Deploy MySQL on Klutch.sh

Follow our MySQL deployment guide to set up a MySQL database. After deployment, you’ll receive a connection URL.

Option 2: Deploy PostgreSQL on Klutch.sh

Follow our PostgreSQL deployment guide for an alternative database option.

Option 3: Deploy MariaDB on Klutch.sh

Follow our MariaDB deployment guide for a MySQL-compatible option with enhanced features.

Database Connection Settings

Once you have a database deployed, you’ll need these environment variables for your Drupal app:

  • DRUPAL_DB_HOST: Your database app URL (e.g., mysql-app.klutch.sh)
  • DRUPAL_DB_PORT: 8000 (the port Klutch.sh uses for TCP traffic)
  • DRUPAL_DB_NAME: Your database name (e.g., drupal)
  • DRUPAL_DB_USER: Your database username
  • DRUPAL_DB_PASSWORD: Your database password
  • DRUPAL_DB_DRIVER: mysql or pgsql depending on your database

Deploying to Klutch.sh

Now that your Drupal project is ready and pushed to GitHub, follow these steps to deploy it on Klutch.sh with persistent storage.

Deployment Steps

    1. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    2. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “Drupal Website”).

    3. Create a New App

      Navigate to Create App and configure the following settings:

    4. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main or master)
    5. Configure Traffic Type

      • Traffic Type: Select HTTP (Drupal is a web application)
      • Internal Port: Set to 80 (the default Apache port that your container listens on)
    6. Set Environment Variables

      Add the following environment variables for your Drupal configuration:

      Database Connection:

      • DRUPAL_DB_HOST: Your database app URL (e.g., mysql-app.klutch.sh)
      • DRUPAL_DB_PORT: 8000
      • DRUPAL_DB_NAME: Your database name (e.g., drupal)
      • DRUPAL_DB_USER: Your database username
      • DRUPAL_DB_PASSWORD: Your database password (use a strong password)
      • DRUPAL_DB_DRIVER: mysql or pgsql

      Drupal Configuration:

      • DRUPAL_HASH_SALT: A random string for security (generate using openssl rand -base64 32)
      • DRUPAL_ENV: production

      Security Note: Always use strong, unique passwords and hash salts for production deployments. Never commit sensitive values to your repository.

    7. Attach Persistent Volumes

      Drupal requires persistent storage for uploaded files, private files, and site configuration:

      Sites Directory Volume:

      • In the Volumes section, click “Add Volume”
      • Mount Path: Enter /var/www/html/sites/default/files
      • Size: Choose based on your expected file storage needs (e.g., 10GB, 20GB, 50GB)

      Important: This volume stores all user-uploaded files (images, documents, media). Without a persistent volume, all uploaded files will be lost when the container restarts.

    8. Configure Additional Settings

      • Region: Select the region closest to your users for optimal latency
      • Compute Resources: Choose CPU and memory based on your traffic (minimum 512MB RAM, 1GB+ recommended for production)
      • Instances: Start with 1 instance (you can scale horizontally later)
    9. Deploy Your Drupal Site

      Click “Create” to start the deployment. Klutch.sh will:

      • Automatically detect your Dockerfile in the repository root
      • Build the Docker image with Apache and PHP configured
      • Attach the persistent volume for file storage
      • Start your Drupal container
      • Assign a URL for external access
    10. Complete Drupal Installation

      Once deployment is complete, you’ll receive a URL like example-app.klutch.sh. Visit this URL in your browser to complete the Drupal installation wizard:

      • Choose your installation profile (Standard, Minimal, or Demo)
      • Configure site information (site name, site email address)
      • Create the administrator account
      • Configure regional settings

      The database connection will be automatically configured using the environment variables you set.


Post-Deployment Configuration

Enable Clean URLs

Drupal’s Apache .htaccess file should enable clean URLs by default. Verify by visiting: https://example-app.klutch.sh/admin/config/search/path

Configure File System

  1. Navigate to Administration > Configuration > Media > File system (/admin/config/media/file-system)
  2. Verify the public and private file paths:
    • Public file system path: sites/default/files
    • Private file system path: sites/default/files/private (create if needed)
  3. Ensure the directories are writable

Set Up Cron

Drupal uses cron for maintenance tasks. Configure cron to run periodically:

  1. Visit Administration > Configuration > System > Cron (/admin/config/system/cron)
  2. Set the cron run interval (e.g., every 3 hours)
  3. Optionally, set up an external cron job to trigger: https://example-app.klutch.sh/cron/YOUR_CRON_KEY

Install Additional Modules

Install commonly needed modules using Drush or Composer:

Terminal window
# Connect to your container (if you have access)
composer require drupal/admin_toolbar
composer require drupal/pathauto
composer require drupal/token
composer require drupal/metatag
composer require drupal/google_analytics
# Enable the modules
drush en admin_toolbar admin_toolbar_tools pathauto token metatag google_analytics -y

Updating Drupal

To update Drupal core or modules:

Terminal window
# Update Drupal core
composer update drupal/core-recommended --with-dependencies
# Update all modules
composer update
# Update a specific module
composer update drupal/module_name
# After updating, run database updates
drush updatedb -y
drush cache:rebuild

Deploying Updates to Klutch.sh

  1. Commit your updated composer.json and composer.lock files
  2. Push to GitHub
  3. Klutch.sh will automatically rebuild and redeploy your application
  4. After deployment, run database updates via the UI: /update.php or using Drush

Production Best Practices

Security Recommendations

  • Strong Passwords: Use complex passwords for all user accounts, especially the administrator account
  • Two-Factor Authentication: Install and enable the TFA module for admin accounts
  • Regular Updates: Keep Drupal core and contributed modules up to date with security patches
  • File Permissions: Ensure proper file permissions (files directories should be writable, others read-only)
  • Disable Development Modules: Remove or disable development modules in production (Devel, Field UI, Views UI)
  • HTTPS Only: Klutch.sh provides HTTPS by default; ensure it’s enforced
  • Environment Variables: Store all credentials and API keys as environment variables
  • Trusted Host Patterns: Configure trusted host patterns in settings.php to prevent HTTP host header attacks
  • Security Modules: Install security-focused modules like Security Kit, Shield, and Security Review

Performance Optimization

  • Caching: Enable Drupal’s internal page cache and dynamic page cache
    • Visit Administration > Configuration > Development > Performance (/admin/config/development/performance)
    • Enable “Cache pages for anonymous users”
    • Enable “Aggregate CSS files” and “Aggregate JavaScript files”
  • OpCache: Already configured in our Dockerfile for PHP opcode caching
  • Redis or Memcached: For high-traffic sites, integrate Redis for caching:
    Terminal window
    composer require drupal/redis
  • CDN: Use a CDN for static assets (images, CSS, JS)
  • Image Optimization: Install and configure the ImageAPI Optimize module
  • Lazy Loading: Enable lazy loading for images
  • Database Query Optimization: Use Views caching and query optimization
  • Twig Template Caching: Enabled by default in production mode

Content Strategy

  • Content Types: Design clear, structured content types before building
  • Taxonomies: Use vocabularies and terms for content organization
  • Media Management: Use the Media module for centralized media management
  • Revisions: Enable content revisions for important content types
  • Workflows: Use Content Moderation module for editorial workflows
  • SEO: Install Pathauto, Metatag, and XML Sitemap modules for SEO optimization

Backup Strategy

Implement a comprehensive backup strategy:

Database Backups:

Terminal window
# Export database using Drush
drush sql:dump > backup-$(date +%Y%m%d).sql
# Or use mysqldump directly
mysqldump -h mysql-app.klutch.sh -P 8000 -u drupal_user -p drupal_db > backup.sql

File Backups:

  • Regularly back up the /var/www/html/sites/default/files directory
  • Consider automated backups to cloud storage (S3, Google Cloud Storage)
  • Include custom modules and themes in version control

Configuration Management:

  • Use Drupal’s Configuration Management to export configuration
  • Store configuration in version control
Terminal window
drush config:export

Consider:

  • Daily automated database backups
  • Weekly file system backups
  • Multiple backup retention periods (daily for 7 days, weekly for 4 weeks, monthly for 12 months)
  • Offsite backup storage
  • Regular restore testing to verify backup integrity

Monitoring

Monitor your Drupal site for:

  • Uptime: Ensure your site is accessible 24/7
  • Response Time: Track page load times and API response times
  • Error Logs: Monitor Drupal’s watchdog logs for errors and warnings
    • Access at Administration > Reports > Recent log messages (/admin/reports/dblog)
  • Disk Usage: Monitor the persistent volume to ensure adequate space
  • PHP Errors: Check PHP error logs for issues
  • Traffic Patterns: Analyze visitor traffic and peak usage times
  • Database Performance: Monitor slow queries and database connection counts
  • Security: Regular security reviews and vulnerability scans
  • Module Updates: Track available updates for modules and themes

Troubleshooting

Cannot Access Drupal Site

  • Verify that your app is running in the Klutch.sh dashboard
  • Check that the internal port is set to 80 (Apache’s default port)
  • Ensure HTTP traffic is selected
  • Wait a few minutes after deployment for DNS propagation
  • Check logs in the Klutch.sh dashboard for errors

Database Connection Errors

  • Verify all database environment variables are set correctly
  • Ensure DRUPAL_DB_HOST points to your database app URL
  • Confirm DRUPAL_DB_PORT is set to 8000
  • Test database connectivity from your local machine using the connection string
  • Check that the database is running and accessible
  • Verify username and password are correct

Files Not Persisting

  • Verify that the persistent volume is correctly attached at /var/www/html/sites/default/files
  • Check that the volume has sufficient space allocated
  • Ensure file permissions are correct (www-data should own the files directory)
  • Test by uploading a file, redeploying, and checking if the file still exists

Performance Issues

  • Enable Drupal’s caching mechanisms in the Performance settings
  • Check if CSS and JavaScript aggregation is enabled
  • Review slow query logs in the database
  • Consider adding Redis for caching
  • Monitor PHP memory usage and increase if needed
  • Optimize images and use lazy loading
  • Review and optimize custom module code
  • Consider increasing compute resources (CPU/memory) in Klutch.sh

White Screen of Death (WSOD)

  • Check PHP error logs for fatal errors
  • Verify memory_limit is sufficient (256M minimum)
  • Enable error reporting temporarily:
    error_reporting(E_ALL);
    ini_set('display_errors', TRUE);
  • Clear Drupal cache: drush cache:rebuild
  • Check for PHP syntax errors in custom code
  • Verify all required PHP extensions are installed

Permissions Errors

  • Ensure www-data owns the files directory:
    Terminal window
    chown -R www-data:www-data /var/www/html/sites/default/files
  • Set proper permissions:
    Terminal window
    chmod 755 /var/www/html/sites/default/files
  • Verify settings.php is not writable:
    Terminal window
    chmod 444 /var/www/html/sites/default/settings.php

Out of Disk Space

  • Check persistent volume usage in the Klutch.sh dashboard
  • Increase volume size if needed
  • Clean up old files and unused media
  • Remove old database backups stored on the volume
  • Optimize and clean up the database:
    Terminal window
    drush cache:rebuild
    drush watchdog:delete all

Advanced Configuration

Multisite Setup

Drupal supports running multiple sites from a single codebase. To set up multisite:

  1. Create separate directories in /var/www/html/sites/ for each site
  2. Configure each site’s settings.php
  3. Add separate persistent volumes for each site’s files
  4. Set up separate databases for each site
  5. Configure DNS to point different domains to your Klutch.sh app

Drush Integration

Drush is the Drupal shell for command-line operations. Add to your Dockerfile:

# Install Drush globally
RUN composer global require drush/drush
ENV PATH="${PATH}:/root/.composer/vendor/bin"

Useful Drush commands:

Terminal window
drush status # Show site status
drush cache:rebuild # Clear all caches
drush updatedb # Run database updates
drush config:export # Export configuration
drush config:import # Import configuration
drush user:login # Generate one-time login link

Custom Theme Development

To add a custom theme:

  1. Create your theme in themes/custom/mytheme
  2. Update your Dockerfile to copy it:
    COPY ./themes/custom /var/www/html/themes/custom
  3. Install and enable the theme:
    Terminal window
    drush theme:enable mytheme
    drush config:set system.theme default mytheme -y

Custom Module Development

To add custom modules:

  1. Create your module in modules/custom/mymodule
  2. Update your Dockerfile to copy it:
    COPY ./modules/custom /var/www/html/modules/custom
  3. Enable the module:
    Terminal window
    drush en mymodule -y

Headless/Decoupled Drupal

To use Drupal as a headless CMS:

  1. Install JSON:API or RESTful Web Services modules:
    Terminal window
    composer require drupal/jsonapi_extras
    drush en jsonapi jsonapi_extras -y
  2. Configure CORS settings in services.yml if needed
  3. Set up OAuth2 or JWT authentication for API access
  4. Access your content via API endpoints:
    • JSON:API: https://example-app.klutch.sh/jsonapi
    • REST: https://example-app.klutch.sh/rest

Additional Resources


Conclusion

Deploying Drupal to Klutch.sh with Docker provides a powerful, flexible content management platform with persistent storage and production-ready configuration. By following this guide, you’ve set up a Drupal site that’s secure, performant, and ready to power your content-driven applications with enterprise-grade content management capabilities.

Whether you’re building a simple blog, a complex corporate website, or a headless CMS for a modern application, Drupal on Klutch.sh gives you the flexibility and scalability you need to succeed.