Mysql Replikation neu aufsetzen als Bash Skript

Donnerstag, 24. Juni, 2021

Wenn eine bestehende Mysql Replikation nicht mehr funktioniert, so half mir etliche Male im Laufe der Berufszeit als Webmaster beim Schweizer Radio DRS / Sysadmin Daseins an der Uni Bern ein top-down-Skript weiter. Wenn gerade Stress ist und man in der Situation nicht erst alle Kommandos zur Wiederinbetriebnahme des Slave nachschlagen mag, dann ist ist man froh, wenn man ein Skript dafür parat liegen hat.

reinit_mysql_replication.sh

Es gibt keine Parameter.

Installation:

Man benötigt einen Mysql Client. Ich hatte daher die Skripte am Mysql-Slave unterhalb /root zu liegen. Daher ist die Verbindung zum Slave ohne Passwort (wird aus der /root/.my.cnf gelesen).
Es wird auch vom eigenen Rechner aus funktionieren, der die Mysql-Ports von Master und Slave erreichen kann. Es ist nur “einen Tick” langsamer (sprich: bei vielen und/ oder grossen Datenbanken > 1 GB Gesamtgrösse nicht zu empfehlen).

Konfiguration:

Die *dist Datei ist umzukopieren und die Hostnamen und Root-Passwörter für Master + Slave sind zu setzen.

Start:

Das Skript reinit_mysql_replication.sh führt der Reihe nach folgende Aktionen aus: es …

  • zeigt aktuellen Slave Status
  • wartet dann auf ein RETURN, bevor die Replikation neu aufgesetzt wird

Aktionen zum Neuaufsetzen der Replikation: das Skript …

  • liest die Position des Binlog am Master (per SQL “SHOW MASTER STATUS G;”)
  • sperrt den Master für Schreibaktionen (”FLUSH TABLES WITH READ LOCK;”)
  • holt aktuelle Datenbank-Dumps vom Master (mysqldump –all-databases –lock-all-tables …)
  • hebt Schreibsperre am Master auf (”UNLOCK TABLES;”)
  • stoppt den Slave (”STOP SLAVE G;”)
  • importiert Dumps des Master auf dem Slave (cat $dumpMaster | mysql $paramdbSlave)
  • setzt am Slave binfile und Position (”CHANGE MASTER TO MASTER_LOG_FILE = …” ; “CHANGE MASTER TO MASTER_LOG_POS = …”)
  • startet den Slave (”START SLAVE G;”)

weiterführende Links:

  1. git-repo.iml.unibe.ch: iml-open-source/mysql-slave-scripts

Restic client auf 64 Bit Linux installieren

Mittwoch, 28. April, 2021

Restic [1] ist ein in Go geschriebenes Backup-Tool für die Kommandozeile … oder zum Skripten. Es besteht aus einem einzigen Binary und hat keinerlei Abhängigkeiten zu Libs, Paketen oder irgendwas. Es erzeugt dedulizierte Backups: initial wird ein Vollbackup gemacht und dann nie wieder - es braucht dann nur noch inkrementelle Backups. Restic gibt es für Windows/ Mac/ Linux und diverse Plattformen (BSD, Solaris, Mips, … - siehe Releases (dort etwas scrollen :-) [2]).

Das hat was.

Daheim werfe ich gerade einen Http-Server als Backup-Endpoint auf die Synology [3].

Auf Systeme am Institut habe ich grob 150 Linux-Systeme - mit altem und neuen Linux Varianten verschiedener Distributionen. Ich habe ein Bash Skript geschrieben, das mit wget das Binary des Restic Client holt, entpackt und ins /usr/bin legt. Wer es für ein anderes OS oder Architektur braucht, müsste den Suffix “_linux_amd64” ersetzen … oder aber auch dynamisch machen (mit

uname -a

könnte man hinkommen).

#!/usr/bin/env bash

