Technology Encyclopedia Home >How to Deploy Drupal on a Cloud Server — Enterprise CMS on Your Own VPS

How to Deploy Drupal on a Cloud Server — Enterprise CMS on Your Own VPS

Drupal has a reputation for being complicated, and it's not entirely undeserved — it's a more powerful and more opinionated CMS than most. But for certain use cases, especially structured content with complex relationships, it's genuinely the right tool. Universities, government agencies, and large content platforms use it because of that flexibility, not despite the learning curve.

I've deployed Drupal for a few client projects where the content structure was too complex for WordPress. The deployment process is predictable once you know the quirks — primarily around file permissions and the trusted host patterns configuration.

This guide deploys Drupal 10 on Ubuntu 22.04 with Nginx, PHP 8.2, and MySQL, including the permission setup and configuration that most guides gloss over.

I run this on Tencent Cloud Lighthouse with the 2 vCPU / 4 GB RAM plan. Drupal with Nginx and PHP-FPM is efficient and handles a production site comfortably at this spec. The snapshot feature is worth using before Drupal module updates — Drupal's update process can occasionally break things, and having a full server snapshot means you can restore in under 5 minutes if a module update causes problems. Lighthouse's clean Ubuntu images also mean you can test a Drupal deployment on a fresh instance and know it's not inheriting any environment-specific issues.


Table of Contents

  1. Why Use Drupal?
  2. Prerequisites
  3. Part 1 — Server Setup (LEMP Stack)
  4. Part 2 — Install Composer
  5. Part 3 — Create Database and User
  6. Part 4 — Download and Install Drupal
  7. Part 5 — Configure Nginx
  8. Part 6 — Run the Drupal Installer
  9. Part 7 — Enable HTTPS
  10. Part 8 — Post-Installation Configuration
  11. The Gotcha: File Permissions
  12. Common Drupal Commands (Drush)

  • Key Takeaways
  • Use the appropriate Lighthouse application image to skip manual installation steps where available
  • Lighthouse snapshots provide one-click full-server backup before major changes
  • OrcaTerm browser terminal lets you manage the server from any device
  • CBS cloud disk expansion handles growing storage needs without server migration
  • Console-level firewall + UFW = two independent protection layers

