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
- Required:
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
:
$ sudo adduser 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
touser = bolt
- Change
group = www-data
togroup = bolt
(leavelisten.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:
$ sudo php-fpm8.0 -t
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:
$ sudo mysql
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:
mysql> exit
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:
$ sudo su - bolt
Navigate to the source directory:
$ cd /var/www/bolt
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:
$ nano .env.local
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:
$ composer dump-env prod
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:
$ exit
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:
$ sudo nginx -t
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:
$ sudo nginx -t
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:
$ sudo nginx -t
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:
$ sudo reboot
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.