Das Blog ist tot, lang lebe das Blog

howto grav blog cms scss

Jaja, lange nix mehr passiert hier. Dabei sind durchaus spannende Sachen passiert. Aber wie so oft, wenn es spannend ist, fehlt oft die Zeit. Und leider waren einige Themen eher komplex und nur schwierig in einen Blogartikel zu verpacken. Jetzt tut sich immerhin etwas. Ich habe die Schnauze voll von Wordpress. Einige (gut, fast alle) Artikel waren ja bereits schon länger nicht mehr in der Form lesbar, in der es ursprünglich mal geplant war. Ich mag es nicht in HTML zu bloggen, daher hatte ich mir ein Plugin installiert, welches aber leider den Geist aufgegeben hat. Trotz Auto-Update muss man ständig auf der Hut vor Sicherheitslücken sein. Und überhaupt ist es irgendwie zu fett und kann viel zu viel.

Im Moment schaue ich mir daher Grav an.

Grav ist eher ein normales CMS als ein Tool für einen Blog. Die Besonderheit, es kommt ganz ohne Datenbank daher. Alles wird direkt im Filesystem abgelegt. Daher braucht es im Grunde nicht einmal eine Administrationsoberfläche. Die Struktur der Seite wird über Verzeichnisse erzeugt, die Artikel selbst sind Markdown-Dateien. Im Kopfbereich der Markdown-Dateien werden Metadaten aufgelistet (z.B. der Titel der Seite, aber auch Kategorien und Tags). Das Design besteht aus Twig-Templates.

Grav lässt sich mittels Plugins um weitere Funktionen erweitern. Die Auswahl ist nicht so groß, wie z.B. bei Wordpress, aber das sehe ich eher als Vor- denn als Nachteil. Steuern lässt sich Grav vollständig über die Kommandozeile. Wer lieber ein Webinterface nutzen möchte, kann ein solches als Plugin nachinstallieren. Sofern Plugins untereinander Abhängigkeiten haben, werden diese automatisch mitinstalliert. Auch Themes lassen sich, wie Plugins, einfach nachinstallieren. Leider scheint das Comments Plugin nicht mehr gepflegt zu werden und auch nicht mehr, ohne weiteres, zu funktionieren.

Grav-Installation und Nutzung

Aber fangen wir doch vorn an, erst einmal muss natürlich Grav selbst installiert sein. Ich gehe einfach mal davon aus, dass bereits ein Webserver wie Nginx nebst php-fpm oder Apache mit mod_php zur Verfügung steht (im Grunde würde auch eine Kommandozeileninstallation von PHP ausreichen):

cd /var/www/html/
git clone https://github.com/getgrav/grav.git
cd grav
./bin/grav install

Sofern Grav zur weiteren Installation irgendwelche Dependencies fehlen, werden diese entsprechende genannt und müssten nachinstalliert werden. Alternativ kann man natürlich auch den unter https://github.com/getgrav/docker-grav zur Verfügung gestellten Docker-Container verwenden. Eine vollständige Installationanleitung, die noch weitere Installationswege bereithält, findet sich unter https://learn.getgrav.org/basics/installation.

Nachdem ./bin/grav install durchgelaufen ist, kann man sich seine Grav-Seite auch schon im Browser anschauen. Zwei Beispielseiten gehören zur Standardinstallation. Sie beschreiben auch mögliche weitere Schritte zur Einrichtung.

Plugins

Mit dem Befehl ./bin/gpm ruft man die Paketverwaltung von Grav auf. Eine Liste der Plugins und Themes kann mit ./bin/gpm index abgerufen werden. Wer mehr über ein Plugin erfahren möchte kann hierfür ./bin/gpm info $slug nutzen.

Ein Blog ist natürlich kein Blog ohne einen RSS/Atom-Feed, also schauen wir uns das feed-Plugin einmal genauer an:

cd /var/www/html/grav/
./bin/gpm info feed

Der Output lässt keine Wünsche mehr offen:

GPM Releases Configuration: Stable