# ------------------------------------------------------
# CONFIG
# ------------------------------------------------------
resticversion=0.12.0
doLink=0

installdir=/usr/bin
resticfile=restic_${resticversion}_linux_amd64
downloadfile=${resticfile}.bz2
downloadurl=https://github.com/restic/restic/releases/download/v${resticversion}/${downloadfile}

# ------------------------------------------------------
# MAIN
# ------------------------------------------------------
echo
echo "##### INSTALL RESTIC CLIENT into $installdir #####"
echo

echo ----- DOWNLOAD
if [ ! -f "${downloadfile}" ]; then
         wget -O "${downloadfile}.running" -S "${downloadurl}" 
                 && mv "${downloadfile}.running" "${downloadfile}"

else
         echo SKIP download
fi
echo

echo ----- UNCOMPRESS
bzip2 -d "${downloadfile}"
echo

echo ----- INSTALL
mv "${resticfile}" "${installdir}"
chmod 755 "${installdir}/${resticfile}"
rm -f "${installdir}/restic" 2>/dev/null
test $doLink -eq 0 || ln -s "${installdir}/${resticfile}" "${installdir}/restic"
test $doLink -eq 0 && mv "${installdir}/${resticfile}" "${installdir}/restic"

echo
echo ----- SELF-UPDATE
restic self-update
echo
echo ----- RESULT:
test $doLink -eq 0 || ls -l "${installdir}/${resticfile}" 
ls -l "${installdir}/restic"
echo
echo ----- CURRENT VERSION:
restic version
echo
echo ----- DONE

weiterführende Links:

  1. https://restic.net/ Homepage von Restic
  2. Github: Restic Releases
  3. Github: Skript zur Installation eines Restic Http Servers auf einer Synology

AhCrawler läuft mit PHP8

Montag, 28. Dezember, 2020

Der AhCrawler ist ein PHP Open Source Projekt, das für den Einbau einer Suche auf der eigenen Webseite enststand. Im Backend kann man den Suchindex wie auch die von Besuchern eingegebenen Suchbegriffe analysieren. Hinzu kommen Werkzeuge, wie Linkchecker, Http-Header-Analyse, SSL-Check und Annehmlichkeiten, wie der integrierte webbasierte Updater oder die Verwaltungsmöglichkeit mehrerer Webseiten.

2020-12-28-ahcrawler-v139-is-php8-compatiblepng.png

Nachdem PHP in Version 8 erschien, kam Anfang Dezember 2020 eine Version heraus, die offensichtliche Fehler in der WebGUI unter PHP8 bereinigte. Der Crawler zeigte hingegen bei Http Head Requests mit Curl “irgendwann” ein komisches Verhalten und brach mit einem “Segmentation Fault” ab.

Mit dem heutigen Release des AhCrawler ist aber auch das Geschichte. Ich bezeichne die Software nunmehr als PHP8 kompatibel! Tusch :-)

weiterführende Links:

  1. AhCrawler (de)
  2. DOCs: AhCrawler (en)

Flatpress - sichere Passwortfunktion statt MD5 Hash

Sonntag, 20. Dezember, 2020

Ich hatte es es ja genauso in mein meinen Webtools mit Login gern gemacht: neben dem Admin User wurde das Passwort als MD5 Hash in einer Config-Datei hinterlegt.

Die Hashfunktion MD5 ist nach IT Masstäben nicht mehr wirklich sicher - heisst: man kann mit einem zeitlich vertretbaren Aufwand aus dem Hash das (oder ein) Passwort ermitteln, dass auf den Hash matcht. Verzichtet man gar auf Salts, ist der Angreifer mit Rainbow Tables gar in Sekundenbruchteilen am Ziel. Das ist gar nicht gut. Auf MD5 sollte man heutzutage beim Hashing von Passwörtern - egal ob in einer Konfigurationsdatei oder Datenbank-Feld - komplett verzichten.