Why Use Drupal? {#why}

Drupal excels when you need:

  • Complex content types with custom fields (structured content)
  • Fine-grained permissions — users, roles, and access control
  • Multilingual sites — built-in translation system
  • API-first content — headless CMS with JSON:API and GraphQL
  • Enterprise-scale content management

For a personal blog or simple website, WordPress or Ghost is simpler. Choose Drupal when the content architecture is complex.


Prerequisites {#prerequisites}

Requirement Notes
Cloud server Tencent Cloud Lighthouse Ubuntu 22.04
PHP 8.2 Drupal 10 minimum requirement
MySQL / MariaDB We'll use MySQL
Composer PHP dependency manager

Part 1 — Server Setup (LEMP Stack) {#part-1}

ssh ubuntu@YOUR_SERVER_IP
sudo apt update && sudo apt upgrade -y

# PHP repository for latest versions
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Install Nginx + PHP 8.2 + required extensions for Drupal
sudo apt install -y nginx php8.2-fpm php8.2-mysql php8.2-xml \
  php8.2-gd php8.2-curl php8.2-mbstring php8.2-zip php8.2-intl \
  php8.2-opcache php8.2-apcu

# Install MySQL
sudo apt install -y mysql-server
sudo systemctl start mysql && sudo systemctl enable mysql

sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable

Configure PHP for Drupal (edit /etc/php/8.2/fpm/php.ini):

sudo nano /etc/php/8.2/fpm/php.ini
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
date.timezone = UTC
sudo systemctl restart php8.2-fpm

Part 2 — Install Composer {#part-2}

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
composer --version

Part 3 — Create Database and User {#part-3}

sudo mysql_secure_installation   # If not already done
sudo mysql
CREATE DATABASE drupal_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'drupal_user'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT ALL PRIVILEGES ON drupal_db.* TO 'drupal_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Part 4 — Download and Install Drupal {#part-4}

cd /var/www

# Create Drupal project using Composer (recommended method)
sudo composer create-project drupal/recommended-project drupal

# Set ownership
sudo chown -R ubuntu:www-data /var/www/drupal
sudo chmod -R 755 /var/www/drupal
sudo chmod -R 775 /var/www/drupal/web/sites/default/files

The Composer method downloads Drupal core plus recommended modules and sets up a proper project structure.


Part 5 — Configure Nginx {#part-5}

sudo nano /etc/nginx/sites-available/drupal
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    root /var/www/drupal/web;
    index index.php index.html;

    access_log /var/log/nginx/drupal_access.log;
    error_log  /var/log/nginx/drupal_error.log;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Block hidden files
    location ~ \..*/.*\.php$ { return 403; }
    location ~ ^/sites/.*/private/ { return 403; }
    location ~ ^/sites/[^/]+/files/.*\.php$ { deny all; }
    location ~ (^|/)\. { return 403; }

    # Allow "Well-Known" URIs for Let's Encrypt
    location ~* ^/.well-known/ { allow all; }

    # Drupal clean URLs
    location / {
        try_files $uri /index.php?$query_string;
    }

    # PHP via PHP-FPM
    location ~ '\.php$|^/update.php' {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        include fastcgi_params;
    }

    # Static file caching
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        try_files $uri @rewrite;
        expires max;
        log_not_found off;
    }

    # Drupal image styles
    location ~ ^/sites/.*/files/styles/ {
        try_files $uri @rewrite;
    }

    location @rewrite {
        rewrite ^ /index.php;
    }
}
sudo ln -s /etc/nginx/sites-available/drupal /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Part 6 — Run the Drupal Installer {#part-6}

Visit http://yourdomain.com in your browser. The Drupal installation wizard appears:

  1. Choose language → English (or your preferred language)
  2. Select installation profile → Standard (recommended for most sites)
  3. Database configuration:
    • Database type: MySQL
    • Database name: drupal_db
    • Database username: drupal_user
    • Database password: your password
    • Host: localhost
  4. Site configuration: set site name, admin email, and admin account
  5. Click Save and continue

Installation takes 1-2 minutes.


Part 7 — Enable HTTPS {#part-7}

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

After HTTPS is configured, set the trusted host patterns in Drupal:

sudo nano /var/www/drupal/web/sites/default/settings.php

Add at the end:

$settings['trusted_host_patterns'] = [
    '^yourdomain\.com$',
    '^www\.yourdomain\.com$',
];

Part 8 — Post-Installation Configuration {#part-8}

Fix file permissions for security

Drupal recommends read-only settings file after installation:

sudo chmod 444 /var/www/drupal/web/sites/default/settings.php
sudo chmod 555 /var/www/drupal/web/sites/default

Install Drush (Drupal command-line tool)

cd /var/www/drupal
composer require drush/drush

# Add to PATH
echo 'export PATH="$PATH:/var/www/drupal/vendor/bin"' >> ~/.bashrc
source ~/.bashrc

drush status

Set up cron

# Run Drupal cron every hour
(crontab -l; echo "0 * * * * cd /var/www/drupal && vendor/bin/drush core:cron >> /var/log/drupal-cron.log 2>&1") | crontab -

Configure Redis caching (optional but recommended)

sudo apt install -y redis-server php8.2-redis
composer require drupal/redis

# Enable in Drupal admin: Extend → Redis → Install
# Configure in settings.php:
$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = '127.0.0.1';
$settings['cache']['default'] = 'cache.backend.redis';

The Gotcha: File Permissions {#gotcha}

The most common Drupal issue: incorrect file permissions causing errors when uploading images, installing modules, or writing config.

Drupal's web server (www-data) needs write access to the files directory and settings:

# During setup and development
sudo chown -R ubuntu:www-data /var/www/drupal/web/sites
sudo chmod -R 775 /var/www/drupal/web/sites/default/files
sudo chmod 664 /var/www/drupal/web/sites/default/settings.php

# After installation (tighten for security)
sudo chmod 444 /var/www/drupal/web/sites/default/settings.php
sudo chmod 555 /var/www/drupal/web/sites/default

If modules or configuration can't be written during admin operations:

# Temporarily re-enable write access
sudo chmod 644 /var/www/drupal/web/sites/default/settings.php
# Do your admin work
# Then re-tighten
sudo chmod 444 /var/www/drupal/web/sites/default/settings.php

Common Drupal Commands (Drush) {#commands}

# Status and info
drush status
drush pm-list --status=enabled     # List enabled modules

# Cache
drush cache:rebuild                # Rebuild all caches (drush cr)

# Database
drush sql:dump > backup.sql        # Backup database
drush sql:cli < backup.sql         # Import database

# Updates
drush pm:update                    # Check for module updates
drush pm:update MODULE_NAME        # Update specific module
drush updatedb                     # Run pending database updates

# Configuration
drush config:export                # Export config to files
drush config:import                # Import config from files

# User management
drush user:create USERNAME --password=PASS --mail=EMAIL
drush user:role:add administrator USERNAME

# Cron
drush core:cron                    # Run cron manually

Troubleshooting {#troubleshooting}

Issue Likely Cause Fix
Connection refused Service not running or wrong port Check systemctl status SERVICE and verify firewall rules
Permission denied Wrong file ownership or permissions Check file ownership with ls -la and use chown/chmod to fix
502 Bad Gateway Backend service not running Restart the backend service; check logs with journalctl -u SERVICE
SSL certificate error Certificate expired or domain mismatch Run sudo certbot renew and verify domain DNS points to server IP
Service not starting Config error or missing dependency Check logs with journalctl -u SERVICE -n 50 for specific error
Out of disk space Logs or data accumulation Run df -h to identify usage; clean logs or attach CBS storage
High memory usage Too many processes or memory leak Check with htop; consider upgrading instance plan if consistently high
Firewall blocking traffic Port not open in UFW or Lighthouse console Open port in Lighthouse console firewall AND sudo ufw allow PORT

Frequently Asked Questions {#faq}

Can I migrate an existing Drupal site to a cloud server?
Yes. Export your content and database from the current host, import them on the new server, then update your DNS to point to the new IP. Update any hardcoded URLs in the database or configuration files.

How do I keep Drupal updated securely?
Enable automatic minor updates where available, and manually update major versions after testing on a staging environment. Take a Lighthouse snapshot before any significant update.

Do I need a CDN for my Drupal site?
For international audiences, yes. A CDN like EdgeOne caches static assets at edge nodes worldwide, improving load times for visitors far from your server region.

What causes Drupal to be slow on a VPS?
Usually: missing caching plugin/configuration, unoptimized images, too many plugins, or insufficient server RAM. Start with a caching layer (Redis or built-in cache) and image optimization.

How do I secure the admin panel?
Change the default admin URL if possible, use a strong unique password, enable two-factor authentication, and consider restricting admin access by IP in your Nginx configuration.

Deploy Drupal today:
👉 Tencent Cloud Lighthouse — PHP-ready Ubuntu VPS
👉 View current pricing and promotions
👉 Explore all active deals and offers