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:
mkdir drupal-klutchcd drupal-klutchgit initStep 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 DrupalRUN 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 DrupalRUN { \ 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 directoryWORKDIR /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 permissionsRUN chown -R www-data:www-data /var/www/html
# Expose port 80EXPOSE 80Note: 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 productionif (!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 reportingif (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:
# Build and start the containersdocker-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 logsdocker-compose logs -f drupal
# Stop and remove containers when done testingdocker-compose downStep 6: Create .dockerignore File
Create a .dockerignore file to exclude unnecessary files from your Docker build:
.git.gitignoredocker-compose.ymlREADME.md.env.env.localnode_modulessites/default/files/*sites/simpletestStep 7: Push to GitHub
Commit your Dockerfile and configuration files to your GitHub repository:
git add Dockerfile settings.local.php .dockerignoregit commit -m "Add Drupal Dockerfile and configuration"git remote add origin https://github.com/yourusername/drupal-klutch.gitgit push -u origin mainNote: 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 usernameDRUPAL_DB_PASSWORD: Your database passwordDRUPAL_DB_DRIVER:mysqlorpgsqldepending 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
-
Log in to Klutch.sh
Navigate to klutch.sh/app and sign in to your account.
-
Create a New Project
Go to Create Project and give your project a meaningful name (e.g., “Drupal Website”).
-
Create a New App
Navigate to Create App and configure the following settings:
-
Select Your Repository
- Choose GitHub as your Git source
- Select the repository containing your Dockerfile
- Choose the branch you want to deploy (usually
mainormaster)
-
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)
-
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:8000DRUPAL_DB_NAME: Your database name (e.g.,drupal)DRUPAL_DB_USER: Your database usernameDRUPAL_DB_PASSWORD: Your database password (use a strong password)DRUPAL_DB_DRIVER:mysqlorpgsql
Drupal Configuration:
DRUPAL_HASH_SALT: A random string for security (generate usingopenssl 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.
-
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.
-
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)
-
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
-
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
- Navigate to Administration > Configuration > Media > File system (
/admin/config/media/file-system) - 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)
- Public file system path:
- Ensure the directories are writable
Set Up Cron
Drupal uses cron for maintenance tasks. Configure cron to run periodically:
- Visit Administration > Configuration > System > Cron (
/admin/config/system/cron) - Set the cron run interval (e.g., every 3 hours)
- 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:
# Connect to your container (if you have access)composer require drupal/admin_toolbarcomposer require drupal/pathautocomposer require drupal/tokencomposer require drupal/metatagcomposer require drupal/google_analytics
# Enable the modulesdrush en admin_toolbar admin_toolbar_tools pathauto token metatag google_analytics -yUpdating Drupal
To update Drupal core or modules:
Using Composer (Recommended)
# Update Drupal corecomposer update drupal/core-recommended --with-dependencies
# Update all modulescomposer update
# Update a specific modulecomposer update drupal/module_name
# After updating, run database updatesdrush updatedb -ydrush cache:rebuildDeploying Updates to Klutch.sh
- Commit your updated
composer.jsonandcomposer.lockfiles - Push to GitHub
- Klutch.sh will automatically rebuild and redeploy your application
- After deployment, run database updates via the UI:
/update.phpor 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”
- Visit Administration > Configuration > Development > Performance (
- 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:
# Export database using Drushdrush sql:dump > backup-$(date +%Y%m%d).sql
# Or use mysqldump directlymysqldump -h mysql-app.klutch.sh -P 8000 -u drupal_user -p drupal_db > backup.sqlFile Backups:
- Regularly back up the
/var/www/html/sites/default/filesdirectory - 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
drush config:exportConsider:
- 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)
- Access at Administration > Reports > Recent log messages (
- 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_HOSTpoints to your database app URL - Confirm
DRUPAL_DB_PORTis 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:rebuilddrush watchdog:delete all
Advanced Configuration
Multisite Setup
Drupal supports running multiple sites from a single codebase. To set up multisite:
- Create separate directories in
/var/www/html/sites/for each site - Configure each site’s
settings.php - Add separate persistent volumes for each site’s files
- Set up separate databases for each site
- 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 globallyRUN composer global require drush/drushENV PATH="${PATH}:/root/.composer/vendor/bin"Useful Drush commands:
drush status # Show site statusdrush cache:rebuild # Clear all cachesdrush updatedb # Run database updatesdrush config:export # Export configurationdrush config:import # Import configurationdrush user:login # Generate one-time login linkCustom Theme Development
To add a custom theme:
- Create your theme in
themes/custom/mytheme - Update your Dockerfile to copy it:
COPY ./themes/custom /var/www/html/themes/custom
- Install and enable the theme:
Terminal window drush theme:enable mythemedrush config:set system.theme default mytheme -y
Custom Module Development
To add custom modules:
- Create your module in
modules/custom/mymodule - Update your Dockerfile to copy it:
COPY ./modules/custom /var/www/html/modules/custom
- Enable the module:
Terminal window drush en mymodule -y
Headless/Decoupled Drupal
To use Drupal as a headless CMS:
- Install JSON:API or RESTful Web Services modules:
Terminal window composer require drupal/jsonapi_extrasdrush en jsonapi jsonapi_extras -y - Configure CORS settings in
services.ymlif needed - Set up OAuth2 or JWT authentication for API access
- Access your content via API endpoints:
- JSON:API:
https://example-app.klutch.sh/jsonapi - REST:
https://example-app.klutch.sh/rest
- JSON:API:
Additional Resources
- Klutch.sh Documentation
- Official Drupal Documentation
- Drupal Docker Image Documentation
- Klutch.sh Volumes Guide
- Drupal Composer Documentation
- Drush Documentation
- Drupal Security Best Practices
- Drupal API Documentation
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.