Ich will es keineswegs verdammen: als reine Hash Funktion zum Bilden von Prüfsummen von nicht-sensiblen Daten, wie Prüfsummen von Download-Dateien, ist es bedenkenlos einsetzbar.

Aber zurück zum Speichern von Passwörtern. PHP bietet seit einiger Zeit von Haus sichere Funktionen an, sichere Passwort-Hashes zu generieren [2] wie auch eine Check-Funktion [3]. Auf dieses Paar habe ich meine Tools umgestellt und kannte das Prozedere der Umstellung bereits.

Da ich hier als “mein” Blogtool Flatpress seit gefühlten Äonen selbst verwende, hab ich mich gern auch an jenem Tool drangesetzt, und dessen md5 Passwort-Hash durch eine sicherere Variante ersetzt - und eine Lösung für den Issue #59 [4] als Pull Request eingereicht.

Das gilt nicht nur für die neu angelegten Passwörter - auch die Migration ist berücksichtigt: bestehende mit md5 Hash gespeicherte Passwörter werden on the fly beim nächsten Login umgeschrieben.

Arvid, danke und merci für den Merge und Erwähnung auf Twitter [1] für die kommende Version 1.2!

I love OpenSource :-)

weiterführende Links:

  1. Twitter-Nachricht
  2. PHP: Funktion password_hash
  3. PHP: Funktion password_hash
  4. Github Flatpress: Issue #59
  5. Flatpress.org

Matomo-Javascript Tracking Code auslagern

Samstag, 3. Oktober, 2020

Matomo empfiehlt zum Tracken einer Webseite den Einbau des Codeschnipsels innerhalb des HTML Dokuments … im Head Bereich. [1]

Aber: das Hineinschreiben von Javascript Code in das HTML Dokument ist nicht so recht günstig, wenn man im CSP Security Header das Attribut script-src sicher und ohne unsafe-inline konfigurieren will. [3]

Die Abhilfe besteht darin, dass man [2]

  1. das Snippet in eine Javascript Datei auslagert.
  2. den Aufruf des Trackens im Onload Event einfügt - der ebenfalls in der Javascript-Datei ist und nicht im HTML-Code einer Webseite.

Hier einmal ist die Funktion embedTrackingCode benannt:

function embedTrackingCode() {
	var _paq = window._paq = window._paq || [];
	_paq.push(["trackPageView"]);
	_paq.push(["enableLinkTracking"]);

	var u="/matomo/";
	_paq.push(['setTrackerUrl', u+'matomo.php']);
	_paq.push(['setSiteId', 1]);

	var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
	g.defer=true; g.async=true; g.src=u+"matomo.js"; s.parentNode.insertBefore(g,s);    
}

… welche bei Abschluss des Ladevorgangs initialisiert wird:

window.onload = (event) => {
	embedTrackingCode();
};

Hinweis:

Wenn der Tracking Code in einer Javascript-Datei ist, muss man das Http-Caching der JS Datei bei einem expires= im Http Response Header beachten. Man ist u.U. nicht mehr so flexibel, wenn man den Code anpassen wollte, weil Browser das Javascript aus dem Cache nehmen, statt frisch vom Server die angepasste Version zu holen. Man kann per ETag cachen lassen … oder kann die JS-Datei mit Versionsnummer benennen.

weiterführende Links:

  1. Matomo Guide: JavaScript Tracking Client (en)
  2. Matomo Blog: Different ways of embedding the Matomo tracking code for faster website performance (en)
  3. developer.mozilla.org: CSP Header - script-src (en)

Sourcen für Icinga Checks und Graphen mit Graphite

Freitag, 31. Juli, 2020

An “meinem” Institut geht ohne Open Source eigentlich nichts. Damit wir nicht nur nehmen, geben wir an und wann auch etwas als Open Source zurück. Für dieses Thema wird auf unserer Instituts-Webseite kein Platz eingeräumt, daher publiziere ich es hier in meinem privaten Blog.

