Flat-file CMS for personal websites.

Overview

Grav is a flat-file CMS meaning no database - all content is stored as files. Used for opa.janvv.nl and www.janvv.nl.

Access: https://opa.janvv.nl, https://www.janvv.nl Container: CT 123 IP: 192.168.144.72 Port: 80

Source Code

Docker Compose & Install Script: github.com/opajanvv/homelab-docker/tree/main/grav Local copy: ~/dev/homelab-docker/grav/

Deployment

# Clone LXC template
pct clone 902 123 --hostname grav --full
pct set 123 --cores 1 --memory 512
pct set 123 -net0 name=eth0,bridge=vmbr0,firewall=1,gw=192.168.144.1,ip=192.168.144.72/23
pct set 123 -mp0 /lxcdata/grav,mp=/data
pct set 123 -mp1 /home/jan/homelab-docker,mp=/opt/homelab-docker
pct set 123 -features nesting=1,keyctl=1
pct set 123 -onboot 1

# Add AppArmor workaround
cat >> /etc/pve/lxc/123.conf << 'EOF'
lxc.apparmor.profile: unconfined
lxc.mount.entry: /dev/null sys/module/apparmor/parameters/enabled none bind 0 0
EOF

# Deploy
pct start 123
pct exec 123 -- bash -c 'systemctl enable --now docker'
# Configs available via bind mount (no git clone needed)
pct exec 123 -- bash -c 'cd /opt/homelab-docker/grav && chmod +x install.sh && ./install.sh'

Configuration

Stack: Nginx + PHP-FPM

Data Locations:

  • /data/html/ - Grav installation and content
  • /opt/homelab-docker/grav/ - Docker Compose config, nginx.conf

Nginx Config: Custom nginx.conf for handling Grav's routing

Access

  • opa.janvv.nl: https://opa.janvv.nl
  • www.janvv.nl: https://www.janvv.nl
  • Direct: http://192.168.144.72

Content Management

Editing content: Content is in Markdown files under /data/html/user/pages/

  • Login to admin panel: https://opa.janvv.nl/admin
  • Edit pages via web admin or by editing Markdown files directly

Themes and plugins: Managed via Grav admin or by copying to respective directories

Backup

What to backup:

  • /lxcdata/grav/html/ - Entire Grav installation including content

Backup command:

rsync -av /lxcdata/grav/html/ /backup/homelab/grav/

Restore:

pct stop 123
rsync -av /backup/homelab/grav/ /lxcdata/grav/html/
pct start 123

Maintenance

Update:

pct exec 123 -- bash -c 'cd /opt/homelab-docker/grav && docker compose pull && docker compose up -d'

Update Grav (via admin): Admin → Updates Clear cache: Admin → Tools → Clear Cache

View logs:

pct exec 123 -- bash -c 'cd /opt/homelab-docker/grav && docker compose logs -f'

Common Tasks

Create page: Admin → Pages → Add Page Install plugin: Admin → Plugins → Add Install theme: Admin → Themes → Add

Comments

Blog posts on tech and krabbels have a custom comments plugin (user/plugins/comments/). Comments are stored as YAML files in /lxcdata/grav-comments (bind-mounted as mp2 into CT 123 at /data/comments, then Docker-mounted into the containers). Spam protection via Cloudflare Turnstile, email notifications via Brevo HTTP API.

Related