Installing Bolt CMS with Nginx, MySQL, PHP, and HTTPS on Ubuntu 20.04

Bolt is a free and open-source content management system that leverages the Symfony PHP framework. Designed for mid-sized websites, it caters to both content managers and developers. This tutorial outlines the steps to install Bolt on Ubuntu 20.04 using Nginx as the web server, MySQL as the database engine, and PHP. Additionally, it covers setting up HTTPS using a complimentary Let’s Encrypt TLS certificate.

System Requirements and Initial Setup

Before proceeding with the installation, ensure the following prerequisites are met:

  • Launch an Ubuntu 20.04 cloud instance.
  • Establish a non-root user account with sudo access.
  • Apply the latest system updates.
  • Adjust the Ubuntu firewall to allow traffic through ports 80 (HTTP), 443 (HTTPS), and 22 (SSH).
  • Secure a fully qualified domain name (FQDN) such as bolt.example.com and point it to your server’s IP address. This is essential for authentication to function properly.
  • Access your server using the non-root user credentials.

In all command examples, be sure to substitute bolt.example.com with your server’s actual domain name.

Step 1: Install Required System Packages for Bolt CMS

To run Bolt CMS, you need to install several essential software components:

  • A web server such as Nginx
  • A relational database like MySQL
  • PHP version 7.2.9 or newer, with at least 32MB of allocated memory
  • The following PHP extensions:
    • Required: curl, exif, fileinfo, gd, json, mysqlnd (for MySQL support), openssl, pdo, posix, xml, zip
    • Recommended (optional): intl, mbstring, opcache

Install the Nginx Web Server

Use the following command to install Nginx:

$ sudo apt -y install nginx

Set Up MySQL 8.0

Enable PHP 8.0 Using the Ondřej Surý Repository

To get access to PHP 8.0, add the ppa:ondrej/php repository, which is a long-standing and trusted community source:

$ sudo LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php

Install PHP 8.0 and Required Extensions

Next, install PHP 8.0 along with all the necessary modules:

$ sudo apt -y install php8.0-cli php8.0-curl php8.0-fpm php8.0-gd php8.0-intl php8.0-mbstring php8.0-mysql php8.0-xml php8.0-zip

Install Unzip Utility

To handle zip archives, install the unzip package using the command below:


$ sudo apt -y install unzip


Step 2: Set Up and Configure PHP for Bolt CMS

Start by selecting a time zone supported by your system. Use the navigation keys (Up, Down, PgUp, PgDn) to scroll through the list and press Q to exit:

$ timedatectl list-timezones

Choose an appropriate time zone, such as America/New_York, and configure your server accordingly:

$ sudo timedatectl set-timezone America/New_York

Edit PHP’s main configuration file to apply your time zone setting:

$ sudo nano /etc/php/8.0/fpm/php.ini

Find the line ;date.timezone =, remove the semicolon, and insert your time zone like this:

date.timezone = America/New_York

You can also tweak the following parameters if needed:

  • max_execution_time
  • memory_limit
  • post_max_size
  • upload_max_filesize

Save and close the file once your changes are complete.

Create a Dedicated User for Managing Bolt

To handle the Bolt CMS source code securely, create a new user named bolt:

Switch to this user whenever you need to modify the website’s source code.

Configure PHP-FPM for the Bolt User

Copy the default PHP-FPM pool configuration to create a custom one for Bolt:

$ sudo cp /etc/php/8.0/fpm/pool.d/www.conf /etc/php/8.0/fpm/pool.d/bolt.conf

Disable the default configuration by renaming it:

$ sudo mv /etc/php/8.0/fpm/pool.d/www.conf /etc/php/8.0/fpm/pool.d/www.conf.default

Edit the newly created Bolt PHP-FPM pool configuration:

$ sudo nano /etc/php/8.0/fpm/pool.d/bolt.conf

Make the following changes in the file:

  • Replace [www] with [bolt]
  • Change user = www-data to user = bolt
  • Change group = www-data to group = bolt (leave listen.group = www-data unchanged)
  • Ensure that listen = /run/php/php8.0-fpm.sock is not commented out

Append the following configuration block at the end of the file to manage error logging and session storage:

catch_workers_output = yes
php_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php-fpm/bolt/error.log

php_admin_value[session.save_path] = /var/lib/php/sessions/bolt

This configuration logs PHP errors to /var/log/php-fpm/bolt/error.log and saves session files under /var/lib/php/sessions/bolt.

