Skip to main content
CiviCRM is a popular open source CRM that integrates with a number of Content Management Systems including Drupal, Wordpress, and Joomla, or can be installed standalone. This guide describes how to set up and install CiviCRM on Drupal 11 using Upsun’s infrastructure.

What this guide covers

This article shows how to:
• Install CiviCRM on Drupal 11 using a ready-to-use composer template
• Deploy the project on Upsun with a production-ready configuration
• Apply best practices developed from running CiviCRM sites in production over many years
By the end, you’ll have a working CiviCRM installation running on Upsun in just a few minutes.

Why CiviCRM + Drupal on Upsun

After working with CiviCRM and Drupal across many different hosting setups, I’ve found Upsun to be a particularly strong fit for running CiviCRM in production.

About the CiviCRM Drupal template

You can view the template here. This template is derived from an Upsun Drupal 11 starting template, and if you’ve installed Drupal on Upsun before, then you will have no problem getting started. If you are new to Upsun, visit the documentation. There is an upsun config.yaml included in this template, which expands on the default with best practices and additions particular to CiviCRM. You can clone this repository, add the git remote to your Upsun project code repository, push, and it will deploy and create the environment automatically.

Before you begin

You must update 3 environment variables in the Upsun Variables UI before installation of CiviCRM. The variables are: CIVICRM_SITE_KEY, CIVICRM_CRED_KEY and CIVICRM_SIGN_KEY. Refer to the CiviCRM documentation for how to generate unique keys for your installation.

Installing Drupal and enabling CiviCRM

Go to your project’s domain, and install Drupal per normal. Proper Drupal settings files are already in place, so it will install into the database setup by Upsun that is defined in the config.yml automatically. Once Drupal is installed, visit the “Extend” page at /admin/modules to install modules. Find “CiviCRM”, check the box, and click the “Install” button. A proper civicrm.settings.php is already included in this template, and everything will work automatically.
Once CiviCRM is installed, install the CiviCRM Drush module. The provided Upsun config.yml executes drush commands provided by this module to execute CiviCRM scheduled jobs and send mailings. Create an ‘Administrator’ user with the username “Cron User” that will be used when the drush command is executed.
A submodule, “CiviCRM Theme” installs automatically with CiviCRM. This allows setting which Drupal theme is used for CiviCRM administration pages. Visit /admin/appearance and try using Claro for good results.

That’s it!

CiviCRM is now installed on a high quality infrastructure, with a professional configuration in less than 5 minutes. Upsun with this template is literally that easy. You can visit it at /civicrm and see the CiviCRM menu. Feel free to install the other CiviCRM integration modules to make the most out of your installation. Note that at the time of this writing there are two patches installed by composer for CiviCRM in this template. Those will be removed in the near future when they are merged. For years CiviCRM would not allow installation with a pre-existing civicrm.settings.php in the codebase, and these patches remove that condition. The code base file system is read-only on Upsun, so it is not possible for the installation to create this file. Not to worry, this file provided has everything you need.

Upsun configuration details for CiviCRM

If you’re interested in details of the Upsun config.yml specifically for CiviCRM and additional features, keep reading!! I’ll describe this and teach how to add CiviCRM extensions with Skvare’s CiviCRM extension composer plugin.

Databases

CiviCRM can be installed into the same database as Drupal, or its own separate database. We install CiviCRM into its own database to keep the data from the applications separate. All features of CiviCRM and the Drupal integration modules work the same both ways.
We’re using the latest version of Maria DB, 11.8
The database service is defined as below:
services:  
  db:
    type: mariadb:11.8
    configuration:
      properties:        
        max_allowed_packet: 64
        max_heap_table_size: 32
        table_definition_cache: 2000
        table_open_cache: 2000
        default_charset: utf8mb4
        default_collation: utf8mb4_unicode_ci
        innodb_adaptive_hash_index: 0
        optimizer_use_condition_selectivity: 4
      schemas:
        - main
        - civicrm
      endpoints:        
        mysql:
          default_schema: main
          privileges:
            main: admin
            civicrm: admin
        civicrm:
          default_schema: civicrm
          privileges:
            main: admin
            civicrm: admin
This configures a database “mysql” for Drupal, and one “civicrm” for CiviCRM. We set the some sane database defaults, including the charset and collation to industry standard. Then the relationships for the application to the database defined as:
    relationships:
        database: 'db:mysql'
        civicrm: 'db:civicrm'

Nginx / PHP

We like a little more sophisticated configuration for PHP than default examples have. Upsun has the capability of using Composable Images. This allows installation of over 80K different software NixOS packages and initial setup this way gives maximum future potential.
applications:
  drupal:
    type: 'composable:25.05'
    stack:
      - php@8.3:
          extensions:
            - opcache
            - redis
            - sodium
            - apcu
            - blackfire
            - imagick
      - gnupg
      - patch
      - duplicity
      - python3
      - upsun
      - python3Packages.numpy
      - python3Packages.boto3
      - php83Extensions.mbstring
      - php83Extensions.iconv
      - php83Extensions.redis
      - php83Extensions.opcache
      - php83Extensions.sodium
      - php83Extensions.apcu
      - php83Extensions.blackfire
      - php83Extensions.imagick