Ich habe seit Anfang des Jahres eine Icinga Instanz bei uns aufgebaut. Als Icinga-Client auf unseren Servern verwenden wir ein Bash-Skript, das die REST API des Icinga-Servers als auch des Directors anspricht.

Es gibt es diverse mit Bash geschriebene Checks, die die Standard-Nagios Checks ergänzen (und nur teilw. ersetzen). Zur Abstraktion diverser Funktionen, wie z.B.

  • Prüfung auf notwendige Binaries im Check
  • Schreiben von Performance-Daten
  • Handhabe von Exitcodes

… gibt es eine Include Datei, die gemeinsame Funktionen beherbergt. Oder anders: wer einen der Checks verwenden möchte, muss neben dem Check auch einmal die Include-Datei übernehmen.

Die Sourcecodes der Checks sind nun publiziert in [1].

Viele Plugins schreiben Performance-Daten, die wir mit dem Icinga-Graphite-Modul visualisieren. Die unsrigen Ini-Dateien der Graph-Templates liegen in einem separaten Repository [2]. Beim Schreiben der Ini-Dateien der Graph-Templates kam ich immer wieder ans Limit und es gibt (noch?) nicht so wirklich viele dokumentierte Vorlagen. Und so manche in Graphite dokumentierte Funktionen greifen (scheinbar?) nicht in den Inis für Icinga Graphite.

icinga-graph-check_cpu.png icinga-graph-check_netio.png

Ich hoffe, dass trotz ausbaufähiger Dokumentation der ein oder andere doch entwas mitnehmen kann.

Ich kann mir gut vorstellen, den ein oder anderen Check noch einmal im Detail hier im Blog vorzustellen.

weiterführende Links: (en)

  1. git-repo.iml.unibe.ch: icinga-checks
  2. git-repo.iml.unibe.ch: icinga-graphite-templates
  3. Graphite - Icinga Web 2 Module
  4. Graphite Functions

Bash Rest API Client

Dienstag, 3. März, 2020

Ich bin an unserem Institut am Neuaufbau des Monitorings mit ICINGA dran. Weil es so empfohlen wird, kommt das Director Modul zum Einsatz. Ach so, bereut habe ich dies nicht.

Das Monitoring funktioniert über passive Checks: jeder Server meldet sich selbst an und sendet seine Monitoring Daten zu Icinga ein.

Jeder unserer Server soll ein Host Objekt anlegen, die bemötigten Service-Objekte und und die Services mit dem Host-Objekt verknüpfen. Dazu “spricht” jeder Server per REST API mit dem Director. Der muss die Konfiguration zum Icinga-Server deployen.

Zum Einsenden der Daten braucht es den bereitgestellten Slot für den Host+Service auf dem Icinga-Service. Der Client spricht zum Einliefern der Monitoring-Daten ebenfalls mit einer REST-API - aber dann mit der des Icinga Daemons.

Zum Abstrahieren der REST-API Zugriffe auf verschiedene APIs habe ich alles rund um Http abstrahiert und eine Bash-Komponente geschrieben, die diverse Funktionen für Http-Zugriffe und Abfragen in Skripten einfacher verfügbar macht. Die Verwendbarkeit in Skripten war der Fokus. Die Funktionen ähneln vom Aussehen Methoden einer Klasse: “http.[Funktion]”.
Macht man einen Http-Request, so bleibt dessen Antwort im RAM. Bis man den nächsten Request macht - oder die Shell / das Skript beendet.
Weil es ein Wrapper von Curl ist, kann man alle Http-Methoden, wie GET, HEAD, POST, PUT, DELETE verwenden.

Um einen ersten Eindruck zu vermitteln:

http.makeRequest GET https://www.axel-hahn.de/

Diese Aktion erzeugt keine Ausgabe.

