Step-by-Step Guide: Deploy a Kirby CMS Website on Linode Using Nginx

Prerequisites #

Before you begin, ensure you have:

  • A Linode (Akamai) account.
  • SSH access to your terminal.
  • Basic knowledge of Linux commands.

Step 1: Create Compute Instance #

Read: workflow.

Step 2: Set Up Nginx & PHP #

Install Nginx #

Install:

bash
sudo apt install nginx -y

Start:

bash
sudo systemctl start nginx

Auto start at boot:

bash
sudo systemctl enable nginx

Verify installation:

Press Q to exit.

bash
sudo systemctl status nginx

Or visit: http://<public_ipv4>

Install PHP #

Install:

bash
sudo apt install php-fpm -y

Verify PHP installation:

bash
php -v

Check fpm.sock PHP version:

bash
ls /run/php/

Example: php8.3-fpm.sock

Verify if php-fpm service is running:

Press Q to exit.

bash
sudo systemctl status php<version>-fpm

Example version: 8.3

Configure PHP #

Create backup:

bash
sudo cp /etc/php/8.3/fpm/php.ini /etc/php/8.3/fpm/php.ini.bak

Open:

bash
sudo vim /etc/php/8.3/fpm/php.ini

Modify:

text
max_execution_time = 60
memory_limit = 256M
post_max_size = 25M
upload_max_filesize = 25M

Configure Nginx #

Create backup:

bash
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

Edit:

bash
sudo vim /etc/nginx/sites-available/default

Modify (uncomment to enable setting):

Make sure to remove the # before the last }.

text
server {
...
  # pass PHP scripts to FastCGI server
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php<version>-fpm.sock;
  }
...
}

Test config:

bash
sudo nginx -t

Restart:

bash
sudo systemctl restart nginx

Verify Installation #

Create page:

bash
sudo vim /var/www/html/test.php

Add:

/var/www/html/test.php
<?php phpinfo(); ?>

Verify: http://<public_ipv4>/test.php

Step 3: Install PHP Extensions & ImageMagick #

Install additional packages:

bash
sudo apt install imagemagick php-common php-curl php-gd php-imagick php-intl php-mbstring php-xml php-zip -y

Verify PHP modules:

bash
php -m

Or: http://<public_ip4v>/test.php

Remove page:

bash
sudo rm /var/www/html/test.php

Step 4: Install Kirby CMS Starterkit #

Create directory:

bash
sudo mkdir -p /var/www/<name>/public_html

Example name: example.com

Download Kirby CMS starterkit:

The starterkit is perfect for testing if everything works as expected.

bash
sudo git clone https://github.com/getkirby/starterkit /var/www/<domain>/public_html/

Step 5: Create Server Block Configuration #

Virtual host file.

Create:

bash
sudo vim /etc/nginx/sites-available/<name>

Example name: example.com

Add:

/etc/nginx/sites-available/<name>
server {
  listen 80;
  listen [::]:80;
  server_name <public_ip4v> or <domain> <sub.domain>;
  root /var/www/<name>/public_html;

  index index.php; # Allow specific filetypes

  rewrite ^/(content|site|kirby)/(.*)$ /error last;
  rewrite ^/\.(?!well-known/) /error last;
  rewrite ^/(?!app\.webmanifest)[^/]+$ /index.php last;

  location / {
    try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php<version>-fpm.sock; # Adjust PHP version
  }
}

Create symbolic link to enable site:

bash
sudo ln -s /etc/nginx/sites-available/<name> /etc/nginx/sites-enabled/

Test configuration:

bash
sudo nginx -t

Reload Nginx:

bash
sudo systemctl reload nginx

Step 6: Set Permissions #

Apply permissions globally to /var/www/ or individually to /var/www/<name>.

Goal: Secure and functional permissions for web content

  • Directories: 755
    • Owner (www-data): Read, write, execute.
    • Group and others: Read and execute (required for Nginx to access directory contents).
  • Files: 644
    • Owner (www-data): Read and write.
    • Group and others: Read-only (Nginx only needs to read files).

Change owner:

Default Nginx user: www-data. Verify: /etc/nginx/nginx.conf

bash
sudo chown -R www-data:www-data /var/www/<name>

Set file permissions to 644:

bash
sudo find /var/www/<name> -type f -exec chmod 644 {} \;

Set folder permissions to 755:

bash
sudo find /var/www/<name> -type d -exec chmod 755 {} \;

Verify:

bash
ll /var/www

Step 7: Test Website #

Check Headers #

200 OK means the server successfully received and processed the request. The site is up and responding normally.

bash
curl -I <public_ip4v>

Enable Panel #

Open:

bash
sudo vim /var/www/<name>/public_html/site/config/config.php

Modify:

/var/www/<name>/public_html/site/config/config.php
<?php
return [
  'panel' => [
    'install' => true
  ],
];

Create account: http://<public_ipv4>/panel

Security Checks #

Access to sensitive folders and files must be blocked.

The following URL's should redirect to the error page:

  • Content folder: http://<public_ipv4>/content/site.txt
  • Kirby folder: http://<public_ipv4>/kirby/bootstrap.php
  • Site folder: http://<public_ipv4>/site/config/config.php
  • Hidden files and folders: http://<public_ipv4>/git/config

Various Checks #

  • Do all pages load correctly?
  • Check browser developer tools (Network and Console) for errors.
  • Does the Panel work (e.g. account creation)?
  • Can you create, edit and delete content?
  • Can you view file details (images, documents, archives) in the Panel?
  • Do images load quickly?
  • Can you upload images, documents and archives via the Panel?

Step 8: Upload Website #

Install #

Wipe:

bash
sudo rm -rfv /var/www/<name>/public_html/{*,.*}

Git clone Kirby CMS plainkit:

bash
sudo git clone https://github.com/getkirby/plainkit /var/www/<name>/public_html/

Enable Panel #

Create config folder:

bash
sudo mkdir -p /var/www/<name>/public_html/site/config/

Open:

bash
sudo vim /var/www/<name>/public_html/site/config/config.php

Modify:

/var/www/<name>/public_html/site/config/config.php
<?php
return [
  'panel' => [
    'install' => true
  ],
];

Change owner and set permissions:

bash
sudo chown -R www-data:www-data /var/www/<name>
sudo find /var/www/<name> -type f -exec chmod 644 {} \;
sudo find /var/www/<name> -type d -exec chmod 755 {} \;

Create account: http://<public_ipv4>/panel

Synchronise #

Temporarily set permissions to user:

Required to allow rsync to read and write files during synchronisation.

bash
sudo chown -R <user>:<user> /var/www/<name>

Synchronise website from local to remote:

bash
rsync -avz --delete \
  --exclude='.*' \
  --exclude='/kirby' \
  --exclude='/media' \
  --exclude='/site/accounts' \
  --exclude='/site/cache' \
  --exclude='/site/sessions' \
  --exclude='_.log*' \
  <path_to_local_folder> \
  linode-<name>:/var/www/<name>/public_html/

Reset permissions to www-data:

bash
sudo chown -R www-data:www-data /var/www/<name>

Next Steps #