Found package 'feed' under the 'Plugins' section

Feed [feed]
-----------
The Feed plugin is a simple yet powerful add-on that lets you view a Grav Collection as JSON, RSS or Atom news feed.

Author      : Team Grav <devs@getgrav.org> <http://getgrav.org>
Version     : 1.6.2
Keywords    : feed, plugin, rss, atom, collection, json
Last Update : Tue, 16 Sep 2014, 00:07:16, +00:00 
Homepage    : https://github.com/getgrav/grav-plugin-feed
Demo        : http://demo.getgrav.org/blog-skeleton
Repository  : https://github.com/getgrav/grav-plugin-feed
Bugs        : https://github.com/getgrav/grav-plugin-feed/issues
Download    : https://getgrav.org/download/plugins/feed/1.6.2
License     : MIT
Would you like to read the changelog? [y|N]  y

1.6.2 [06/06/2017]
------------------

Bugfix:
    * Fix issue with feeds not rendering with cache enabled [#27](https://github.com/getgrav/grav-plugin-feed/pull/27)

Press [ENTER] to continue or [q] to quit q

You can install this package by typing:
    ./bin/gpm install feed

Da das Plugin vom Team Grav selbst kommt, gehe ich davon aus, dass es keine Versionskonflikte mit neuen Grav Versionen geben wird. Also steht der Plugininstallation nichts mehr im Wege:

./gpm install feed

In meinem Fall ist das Plugin natürlich bereits installiert, daher fragt der Paketmanager, ob ich es überschreiben möchte:

GPM Releases Configuration: Stable

The package feed is already installed, overwrite? [y|N] y
Preparing to install Feed [v1.6.2]
  |- Downloading package...   100%
  |- Checking destination...  ok
  |- Installing package...    ok                             
  '- Success!  

Clearing cache

Cleared:  /var/www/html/grav/cache/twig/*
Cleared:  /var/www/html/grav/cache/doctrine/*
Cleared:  /var/www/html/grav/cache/compiled/*
Cleared:  /var/www/html/grav/images/*

Touched: /var/www/html/grav/user/config/system.yaml

Die Datei /var/www/html/grav/user/config/system.yaml enthält die Grundkonfiguration unserer Grav-Instanz. Die Konfiguration des Plugins selbst erfolgt in der Datei /var/www/html/grav/user/plugins/feed/feed.yaml, Änderungen sollten allerdings nicht dort vorgenommen werden. Stattdessen sollte man die Datei nach /var/www/html/grav/user/config/plugins/feed.yaml kopieren. So verhindert man, dass nach einem Update des Plugins die Konfiguration auf den Defaultzustand zurückgesetzt wird. Dieses Schema bleibt bei allen Plugins gleich. Nutzt man das Admin-Plugin, wird die Konfiguration automatisch im ./user/config/plugins/-Verzeichnis angelegt.

enabled: true
limit: 10
description: 'My Feed Description'
lang: en-us
length: 500
enable_json_feed: false

Die Anpassung der Konfiguration kann nun im Texteditor der Wahl vorgenommen werden, die Änderungen sind sofort aktiv.

enabled: true
limit: 100
description: '21x9.org - system_administration'
lang: de-de
length: 2500
enable_json_feed: true

Dieses Spiel kann man jetzt beliebig wiederholen, bis einem der Funktionsumfang ausreichend erscheint.

Themes

Der Paketmanager von Grav wird auch zu Installation von Themes genutzt:

./bin/gpm install antimatter

Auch die bereits bekannten gpm-Funktionen index und info stehen für Themes zur Verfügung

Sofern das Theme nicht automatisch aktiviert wurde, reicht es aus den Eintrag theme: im Abschnitt pages: in der Datei /var/www/html/grav/user/config/system.yaml auf den slug des gewünschten Themes zu verändern.

Das Theme wird in /var/www/html/grav/user/themes/antimatter/ abgelegt. Der Aufbau eines Themes ist immer gleich. Wichtig ist der Unterordner templates. Hier liegen die eigentlichen HTML-Vorlagen. Die zugehörigen CSS-Dateien befinden sich im Unterordner css. Man sollte aber keine Dateien des Themes verändern, da man sonst Probleme bei eventuellen Updates bekommt.

Anpassungen

Sofern man nur CSS-Änderungen vornehmen möchte, kann man diese einfach in der Datei ./css/custom.css vornehmen.

Komplexere Änderungen, die auch die eigentlichen Templates betreffen sollte man auf einem anderen Wege vornehmen, dieser ist im Abschnitt Theme Inheritance unter https://learn.getgrav.org/themes/customization sehr ausführlich beschrieben.

Im Grunde erstellt man ein neues Verzeichnis (z.B. mytheme) im Verzeichnis /var/www/html/grav/user/themes/. Dort erzeugt man dann die Datei mytheme.yaml:

enabled: true
dropdown:
  enabled: false

streams:
 schemes:
   theme:
     type: ReadOnlyStream
     prefixes:
       '':
         - user/themes/mytheme
         - user/themes/antimatter

Außerdem, im gleichen Verzeichnis die Datei blueprints.yaml:

name: MyTheme
version: 1.0.0
description: 'Extending Antimatter'
icon: crosshairs
author:
  name: gpkvt
  email: gpkvt@invalid.org
  url: https://www.21x9.org

Sowie mytheme.php:

<?php
namespace Grav\Theme;

class Mytheme extends Antimatter {
  // some new methods, properties, etc.
}
?>

Nun benötigt man noch ein paar SCSS Daten, aus denen dann später die CSS-Dateien generiert werden:

mkdir /var/www/html/grav/user/themes/mytheme/scss/template -p
cp /var/www/html/grav/user/themes/antimatter/scss/template.scss /var/www/html/grav/user/themes/mytheme/scss/template.scss
apt install ruby-sass
cd /var/www/html/grav/user/themes/mytheme/
scss --load-path ../antimatter/scss --watch scss:css-compiled
touch /var/www/html/grav/user/themes/mytheme/scss/template/_custom.scss

Nach dem Start von SCSS wartet der Befehl auf weitere Eingaben. Er kann jedoch einfach mit Strg+C beendet werden.

Alle Änderungen in der Datei ./scss/template/_custom.scss werden von Grav automatisch übernommen.

Nachdem diese Arbeiten abgeschlossen sind, kann das neue Theme in der sysrtem.yaml im config-Verzeichnis von Grav aktiviert werden:

pages:
  theme: mytheme

Will man nun Änderungen am Theme durchführen, kopiert mal einfach die Dateien aus dem Originaltheme in mytheme und nimmt die gewünschen Anpassungen in der Kopie vor:

mkdir -p /var/www/html/grav/user/themes/mytheme/templates/parials -p
cp /var/www/html/grav/user/themes/antimatter/templates/blog.html.twig  /var/www/html/grav/user/themes/mytheme/templates/blog.html.twig 
cp /var/www/html/grav/user/themes/antimatter/templates/partials/blog_item.html.twig  /var/www/html/grav/user/themes/mytheme/templates/partials/blog_item.html.twig 
cp /var/www/html/grav/user/themes/antimatter/languages.yaml  /var/www/html/grav/user/themes/mytheme/languages.yaml

Inhalte

Inhalte in Grav können unterschiedlichen Typen entsprechen. Der Typ bestimmt dann, welches Design-Template für den jeweiligen Inhalt genutzt wird. Das von mir gewählte Theme unterstützt den Typ blog. Im Verzeichnis /var/www/html/user/pages ein neues Verzeichnis 01.blog. Dort lege ich nun eine Datei blog.de.md an:

cd /var/www/html/user/pages/
mkdir 01.blog
cd 01.blog
cat << EOF > blog.de.md
---
sitemap:
    changefreq: daily
    priority: !!float 1
content:
    items:
        - '@self.children'
    limit: 10
    order:
        by: date
        dir: desc
    pagination: true
    url_taxonomy_filters: true
EOF

Wichtig ist hierbei der Abschnitt content. Er sorgt dafür, dass alle Elemente, die in Unterordnern von 01.blog angelegt werden, als Artikel auf der Seite gelistet werden. Dementsprechende lege ich für jeden Artikel ein ein weiteres Verzeichnis unterhalb von 01.blog an und erstelle dort jeweils eine Datei mit dem Namen item.de.md. Sofern ich innerhalb des Artikels Grafiken oder Dateien einbinde, kann ich diese ebenfalls in das Verzeichnis des jeweiligen Artikels ablegen.

Ein beispielhafter Artikel sieht wie folgt aus (/var/www/html/user/pages/01.blog/01.firstarticle/item.de.md):

---
title: 'Titel des Artikels'
media_order: artikelbild.png
date: '01-01-2018 11:11'
publish_date: '01-01-2018 11:11'
taxonomy:
    category:
        - blog
    tag:
        - tag1
        - tag2
        - tag3
author: gpkvt
---

Zusammenfassung / Einleitung des Artikels

===

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

Grav-Konfiguration

Die Konfiguration von Grav selbst teilt sich in verschiedene Dateien in /var/www/html/grav/user/config/ auf. Wichtig sind hier insbesondere site.yaml und system.yaml. Die möglichen Einstellungen sind sehr ausführlich unter https://learn.getgrav.org/basics/grav-configuration beschrieben. Ich habe hier lediglich kleinere Anpassungen vornehmen müssen.

system.yaml

Es werden nur die geänderten Werte aufgeführt.

timezone: Europe/Berlin
reverse_proxy_setup: true
intl_enabled: true
languages:
  supported:
    - de
    - en
home:
  alias: /blog
  hide_in_urls: true
pages:
  theme: antimatter
  order:
    by: default
    dir: asc
  list:
    count: 20
  dateformat:
    default: 'd-m-Y H:i'
    short: 'jS M Y'
    long: 'F jS \a\t g:ia'
  publish_dates: true
  markdown:
    extra: true
    auto_line_breaks: true
    auto_url_links: true
    escape_markup: true
errors:
  display: -1
  log: true
images:
  default_image_quality: 80
  cache_perms: '0750'                                                                                                                                                   

site.yaml

title: 21x9.org
default_lang: de
author:
  name: gpkvt
  email: gpkvt@invalid.org
taxonomies:
  - category
  - tag
summary:
  enabled: true
  format: short
  size: 300
  delimiter: '==='
blog:
  route: /blog

Mehrsprachigkeit

Grav unterstützt mehrere Sprachen. Viele Plugins und Themes bringen bereits eine languages.yaml mit, in der mehr oder weniger viele Sprachen bereits vorhanden sind.

Welche Sprachen die eigene Grav-Installation unterstützen soll, welche als Default gilt, und ob die Sprache anhand der Browsereinstellungen ermittelt werden soll, wird in der system.yaml im config Verzeichnis festgelegt:

intl_enabled: true
languages:
  supported:
    - de
    - en
  include_default_lang: false
  translations: true
  translations_fallback: true
  session_store_active: true
  http_accept_language: true
  override_locale: false

Die Default-Sprache wird in der site.yaml hinterlegt:

default_lang: de

Die Sprachdateien sind, egal ob Theme oder Plugin, immer gleich aufgebaut:

en:
  TRANSLATION_TEST: Antimatter!
  BLOG:
    ITEM:
      CONTINUE_READING: Continue reading...

de:
  TRANSLATION_TEST: Antimatter!
  BLOG:
    ITEM:
      CONTINUE_READING: Weiterlesen...

Die Sprachdatei des gewählten Themes kann einfach um eigene Einträge erweitert werden. In den Template-Dateien selbst kann man diese dann einfach wie folgt referenzieren:

{{ 'BLOG.ITEM.CONTINUE_READING'|t }}

Theme und Plugins sind damit bereits mehrsprachig verfügbar (man sollte natürlich noch prüfen, ob ggf. ein Plugin nicht mit der gewünschten Sprache ausgestattet ist und dies ggf. nachholen).

Um Artikel in mehreren Sprachen zu veröffentlichen, erzeugt man zunächst - wie gewohnt - ein neues Verzeichnis innerhalb der pages-Struktur:

mkdir /var/www/html/grav/user/pages/01.blog/ -p

Innerhalb des Verzeichnisses legt man nun jeweils eine Markdown-Datei pro Sprache an:

  • item.de.md
  • item.en.md

Diese befüllt man, wie üblich, mit dem gewünschten Inhalt. Grav liest dann (gemäß unserer Settings in der system.yaml), die Browserspracheinstellungen aus, und liefer, sofern vorhanden, die eingestellte Sprache. Ist diese nicht vorhanden, wird die Default-Sprache (hier de) geladen.

Interessant im Zusammenhang mit der Mehrsprachigkeit ist ggf. das Plugin File Content. Mit diesem können Dateien in eine page eingefügt werden. So kann ich z.B. Configdateien, die ja in verschiedenen Sprachen trotzdem immer gleich bleiben, einfach in das Artikelverzeichnis kopieren und von dort mittels File Content in alle Sprachvarianten importieren. Ändert sich später etwas an der Configdatei, brauche ich die Änderung nur einmal einpflegen. Das Einfügen von externen Dateien ist einfach:

{{ filecontent('rules_json.txt') }}

Da es sich um ein Twig-Statement handelt, muss allerdings der Header der entsprechenden Seiten jeweils um folgende Einträge erweitert werden:

process:
    markdown: true
    twig: true
twig_first: true

Nutzt man diese Funktion sehr intensiv, kann man die Verarbeitung von Twig in Seiten auch global einschalten.

Server-Konfiguration

Da sich Grav vollständig im docroot des Webservers befindet, liegen auch alle Konfigurationsdateien offen zugänglich im Netz, man muss lediglich den Pfad/Dateinamen kennen. Das ist insbesondere dann unschön, wenn man das Admin-Plugin einsetzt. Diese benötigt natürlich entsprechende Zugangsdaten, diese werden in /var/www/html/grav/user/accounts/$username.yaml abgelegt. In den Dateien befindet sich dann der hash des gewählten Passworts.

Auch das Grav-Logfile wird, sofern aktiv, im Docroot abgelegt (/var/www/html/grav/logs/grav.log). Dort finden sich mitunter für Angreifer interessante Angaben, z.B. zur Verzeichnisstruktur des Servers.

Das Grav-Kommandozeilentool bietet die Erstellung von Backups an. Diese werden in /var/www/html/grav/backup/ als tarball abgelegt und könnten von dort einfach heruntergeladen werden. Daher sollte der Zugriff auf dieses Verzeichnis auf jeden Fall gesperrt werden.

Die Konfigurationsdateien haben alle die Endung .yaml bzw. .yml. Die Log-Dateien enden auf .log. Es empfiehlt sich, dem Webserver das Ausliefern dieser Dateien schlicht zu untersagen. Natürlich sollte man sich vorher vergewissern, dass man nicht irgendwo doch Dateien mit entsprechender Endung ausliefern möchte. In dem Fall könnte man stattdessen den Zugriff auf die entsprechenden Verzeichnis von Grav sperren. Ich zeige dies am Beispiel des backup Verzeichnisses.

nginx

location ~ (\.yaml$|\.yml$|\.log$) {
  return 403;
}

location ~ /backup/.*$ {
  return 403;
}

Eine sehr ausführliche nginx-Konfigurationsdatei befindet sich auch im webserver-configs-Verzeichnis der Grav-Installation.

apache

<FilesMatch "\.(yaml|yml|log)$">
  deny from all
</FilesMatch>

<Directory /var/www/html/grav/backup/>
  deny from all
</Directory>

Für Apache sind bereits entsprechende Einstellungen in Form einer .htaccess Datei in Grav enthalten, diese benötigen jedoch mod_rewrite.


Kommentare

Kommentare unterstützt von Disqus.

Nächster Beitrag Vorheriger Beitrag