Man kann dann mit Funktionen den Statuscode abfragen, den Http Response Header, den Body oder aber die Curl Daten (darin sind z.B. Upload- und Download-Speed und Verbindungszeiten).

http.getResponseHeader

… gibt alle Http-Response-Headerzeilen aus.

http.getStatuscode

… zeigt den Statuscode

http.isOk

… testet, ob die Anfrage mit einem 2xx Code zurückkam.

Für Icinga wurde der Zugriff mit Basic Authentication umgesetzt.

GET Abfragen lassen sich für N Sekunden cachen. Darüber hinaus kann man den Response exportieren und wieder importieren. Nach dem Import kann man wiederum den Response mit allen Funktionen erfragen - mit http.getRequestAge holt man sich das Alter der Ausführungszeit des Requests. Man kann ein Debugging aktivieren, um die interne Verarbeitung offenzulegen und nachzuvollziehen.

Und Einiges mehr.

Falls das für euch interessant klingt, schaut euch das Bash-Skript doch einmal an.

weiterführende Links:

  1. Gitlab: iml-open-source/bash-rest-api-client
  2. Icinga Open Source Monitoring Tool
  3. Icingaweb - Director REST API
  4. Icinga: REST API

Linux: bei Änderung einer / mehrerer Dateien ein Kommando starten

Mittwoch, 16. Oktober, 2019

Ich brauchte da mal was für unsere Systemlandschaft: der Webservice soll neu gestartet werden, wenn sich eine vordefinierte Datei ändert. Wenn es ein Update der Web-Applikation gibt, dann kann jenes Update ein touch [Dateiname] auslösen.

Wenn das Check-Skript mit einem User läuft, der den Webservice starten darf - sei es mit root oder einem User, dem sudo auf systemctl erlaubt ist - dann kann ein Entwickler niedrige Applikationsrechte haben, ihn aber eine spezifische höhere Rechte erforderliche Aktion ausführen lassen, ohne ihm selbst root oder sudo Rechte geben zu müssen.

Mein Skript habe ich onfilechange.sh genannt.
Es benötigt minimal Parameter zum Erfassen der zu überwachenden Trigger-Dateien und das auszuführende Kommando.
Mit einem “-v” schaltet man den Verbose-Modus ein - dann sieht man mehr, was das Skript gerade macht.

Parameter:

-c [command]
    command to execute on a file change
-f [filename(s)]
    filenames to watch; separate multiple files with space and put all in quotes
-h
    show this help
-i
    force inotifywait command
-s
    force stat command
-v
    verbose mode; enable showing debug output
-w [integer]
    for stat mode: wait time in seconds betweeen each test or on missing file; default: 5 sec

Ein erstes einfaches Beispiel:
Es wird der Text Hallo ausgegeben, sobald man (z.B. in einem 2. Terminal) die Datei /tmp/mytestfile toucht oder beschreibt.

onfilechange.sh -f "/tmp/mytestfile" -c 'echo "Hallo" '

Mit einem zusätzlichen Parameter -v kann man etwas genauer reinschauen, wie das Skript onfilechange.sh arbeitet.

Auf der Kommandozeile macht das Skript wenig Sinn. Um es permanent laufen zu lassen, sollte man es als Dienst einrichten. Wie man mit dem Skript einen Systemd Service einrichtet, ist in der Readme enthalten. Folge ganz unten dem Link zum Sourcecode.

Lizenz: Free software; GNU GPL 3.0

Und noch etwas zu den Interna, wie man die Datei-Überwachung bewerkstelligen kann:

(1)
Das gibt es zum einen inotifywait . Das Tool erhält man in vielen Distros mit Installation der “inotify-tools”.

Nachteile:
- Die Datei / alle zu prüfende Dateien müssen immer existieren. Wenn es einen Prozess gibt, der das Löschen der Trigger-Datei zulässt, ist diese Kommando ungünstig
- Installation der “inotify-tools” ist erforderlich