Create Log and Session Storage Directories

Run the commands below to create the required directories:

$ sudo mkdir -p /var/log/php-fpm/bolt
$ sudo mkdir -p /var/lib/php/sessions/bolt

Set secure ownership and permissions on those directories:

$ sudo chown bolt:bolt /var/log/php-fpm/bolt
$ sudo chmod 700 /var/log/php-fpm/bolt
$ sudo chown bolt:bolt /var/lib/php/sessions/bolt
$ sudo chmod 700 /var/lib/php/sessions/bolt

Verify and Apply PHP-FPM Configuration

Validate the new PHP-FPM configuration using the following command:

Restart PHP-FPM to activate your changes:


$ sudo systemctl restart php8.0-fpm.service


Step 3: Set Up a MySQL Database for Bolt CMS

To begin, log in to the MySQL database server using the root user account:

Inside the MySQL shell, create a new database that will be used by Bolt. Replace db_name with your preferred database name:

mysql> CREATE DATABASE db_name;

Next, create a new user named db_user and assign it full privileges for the newly created database. Be sure to replace db_password with a secure password of your choice:

mysql> CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'db_password';
mysql> GRANT ALL PRIVILEGES on db_name.* to 'db_user'@'localhost';
mysql> FLUSH PRIVILEGES;

Once these steps are complete, leave the MySQL prompt:


Step 4: Set Up Bolt CMS Using Composer

The fastest and recommended approach to install Bolt is by using Composer, which manages PHP dependencies.

Install Composer

To begin, download Composer:

$ curl -sS https://getcomposer.org/installer | php

Move the downloaded Composer binary to a global path so it can be run system-wide:

$ sudo mv composer.phar /usr/local/bin/composer

Create the Bolt Project Directory

Set up the target directory for storing the Bolt source code:

$ sudo mkdir /var/www/bolt

Change the ownership of the directory to the bolt user:

$ sudo chown bolt:bolt /var/www/bolt

Download Bolt with Composer

Switch to the bolt user to proceed with the download:

Navigate to the source directory:

Install the Bolt source code and its required packages. This may take a few minutes to complete:

$ composer create-project bolt/project .

When prompted with Do you want to continue the setup now? (Y/n), press N followed by Enter to bypass SQLite configuration.

Configure Database and Environment

Create a local environment configuration file:

Insert the following content. Replace db_user, db_password, and db_name with the database credentials you set up in the previous step:

APP_ENV=prod # production environment
DATABASE_URL=mysql://db_user:"db_password"@localhost:3306/db_name

Save the file and close the editor.

Optimize Environment Configuration

Generate a compiled PHP environment file to speed up runtime performance:

Initialize and Populate the Database

Create the necessary schema in the database. If a warning appears stating this operation is not recommended in production, you can safely ignore it for now:

$ bin/console doctrine:schema:create

Load sample data into the database. When prompted, type yes and press Enter:

$ bin/console doctrine:fixtures:load

Create an Administrator Account

Set up your first admin user by running the following command. Replace the placeholders with your desired credentials:

$ bin/console bolt:add-user 'username' 'password' 'email' 'display-name' --admin

When you’re done, switch back to the sudo user so you can proceed with configuring Nginx:


Step 5: Configure Nginx for Your Bolt CMS Website

Begin by creating a new Nginx configuration file specifically for your Bolt installation:

$ sudo nano /etc/nginx/sites-available/bolt-http.conf

Paste the configuration below into the editor. Replace bolt.example.com with your actual domain name:

