Deployment Guide

    Deploy Grav CMS

    Grav is a modern flat-file CMS that delivers fast performance without database overhead. This guide covers deploying Grav on RamNode's reliable VPS hosting with Nginx, PHP 8.3, SSL encryption, and automated backups.

    Ubuntu 22.04/24.04
    Flat-File CMS
    ⏱️ 30-45 minutes
    1

    Introduction

    Grav is a modern, open-source flat-file CMS that stores all content in files rather than a database. This architecture provides exceptional performance, easy backups, and simple version control integration.

    Why Choose Grav?

    • No database required – content stored in Markdown files
    • Blazing fast performance with built-in caching
    • Easy backups – just copy the files
    • Powerful admin panel with live preview
    • Extensible with plugins and themes
    • Git-friendly for version control workflows
    2

    Prerequisites

    Before beginning the installation, ensure you have the following:

    RequirementDetails
    Operating SystemUbuntu 22.04 or 24.04 LTS
    Access LevelRoot or sudo access
    Domain NamePointed to your server's IP address
    MemoryMinimum 512MB RAM (1GB+ recommended)

    Update System Packages

    Update system
    sudo apt update && sudo apt upgrade -y
    3

    Install PHP 8.3

    Grav requires PHP with several extensions. We'll install PHP 8.3 from the Ondřej PPA for the latest stable version:

    Add PHP repository
    sudo add-apt-repository ppa:ondrej/php -y
    sudo apt update

    Install PHP 8.3 with all required extensions:

    Install PHP and extensions
    sudo apt install -y php8.3 php8.3-fpm php8.3-cli php8.3-gd php8.3-curl \
      php8.3-mbstring php8.3-xml php8.3-zip php8.3-opcache php8.3-apcu \
      php8.3-intl php8.3-yaml

    Verify the installation:

    Verify PHP
    php -v
    4

    Configure PHP for Optimal Performance

    Edit the PHP-FPM configuration to optimize for Grav:

    Edit PHP config
    sudo nano /etc/php/8.3/fpm/php.ini

    Locate and modify these settings:

    php.ini settings
    memory_limit = 256M
    upload_max_filesize = 64M
    post_max_size = 64M
    max_execution_time = 300
    max_input_vars = 3000
    date.timezone = America/Chicago

    Restart PHP-FPM to apply changes:

    Restart PHP-FPM
    sudo systemctl restart php8.3-fpm
    5

    Install and Configure Nginx

    Install Nginx:

    Install Nginx
    sudo apt install -y nginx

    Create a new server block configuration for your Grav site:

    Create config
    sudo nano /etc/nginx/sites-available/grav

    Add the following configuration (replace yourdomain.com with your actual domain):

    /etc/nginx/sites-available/grav
    server {
        listen 80;
        listen [::]:80;
    
        server_name yourdomain.com www.yourdomain.com;
        root /var/www/grav;
    
        index index.php index.html;
    
        # Grav-specific location rules
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }
    
        # Deny access to specific directories and files
        location ~* /(.git|cache|bin|logs|backup|tests)/.*$ { return 403; }
        location ~* /(system|vendor)/.*\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
        location ~* /user/.*\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
        location ~ /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) { return 403; }
    
        # PHP handling
        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
            fastcgi_read_timeout 300;
        }
    
        # Static file caching
        location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|eot)$ {
            expires 30d;
            add_header Cache-Control "public, immutable";
            access_log off;
        }
    
        # Deny access to hidden files
        location ~ /\. {
            deny all;
            access_log off;
            log_not_found off;
        }
    }

    Enable the site and test the configuration:

    Enable site
    sudo ln -s /etc/nginx/sites-available/grav /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl restart nginx
    6

    Download and Install Grav

    Create the web directory and download the latest Grav release with Admin panel:

    Download Grav
    cd /var/www
    sudo wget https://getgrav.org/download/core/grav-admin/latest -O grav-admin.zip
    sudo unzip grav-admin.zip
    sudo mv grav-admin grav
    sudo rm grav-admin.zip

    Set the correct ownership and permissions:

    Set permissions
    sudo chown -R www-data:www-data /var/www/grav
    sudo find /var/www/grav -type f -exec chmod 644 {} \;
    sudo find /var/www/grav -type d -exec chmod 755 {} \;
    sudo chmod -R 775 /var/www/grav/cache
    sudo chmod -R 775 /var/www/grav/logs
    sudo chmod -R 775 /var/www/grav/images
    sudo chmod -R 775 /var/www/grav/assets
    sudo chmod -R 775 /var/www/grav/user
    sudo chmod -R 775 /var/www/grav/backup
    7

    Secure with SSL Certificate

    Install Certbot for free Let's Encrypt SSL certificates:

    Install Certbot
    sudo apt install -y certbot python3-certbot-nginx

    Obtain and install the certificate:

    Get SSL certificate
    sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

    Follow the prompts to complete the certificate installation. Certbot will automatically configure Nginx to redirect HTTP to HTTPS.

    Verify automatic renewal is configured:

    Test renewal
    sudo certbot renew --dry-run
    8

    Configure the Firewall

    Enable and configure UFW to allow web traffic:

    Configure UFW
    sudo ufw allow OpenSSH
    sudo ufw allow 'Nginx Full'
    sudo ufw enable
    sudo ufw status
    9

    Complete Grav Setup

    Navigate to your domain in a web browser. You'll be greeted by the Grav Admin setup wizard. Create your admin account with a strong password.

    After logging in, configure your site:

    1. Go to Configuration → Site to set your site title, description, and metadata
    2. Navigate to Configuration → System to configure caching and performance options
    3. Visit Plugins to explore and install additional functionality
    4. Check Themes to customize your site's appearance
    10

    Performance Optimization

    Enable Grav's built-in caching by editing the system configuration:

    Edit system config
    sudo nano /var/www/grav/user/config/system.yaml

    Add or modify these settings:

    system.yaml
    cache:
      enabled: true
      check:
        method: file
      driver: auto
      prefix: 'g'
      purge_at: '0 4 * * *'
      clear_at: '0 3 * * *'
      clear_job_type: 'standard'
      clear_images_by_default: false
      cli_compatibility: false
      lifetime: 604800
      gzip: true
      allow_webserver_gzip: true
    
    twig:
      cache: true
      debug: false
      auto_reload: true
      autoescape: true
    
    assets:
      css_pipeline: true
      css_minify: true
      js_pipeline: true
      js_minify: true
    11

    Set Up Automated Backups

    Create a backup script:

    Create backup script
    sudo nano /usr/local/bin/grav-backup.sh

    Add the following content:

    grav-backup.sh
    #!/bin/bash
    BACKUP_DIR="/var/backups/grav"
    GRAV_DIR="/var/www/grav"
    DATE=$(date +%Y%m%d_%H%M%S)
    RETENTION_DAYS=14
    
    # Create backup directory if it doesn't exist
    mkdir -p $BACKUP_DIR
    
    # Create compressed backup
    tar -czf $BACKUP_DIR/grav_backup_$DATE.tar.gz -C $GRAV_DIR .
    
    # Remove backups older than retention period
    find $BACKUP_DIR -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
    
    echo "Backup completed: grav_backup_$DATE.tar.gz"

    Make the script executable and schedule it with cron:

    Schedule backup
    sudo chmod +x /usr/local/bin/grav-backup.sh
    sudo crontab -e

    Add this line to run daily backups at 2 AM:

    Cron entry
    0 2 * * * /usr/local/bin/grav-backup.sh >> /var/log/grav-backup.log 2>&1

    Configure Log Rotation

    Create logrotate config
    sudo nano /etc/logrotate.d/grav
    /etc/logrotate.d/grav
    /var/www/grav/logs/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 644 www-data www-data
    }

    Maintenance Commands

    Grav includes a powerful CLI tool for maintenance tasks. Here are essential commands:

    Grav CLI commands
    # Update Grav core
    cd /var/www/grav
    sudo -u www-data bin/gpm self-upgrade
    
    # Update all plugins and themes
    sudo -u www-data bin/gpm update
    
    # Clear cache
    sudo -u www-data bin/grav cache
    
    # Check system requirements
    sudo -u www-data bin/grav sandbox
    
    # Create a new user
    sudo -u www-data bin/plugin login new-user
    
    # Backup from CLI
    sudo -u www-data bin/grav backup

    Troubleshooting

    🎉 Congratulations!

    Your Grav CMS installation is now running on your RamNode VPS with optimized performance settings, SSL security, and automated backups. The flat-file architecture means you'll enjoy fast page loads and simple maintenance without database overhead.

    For further customization, explore the official Grav documentation and browse the plugin directory for additional functionality like SEO optimization, sitemaps, and contact forms.