Vorteile:
+ Man kann mehrere Dateien zum Überwachen andocken
+ Man kann spezifisch definieren, welche Events man überwachen möchte
+ Ohne einen Loop zu verwenden, kann man nach Beendigung mit Returncode 0 ein Kommando starten. Die Ausführung erfolgt sofort

(2)
Das Kommando stat liefert etliche Datei-Attribute, wie Namen, letzer Zugriff, letzte Änderung, Rechte, …

Nachteile
- man kann nur 1 Datei prüfen. Bei mehreren muss man sich einen Loop über n Dateien bauen
- es braucht eine while Schleife und ein sleep N, um zyklisch einen Zustand zu überwachen
- der Kommando-Aufruf erfolgt nicht sofort, sondern ist entspr. sleep in dessen Wartezeiten etwas verzögert.

Vorteile:
+ Man kann obige Nachteile weitestgehend umgehen - dann ist die Prüfung mit stat auch die zuverlässigere Variante
+ Es ist in jeder Distribution in der Standard-Installation enthalten

weiterführende Links:

  1. Download/ Readme: git-repo.iml.unibe.ch: onfilechange
  2. Docs: os-docs.iml.unibe.ch/onfilechange/

preDispatcher - speed up my slow Concrete5 website

Dienstag, 20. August, 2019

Meine Concrete5 Webseite wurde langsamer und langsamer. Sie wird auf einem Shared Hosting betrieben (was ohnehin nicht die schnellste Option sein kann) - hier kann ich zudem keinen Varnish oder auch nur irgendeinen anderen Caching Dienst installieren und davorschalten, sondern muss mich mit .htaccess und Standard-PHP-Mitteln behelfen können.

Das Initialisieren eines Requests in Concrete5 (Bootstrapping) braucht scheinbar sehr lange. Selbst statische Inhalts-Seiten, die ein aktives Fullpage Cache haben, benötigen für die Verarbeitung am Server mehr als 200 ms. Hinzu kommen für einen kompletten Request dann noch Netzwerkzeiten für Namensauflösung (DNS), Anfrage zum Server senden … und das Ergebnis zum Browser zurücksenden, was der Browser dann rendert. Meine schnellsten Seiten aus dem CMS waren bei 300 ms. Andere brauchten 3 Sekunden und mehr. Concrete5 ist einfach langsam.

Ich habe einen Cache geschrieben, der Concrete5 vorgeschaltet ist und im Filesystem seine Caching-Daten ablegt. Kurz er hat minimalste Anforderungen und arbeitet mit einem Shared Hoster. Dieses “Vorschalten” umgeht die lange Initialisierungszeit von Concrete5 - dies macht die Seite schnell.

Vor einigen Tagen habe ich eine erste Version meines preDispatchers eingespielt. Erwartungsgemäss muss man ein paar Kinderkrankheiten ausmerzen. Aber erste Ergebnisse in der Webseiten-Statistik (Matomo) zeigen, dass es eine gute Entscheidung war: die mittleren Seiten-Generierungs-Zeiten sanken von über 2s auf unter 0.4s

2019-08-20-predispatcher-generation-time-in-matomo.png

Der PreDispatcher besitzt eine Debugging-Ausgabe, die die Arbeitsweise veranschaulicht und den Unterschied deutlich macht. Das ist ein ungecachter Aufruf einer Seite mit Fullpage Cache in C5 - also inkl. Bootstrapping + Auslieferung einer in C5 gecachten Seite:

2019-08-20-predispatcher-uncached-concrete5-request-of-fullpage-cached-page.png

Der PreDispatcher speichert den Request, der nicht im Cache ist (oder dessen Caching Zeit abgelaufen ist). Der nächste Request auf dieselbe Seite wird dann schnell. Richtig schnell:

2019-08-20-predispatcher-cached-request.png