server {
    listen 80;
    listen [::]:80;

    server_name bolt.example.com; # your server's domain name

    ## Uncomment the following to enable logging
    # access_log /var/log/nginx/bolt.example.com.access.log;
    # error_log /var/log/nginx/bolt.example.com.error.log;

    root /var/www/bolt/public; # document root directory
    index index.php;

    # To avoid upload errors, client_max_body_size must be equal to or
    # larger than PHP post_max_size.
    client_max_body_size 16m;

    # Default prefix match fallback, as all URIs begin with /
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Bolt dashboard access
    #
    # We use two location blocks here, the first is an exact match to the dashboard
    # the next is a strict forward match for URIs under the dashboard. This in turn
    # ensures that the exact branding prefix has absolute priority, and that
    # restrictions that contain the branding string, e.g. "bolt.db", still apply.
    #
    # NOTE: If you set a custom branding path, change '/bolt/' and '/bolt/' to match
    location = /bolt {
        try_files $uri /index.php$is_args$args;
    }
    location ^~ /bolt/ {
        try_files $uri /index.php$is_args$args;
    }

    # Generated thumbnail images
    location ^~ /thumbs {
        try_files $uri /index.php;

        access_log off;
        log_not_found off;
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, mustrevalidate, proxy-revalidate";
        add_header X-Koala-Status sleeping;
    }

    # Do not log but do cache asset files
    location ~* ^.+\.(atom|bmp|bz2|css|doc|eot|exe|gif|gz|ico|jpe?g|jpeg|jpg|js|map|mid|midi|mp4|ogg|ogv|otf|png|ppt|rar|rtf|svg|svgz|tar|tgz|ttf|wav|woff|xls|zip)$ {
        access_log off;
        log_not_found off;
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, mustrevalidate, proxy-revalidate";
        add_header X-Koala-Status eating;
    }

    # Deny access to any files in the theme directory, except for the listed extensions.
    location ~ theme\/.+\.(?!(html?|css|js|jpe?g|png|gif|svg|pdf|avif|webp|mp3|mp?4a?v?|woff2?|txt|ico|zip|tgz|otf|ttf|eot|woff|woff2)$)[^\.]+?$ {
        deny all;
    }

    # Redirect requests for */index.php to the same route minus the "index.php" in the URI.
    location ~ /index.php/(.*) {
        rewrite ^/index.php/(.*) /$1 permanent;
    }

    location ~ [^/]\.php(/|$) {
        try_files /index.php =404;

        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # Mitigate https://httpoxy.org/ vulnerabilities
        fastcgi_param HTTP_PROXY "";

        # Set the HTTP parameter if not set in fastcgi_params
        fastcgi_param HTTPS $https if_not_empty;

        fastcgi_pass unix:/run/php/php8.0-fpm.sock;

        # Include the FastCGI parameters shipped with NGINX
        include fastcgi_params;
    }

    # Block access to "hidden" files
    # i.e. file names that begin with a dot "."
    # An exception is included for Let's Encrypt ssl verification
    location ~ /\.(?!well-known) {
        deny all;
    }

    # Block access to Markdown, Twig & YAML files directly
    location ~* /.+\.(markdown|md|twig|yaml|yml)$ {
        deny all;
    }
}

Save and exit the file once editing is complete.

Enable and Apply the Nginx Configuration

Create a symbolic link to enable the new Nginx site configuration:

$ sudo ln -s /etc/nginx/sites-available/bolt-http.conf /etc/nginx/sites-enabled/bolt-http.conf

Grant the www-data user access to Bolt’s group so Nginx can read from the document root:

$ sudo usermod -aG bolt www-data

Validate the updated Nginx configuration:

Reload the Nginx service to apply the changes:

$ sudo systemctl reload nginx.service

To enhance security, proceed to the next step and configure HTTPS for your Bolt installation.

Step 6 (Optional): Enable HTTPS with Let’s Encrypt for Bolt CMS

Install Certbot and Obtain a Free TLS Certificate

First, follow the “Install Certbot” instructions to set up Certbot using Snap.

Prepare Nginx for HTTPS

Rename your existing HTTP configuration to use it as a base for the HTTPS version:

$ sudo mv /etc/nginx/sites-available/bolt-http.conf /etc/nginx/sites-available/bolt-https.conf

Create a new Nginx config file that will handle plain HTTP traffic:

$ sudo nano /etc/nginx/sites-available/bolt-http.conf

Paste the following content into the file. Make sure to replace bolt.example.com with your actual domain name:

server {
    listen 80;
    listen [::]:80;

    server_name bolt.example.com; # your server's domain name

    root /var/www/bolt/public;

    location / {
        return 301 https://$server_name$request_uri;
    }

    location /.well-known/acme-challenge/ {}
}

This configuration ensures that all HTTP traffic—except for Let’s Encrypt validation requests—is redirected to HTTPS.

Apply and Test Configuration

Check the new Nginx configuration for syntax errors:

Reload the Nginx service to activate the changes:

$ sudo systemctl reload nginx.service

Request an SSL Certificate from Let’s Encrypt

Use Certbot to obtain your SSL certificate. Replace admin@bolt.example.com with your email address and bolt.example.com with your domain name:

$ sudo certbot certonly --webroot -w /var/www/bolt/public -d bolt.example.com -m admin@bolt.example.com --agree-tos --no-eff-email --non-interactive

