Post

Quick Setup of Grav CMS with Admin Plugin on NGINX

A fast and basic setup of Grav CMS with core and admin plugin on an nginx web server.

Quick Setup of Grav CMS with Admin Plugin on NGINX

Using Grav with the Admin Plugin gives you a nice lightweight CMS that works without the need of a database. This quick walkthrough shows how to setup Grav with the Admin Plugin on a Debian based system with a working nginx web server.

Configure nginx

Once you setup DNS to point to your server (not covered here), you will need to configure your web server for the domain you are using. Grav provides some basic configs for different web servers in their GitHub repo and the official Grav docs. The current version is below with some modifications for a site with an SSL/TLS cert. For now, some lines are commented out until a cert is registered. Paste the nginx contfig below in to a new file at /etc/nginx/sites-available/somedomain.com.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# HTTP to HTTPS redirect
server {
        listen      80;
        listen      [::]:80;
        server_name somedomain.com;

        # SSL
        include     snippets/letsencrypt.conf;

        # After you register a cert, uncomment the line(s) below.
        #return 301 https://somedomain.com$request_uri;
}

# Main HTTPS domain
server {
    listen                  443 ssl http2;
    listen                  [::]:443 ssl http2;
    server_name             somedomain.com;
    set                     $base /var/www/somedomain.com;
    root                    $base/public_html;

    # SSL
    # After you register a cert, uncomment the line(s) below.
    #ssl_certificate         /etc/letsencrypt/live/somedomain.com/fullchain.pem;
    #ssl_certificate_key     /etc/letsencrypt/live/somedomain.com/privkey.pem;
    #ssl_trusted_certificate /etc/letsencrypt/live/somedomain.com/chain.pem;

    # Logging
    access_log /var/www/somedomain.com/logs/access.log combined buffer=512k flush=1m;
    error_log  /var/www/somedomain.com/logs/error.log warn;

    # Index files
    index index.html index.php;

    ## Begin - Index
    # for subfolders, simply adjust:
    # `location /subfolder {`
    # and the rewrite to use `/subfolder/index.php`
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    ## End - Index

    ## Begin - Security
    # 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|htm|shtml|shtm|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ { return 403; }

    # Deny running scripts inside user folder.
    location ~* /user/.*\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|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; }
    ## End - Security

    ## Begin - PHP
    location ~ \.php$ {
        # Choose either a socket or TCP/IP address
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
        # fastcgi_pass unix:/var/run/php5-fpm.sock; #legacy
        # fastcgi_pass 127.0.0.1:9000;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }

    # Set the max body size to avoid 403 when saving posts or settings in Grav.
    client_max_body_size 10M;  # Set to 10MB. Adjust as needed.

    ## End - PHP

    location ~* ^/forms-basic-captcha-image.jpg$ {
            try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
            expires 30d;
            add_header Vary Accept-Encoding;
            log_not_found off;
    }

    location ~* ^.+\.(?:css|cur|js|jpe?g|gif|htc|ico|png|html|xml|otf|ttf|eot|woff|woff2|svg)$ {
        access_log off;
        expires 30d;
        add_header Cache-Control public;

        ## No need to bleed constant updates. Send the all shebang in one fell swoop.
        tcp_nodelay off;

        ## Set the OS file cache.
        open_file_cache max=3000 inactive=120s;
        open_file_cache_valid 45s;
        open_file_cache_min_uses 2;
        open_file_cache_errors off;
    }
}

Make a symbolic link to the nginx config in the sites-enabled directory.

1
ln -s /etc/nginx/sites-available/somedomain.com /etc/nginx/site-enabled/

Now nginx will know how to handle requests for the site. Check to make sure there are no problems with the config, then reload nginx for the config to be used.

1
sudo nginx -t && systemctl reload nginx

Register the certificate

Register your cert using certbot. Use the --dry-run flag until you get a success message. There are rate limits on requesting a new cert and too many failed attempts will get you blocked. There are great instructions for certbot commands at certbot.eff.org. The command below should register a cert with the config above. The command below registers and stores a cert on the server. If you do not use certonly, certbot will also attempt to write to the nginx config for the domain.

1
certbot certonly --nginx -d somedomain.com --dry-run # remove the --dry-run flag to really register the cert.

After registering the cert, uncomment the line for handling HTTP to HTTPS redirect and the lines that tell nginx where to find the cert. Look for # After you register a cert, uncomment the line(s) below. in the nginx config.

Get Grav and Create a User

Download Grav Core + Admin Plugin from getgrav.org. Unzip it in the public_html directory. Make sure the files are set to the correct user and group (e.g. www-data:www-data).

Navigate to the site where you should be prompted to create an admin user. Once you do that, you are ready to start creating content!

This work by Jason Raveling is licensed under CC BY-ND 4.0 .