Doing this we must specify the composer installation command during the build phase of a deployment.
    hooks:
        # The build hook runs after Composer to finish preparing up your code.
        # No services are available but the disk is writeable.
        build: |
            set -e
            #Run Composer install
            composer install --no-dev --prefer-dist --no-progress --no-interaction
Nginx configuration is standard per Drupal except we’ve added a couple of items specifically for CiviCRM.
Certain directories are blocked from direct web access
'^/sites/default/files/civicrm/(ConfigAndLog|upload|templates_c|custom)':
  allow: false
We allow access to the CiviCRM extensions directory. The popular extension CiviCRM mosaico requires web access to some html templates for its default templates. You can remove this snippet if you do not plan on using Mosaico
        locations:
            # All requests not otherwise specified follow these rules.
            # Allow Mosaico HTML templates to be loaded.
            '/sites/default/civicrm/extensions':
                root: 'web/sites/default/civicrm/extensions'
                allow: true
                scripts: false
                expires: 15m
                passthru: false

Template cache file mounts

Both Drupal and CiviCRM have separate directories where compile PHP template file caches are stored. By default the locations of these directories are inside the standard public files directory at ./web/sites/default/files/php and ./web/sites/default/files/civicrm/templates_c It is better to not have any PHP files whatsoever in the public files directory, so we change the locations of these directories to ./web/sites/default/php and ./web/sites/default/civicrm/templates_c In the Upsun config.yml we configure 2 separate public file mounts for these locations
        '/web/sites/default/civicrm/templates_c':
            source: instance
            source_path: 'templates_c'
        # Drupal php cache
        '/web/sites/default/php':
            source: instance
            source_path: 'php'
We’ve configured the Drupal settings file and the CiviCRM settings file to make the application use them.

Cron

As mentioned previously, installing the CiviCRM Drush module is required for this configuration.
CiviCRM Drush provides a number of drush commands, including commands to execute CiviCRM API calls from the command line.
The CiviCRM Drush module requires a Drupal user with necessary permissions for the various actions performed by the commands.
Create a new Drupal user with username “Cron User”. Give this user “Administrator” role.
In the config.yaml we define 3 cron jobs, one to execute all CiviCRM scheduled jobs, executing every 30 minutes.
    crons:
      # Run Drupal's cron tasks.
      job_execute:
        spec: '*/30 * * * *'
        commands:
          start: |
                cd web
                drush --name='Cron User' civicrm:api job.execute auth=0 --yes
The next executes the Send Mailings scheduled job every 5 minutes. In this way we maximize the efficiency of sending large mailings. CiviCRM supports simultaneous mailing jobs.
      job_process_mailing:
        spec: '*/5 * * * *'
        commands:
          start: |
                cd web
                drush --name='Cron User' civicrm:api job.process_mailing auth=0 --yes
Finally the standard Drupal cron command, configured here to run hourly
      drupal_cron:
        spec: '0 */1 * * *'
        commands:
          start: |
                cd web
                drush cron --yes

Environment Variables

The Drupal and CiviCRM settings files are configured to support some environmental variables that can be set per project or per environment in Upsun.
In the initial instructions above I specified CIVICRM_SITE_KEY, CIVICRM_CRED_KEY and CIVICRM_SIGN_KEY.

CiviCRM Caching

This template configured Redis as a caching mechanism. To enable CivICRM’s use of Redis, set CIVICRM_CACHING_TYPE with a value of “Redis”. This can be done either in the provided Upsun config.yml or through Upsun’s project or environment variables web pages.

Adding CiviCRM Extensions

The CiviCRM extension ecosystem does not always support fetching CiviCRM extensions with normal composer require statements. We have developed a composer plugin to help manage extensions by being able to fetch them via .zip file download.
See composer.json for examples as we have bundled common extension in this template.
 "uk.co.vedaconsulting.mosaico": {
     "url": "https://download.civicrm.org/extension/uk.co.vedaconsulting.mosaico/3.8.1752072010/uk.co.vedaconsulting.mosaico-3.8.1752072010.zip"
                },
See the README for full instructions and options. Author experience and approach As CTO at Skvare I’ve been developing Drupal and CiviCRM websites for over 13 years. Over this time I’ve used a wide range of hosting infrastructures, including platforms we’ve maintained ourselves. I’ve found Upsun to be a high-quality, easy-to-use option that is fully compatible with CiviCRM. In this article, I share my experience and a composer template that captures those learnings and best practices, allowing anyone to set up a CiviCRM site in just a few minutes. As a developer I’ve helped maintain the Drupal integration for CiviCRM Core over the years, including the updates for Drupal 10 and 11. Skvare maintain several other Drupal modules including CiviCRM Entity, CiviCRM Form Builder Blocks, CiviCRM Drush, and CiviCRM Reroute Mail, as well as the CiviCRM Extension Plugin. All of these modules and more are included in this template.

Need help?

Need help getting setup with CiviCRM Upsun infrastructure? Contact us now.
Last modified on April 27, 2026