Once the process completes, Certbot will store the certificate files under /etc/letsencrypt/archive/bolt.example.com and provide symbolic links in /etc/letsencrypt/live/bolt.example.com for easier access.

You can confirm the symbolic links were created by listing the contents of the directory:

$ sudo ls /etc/letsencrypt/live/bolt.example.com

This should output the following files:

  • cert.pem
  • chain.pem
  • fullchain.pem
  • privkey.pem
  • README

These symbolic links will be used in the next step to complete the SSL setup.

Step 7: Secure Bolt CMS with an SSL Certificate in Nginx

Generate DH Parameters for Stronger Encryption

Create a Diffie-Hellman parameter file with a recommended key length of 2048 bits. This may take a few minutes:

$ sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048

Update Nginx HTTPS Configuration

Edit your Nginx configuration file for HTTPS:

$ sudo nano /etc/nginx/sites-available/bolt-https.conf

Locate the following lines:

“`text
listen 80;
listen [::]:80;

Replace them with the following block to enable HTTPS support using strong SSL settings. Be sure to use your actual domain in place of bolt.example.com:

 listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/bolt.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/bolt.example.com/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; # about 40000 sessions # DH parameters file ssl_dhparam /etc/nginx/dhparam.pem; # intermediate configuration ssl_protocols TLSv1.2; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # HSTS (ngx_http_headers_module is required) (63072000 seconds) # # Uncomment the following line only if your website fully supports HTTPS # and you have no intention of going back to HTTP, otherwise, it will # break your site. # # add_header Strict-Transport-Security "max-age=63072000" always; # OCSP stapling ssl_stapling on; ssl_stapling_verify on; # verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /etc/letsencrypt/live/bolt.example.com/chain.pem; # Use Cloudflare DNS resolver resolver 1.1.1.1;

Save and close the file when finished editing.

Enable and Activate HTTPS Configuration

Create a symbolic link to enable the new HTTPS configuration:

 $ sudo ln -s /etc/nginx/sites-available/bolt-https.conf /etc/nginx/sites-enabled/bolt-https.conf

Test your Nginx configuration to ensure there are no errors:

Apply the new settings by reloading the Nginx service:


 $ sudo systemctl reload nginx.service


Step 8: Automate TLS Certificate Renewal for Bolt CMS

Let’s Encrypt issues certificates that are valid for 90 days. Therefore, you need to ensure that certificate renewal happens at least once every three months. Fortunately, Certbot sets up a systemd timer during installation to handle this task automatically.

Confirm That the Certbot Timer Is Active

Check if the timer is enabled and running:

$ sudo systemctl list-timers | grep 'certbot\|ACTIVATES'

Create a Hook to Reload Nginx After Renewal

Create a script in Certbot’s deploy-hook directory to make sure Nginx reloads whenever the certificate is renewed:

$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Add the following lines to the file:

#!/bin/bash

/usr/bin/systemctl reload nginx.service

Save and close the script file, then make it executable so Certbot can run it:

$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Run a Simulated Renewal Test

To make sure everything works as expected, execute a dry run of the renewal process:


$ sudo certbot renew --dry-run


Step 9: Confirm That Bolt CMS Is Working

To finalize the installation, reboot your server to ensure all services start cleanly with the latest configurations:

After the system boots back up, launch your web browser and visit the following address:

http://bolt.example.com

If everything is set up correctly, you’ll see the Bolt homepage using the default theme and sample content.

To access the administrative backend, navigate to:

http://bolt.example.com/bolt

Log in using the admin username and password you created earlier in Section 4.

Conclusion

With the steps in this guide completed, your Bolt CMS installation is now live, secure, and ready for use. You’ve successfully configured a reliable LEMP stack with Nginx, MySQL, and PHP on Ubuntu 20.04, implemented robust HTTPS encryption using Let’s Encrypt, and prepared the system for automated certificate renewal.

From installing core system packages and dependencies, to setting up the database, fine-tuning PHP, and deploying Bolt via Composer, your server is optimized for performance and security. You can now log in to the Bolt admin dashboard to begin customizing your site, publishing content, and managing your data with ease.

Should you need to expand functionality or adapt the setup for production scaling, Bolt’s flexibility and Symfony foundation provide a strong starting point for future growth.

Source: vultr.com

Create a Free Account

Register now and get access to our Cloud Services.

Posts you might be interested in: