Introduction
Grav is an open-source flat-file CMS written in PHP. This guide will show you how to install Grav on a fresh Debian 11 Rcs instance with an Nginx/PHP-FPM web server and secure it with a Let's Encrypt TLS certificate. Grav CMS does not require a database like MySQL or MariaDB
You'll use a standard, non-root user for Grav CMS to create the Markdown content.
Prerequisites
- A fresh Debian 11 Rcs instance
- This guide was tested on a 2048 MB High Frequency, 1 vCPU instance.
- A domain name pointing to your server IP addresses
- A non-root user
- Be familiar with using the Linux command line
- Know how to use vi, nano, or another text editor
In this guide, the domain name is example.com
and www.example.com
. The non-root user name is johndoe
. Replace these names with your actual domain and user names.
Verify that your domain name is accessible from a different server.
$ ping -c1 example.com
PING example.com (192.0.2.123): 56 data bytes
64 bytes from 192.0.2.123: icmp_seq=0 ttl=57 time=5.163 ms
$ ping -c1 www.example.com
PING www.example.com (192.0.2.123) 56(84) bytes of data.
64 bytes from 192.0.2.123 (192.0.2.123): icmp_seq=1 ttl=58 time=11.1 ms
If you have configured IPv6 for your domain, verify that the server also accessible over IPv6.
$ ping -6 -c1 example.com
PING example.com(2001:0db8:220:1:248:1893:25c8:1946 (2001:0db8:220:1:248:1893:25c8:1946)) 56 data bytes
64 bytes from 2001:0db8:220:1:248:1893:25c8:1946 (2001:0db8:220:1:248:1893:25c8:1946): icmp_seq=1 ttl=58 time=9.92 ms
$ ping -6 -c1 www.example.com
PING www.example.com(2001:0db8:220:1:248:1893:25c8:1946 (2001:0db8:220:1:248:1893:25c8:1946)) 56 data bytes
64 bytes from 2001:0db8:220:1:248:1893:25c8:1946 (2001:0db8:220:1:248:1893:25c8:1946): icmp_seq=1 ttl=58 time=10.2 ms
Before You Begin
Login as root and verify your Debian version.
# lsb_release -ds
Debian GNU/Linux 11 (bullseye)
Ensure that your system is up to date.
# apt update && apt upgrade
Install required and useful packages.
# apt install unzip pwgen
Use pwgen to generate a secure password.
# pwgen -s 20 1
cYmm0DZKNiuooOLxuWf4
Create a non-root user account with sudo access. Use the password you created in the previous step.
# adduser johndoe --gecos "John Doe"
# usermod -aG sudo johndoe
Switch to the new user account.
# su - johndoe
johndoe@server:~$
Note: If desired, you can generate and install an SSH Key, then SSH into the server as johndoe without a password. For the rest of this guide, make sure you are logged in as your non-root user.
If you want to change the timezone from UTC, use this command to reconfigure your timezone.
$ sudo dpkg-reconfigure tzdata
Verify that the UFW firewall is active.
$ sudo ufw status
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
Note: UFW should already be active on a new Rcs Debian 11 instance. If you are using Firewalld as a replacement for UFW, then you use firewall-cmd
to manage your firewall instead, as shown:
$ sudo firewall-cmd --state
[sudo] password for george:
running
1. Install Nginx and Required Extensions
Install the Nginx web server and the required PHP extensions for a Grav CMS installation:
$ sudo apt install nginx php-fpm php-cli php-apcu php-curl php-gd php-mbstring php-xml php-yaml php-zip
Verify the Nginx and PHP installation.
$ sudo nginx -v
nginx version: nginx/1.18.0
$ sudo php -v
PHP 7.4.25 (cli) (built: Oct 23 2021 21:53:50) ( NTS )
2. Open the Nginx Ports
If you use UFW, then use the ufw
command to open the HTTP & HTTPS ports.
$ sudo ufw allow 'Nginx Full'
Or, if you are using Firewalld, then use firewall-cmd
to open the ports.
$ sudo firewall-cmd --permanent --zone=public --add-service={http,https}
success
$ sudo firewall-cmd --reload
success
In your web browser, enter:
http://example.com
http://www.example.com
You should see the Welcome to Nginx! message.
If not, tail the Nginx error log, try again, and the error log file will likely point you in the right direction.
$ sudo tail -f /var/log/nginx/error.log
3. Create the PHP-FPM Configuration
Create a local PHP-FPM configuration file to update the php.ini
settings. These are useful settings for a production-grade Grav CMS installation. You may use the same file to customize other PHP configuration settings.
$ sudo nano /etc/php/7.4/fpm/conf.d/00-local.ini
Add the following:
post_max_size = 64M
upload_max_filesize = 64M
memory_limit = 256M
max_execution_time = 300
max_input_vars = 1540
cgi.fix_pathinfo=0
date.timezone = "America/Chicago"
Save and close the file.
Remove the default PHP-FPM pool configuration and create a PHP-FPM pool configuration for our johndoe user.
$ sudo rm /etc/php/7.4/fpm/pool.d/www.conf
$ sudo nano /etc/php/7.4/fpm/pool.d/johndoe.conf
Edit the file as shown.
[johndoe]
user = johndoe
group = johndoe
listen = /var/run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
chdir = /
Save and close the file.
Create a PHP test file for the johndoe user.
$ mkdir -p ~/www/example.com/html
$ nano ~/www/example.com/html/info.php
Paste the following:
<?php
phpinfo()
?>
Save and close the file.
4. Create the Nginx Site Configuration
Create a new site configuration. Replace example.com
with your domain name.
$ sudo nano /etc/nginx/sites-available/example.com.conf
Paste the following, replacing example.com with your domain name.
server {
listen 80;
server_name example.com www.example.com;
root /home/johndoe/www/example.com/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# deny all direct access for these folders
location ~* /(\.git|cache|bin|logs|backup|tests)/.*$ { return 403; }
# deny running scripts inside core system folders
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
# deny running scripts inside user folder
location ~* /user/.*\.(txt|md|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
# deny access to specific files in the root folder
location ~ /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) { return 403; }
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
}
Save and close the file.
Enable the new site and disable the default site.
$ sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled
$ sudo rm /etc/nginx/sites-enabled/default
Check for errors in the Nginx configuration.
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
5. Test the Configuration
Restart the nginx and php-fpm services.
$ sudo systemctl restart nginx php7.4-fpm
In your web browser, enter:
http://example.com/info.php
You should see the PHP information page displayed, starting with the installed PHP version.
If it is not displayed, check the nginx and php-fpm log files.
$ sudo tail -f /var/log/nginx/error.log
$ sudo tail -f /var/log/php7.4-fpm.log
6. Secure example.com with a Let's Encrypt TLS Certificate
Install the Let's Encrypt certbot package for Nginx and request a new TLS certificate.
$ sudo apt install python3-certbot-nginx
$ sudo certbot --nginx -d example.com -d www.example.com
You will answer a few questions, and then a request for a TLS certificate is made. The questions include:
- An email address for urgent renewal/security notices.
- Agreeing to the Terms of Service.
- Sharing your email address with the Electronic Frontier Foundation.
Look for the following line in the output:
Congratulations! You have successfully enabled https://example.com and https://www.example.com
Certbot also adds TSL support to your Nginx configuration and restarts the Nginx service.
To test your new TLS configuration, enter the following in your web browser:
https://example.com/info.php
https://www.example.com/info.php
Certbot automatically added a schedule to renew the certificate. You can test the renewal process with:
$ sudo certbot --dry-run renew
Look for the following at the end of the command output:
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
A system timer runs twice a day to request a certificate renewal. You can verify that the certbot timer is running by doing:
$ systemctl list-timers | egrep 'NEXT|certbot'
NEXT LEFT LAST PASSED UNIT ACTIVATES
Thu 2021-12-09 02:29:37 CST 13h left Wed 2021-12-08 12:32:29 CST 45min ago certbot.timer certbot.service
7. Install Grav CMS with the Admin Plugin
We are now ready to install the Grav CMS. First, we will install the version that includes the Administration Panel. Do the following:
$ cd ~/www/example.com
$ wget -O grav-admin.zip https://getgrav.org/download/core/grav-admin/latest
$ unzip -q grav-admin.zip
$ rm -rf html
$ mv grav-admin html
In your web browser, enter:
https://example.com
You will automatically be redirected to https://example.com/admin
the first time you access your site domain address. Next, you need to create your first user for the Admin account.
- Enter an Admin user name, email address, password, full name, and title.
- Click
Create User
. You will be logged into your Grav Administration Panel. - Look around, then log out.
- Access your site domain again. You should see "installation successful...".
- Verify that the Typography menu link works. If you see a 404 Error, follow the referenced troubleshooting guide.
You are now ready to create content. Follow the introduction steps displayed on the Say Hello to Grav! page. You can access the Admin panel at https://example.com/admin
.
More Information
You can refer to these links for more information about the Grav CMS.
- The Grav project provides a very detailed tutorial about the Grav CMS.
- Refer to the Development Blog for current Grav project news.
- Find more Grav information at the Grav CMS Community Forums.