Wie lange eine Seite aus einem Cache kommt? Man definiert einen Default für alle Seiten. Mit einer Liste von Regex für aufzurufende URLS kann man die Standard-Vorgabe übersteuern und einen neuen Wert zuweisen.

Zudem gibt es eine Erkennung, was nicht gecacht werden darf - oder wo ein Cache verworfen werden muss. Ich kann mich im C5 Backend einloggen - und der Cache jeder mit Login aufgerufenen Seite wird verworfen.

Ich bin wohl auf dem richtigen Weg. Aber ein wenig Feintuning braucht es noch. Bei Interesse, schaut auf Github … oder fragt mich an :-)

Der PreDispatcher ist Freie Software - unter GNU GPL 3!

weiterführende Links:

  1. Github: pre-dispatcher for more speed
  2. Concrete5 webseite

A Touch Of Glass - Theme für Flatpress

Samstag, 15. Juni, 2019

Mein bisheriger Blog war über Jahre immer ein Custom style … aber eben nicht public.
Nun habe ich meinen erstes Theme für Flatpress veröffentlicht. Vom Look her ist es der klassische Blog Style mit einem hellen Theme als Basis. Wegen der Transparenzen taufte ich es “A Touch Of Glass”.

Warum überhaupt … es gibt ja bereits mehrere Themes?!

  1. Mich stört in Flatpress, dass man den Filter auf einen Monat oder eine Kategorie nicht visualisiert hat. Ich hatte es bis anhin mit einem Hack gelöst. In diesem Theme ist es mit Javascript implementiert: In der Widget-Box ist es nun hervorgehoben als auch im Headerbereich sichtbar.
    2019-06-15-fp-atog-show-category.png
  2. Mehrere Themes für ein 2 oder 3-Spalten-Layout? Das ist unnötig. Wer mag, darf es gern adaptieren. Im Flatpress-Backend platziert man Widgets in einzelne Bereiche. Von mind. 1 Widget benutzte Spalten werden angezeigt; ungenutzte nicht. Klingt banal. Und ist es per CSS an sich auch.
  3. Es fehlen Icons. Naja, an allen Ecken und Enden. Ich habe im Theme per CDN Fontawesome eingebunden und an so einigen Stellen per CSS im Frontend als auch Backend integriert.
  4. Ich wollte ein cooleres Backend. Es soll schliesslich auch 2019 Spass machen, einen neuen Blog-Eintrag zu machen.
    2019-06-15-fp-atog-admin.png

Das Theme gibt etliche Rahmenbedingungen vor. Die Syles - 4 liefere ich einmal mit - sind nur noch extrem einfache CSS Dateien, die einige Default-Farben übersteuern.

2019-06-15-fp-atog-style-blue.png 2019-06-15-fp-atog-style-red.png 2019-06-15-fp-atog-style-sunny.png 2019-06-15-fp-atog-style-teal.png

Weitere Farb-Schemata zu erstellen wird zum Kinderspiel. Wer mag, kann sich eine style.css eines Farbschemas ansehen: es werden CSS Variablen definiert und diese in denjenigen CSS Selektoren angewendet, die übersteuert werden sollen.

Hey, wenn ihr es für gut befindet, empfehlt/ teilt es weiter :-)

UPDATE

  • 19.06.2019: Es sind ein Freitextfilter mit Highligntning bei Kategorieen und auf- und zuklappbare Jahre im Archiv hinzugekommen. Ich hab es nun mal v1.0 genannt :-)
  • 06.08.2019: Mein Twitter-Posting wurde auf dem Flatpress Channel eingefügt (s. Link [6])

weiterführende Links:

  1. Github: Projekt Seite des Themes
  2. Github: Theme A Touch Of Glass als ZIP
  3. Flatpress.org Blogging Engine in PHP ohne Datenbank
  4. Fontawesome Iconset
  5. Twitter: Axels Tweet
  6. Twitter: Flatpress Tweet … und Channel