Installation eines Ghost Blogs auf Debian 7/Wheezy mit Nginx und Node.js

Vor kurzem habe ich dir Ghost vorgestellt. Nun möchte ich dir zeigen wie du einen Ghost-Blog installieren kannst und dabei gleichzeitig auf die Sicherheit deiner Installation achtest.

Download der benötigten Pakete

Da ich die Installation auf einem Debian 7 durchführe und sich Ghost derzeit noch stark in Entwicklung befindet, werden wir folgende Pakete benutzen (die Installation unter Debian 8 verläuft ähnlich, einfach auf meine Ergänzungen dazu achten).

  • Ghost v0.6.4
  • node.js v0.10.29
  • supervisor v3.0
  • nginx v1.2.1

Bitte beachte, dass ich die folgenden Config-Beispiele anhand meines Blogs zeige. Du musst natürlich jeweils deinen Domainnamen einsetzen.

Als erstes updaten wir die Paketliste und installieren alle relevanten Pakete.

apt-get update
apt-get install nginx nodejs supervisor unzip

Danach vergewissern wir uns mit node -v, dass node.js in der richtigen Version installiert ist. Es funktionieren hier alle 0.10.x Versionen.

Nun kann die aktuelle Ghost-Version von der Herstellerseite bezogen werden.

wget https://ghost.org/zip/ghost-latest.zip

Bevor du das Archiv entpackst, legst du am besten einen neuen Ordner im Verzeichnis deines Webservers an. Ich nutze den Standardpfad für Nginx und führe deshalb mkdir /usr/share/nginx/www/linuxfrickeln.de aus. Der Pfad wird von Nginx bei der Installation genutzt und meiner Meinung nach spricht auch nichts dagegen, das zu belassen. Nun kann das Archiv darin entpackt werden.

unzip -uo ghost-latest.zip -d /usr/share/nginx/www/linuxfrickeln.de

Installation von Ghost

Jetzt kannst du zum angelegten Verzeichnis wechseln und Ghost installieren.

cd /usr/share/nginx/www/linuxfrickeln.de && npm install --production

Das war es schon! Jedenfalls theoretisch, denn um die Installation abzusichern müssen wir noch einen Nginx vhost anlegen und den Blog automatisch mit supervisor starten lassen. Außerdem ändern wir noch ein paar Einstellungen für den Blog.

Ghost lässt sich innerhalb verschiedener Umgebungen starten. Das bedeutet, dass mit einem Flag in der Befehlszeile angegeben wird, welcher Teil der Config (production, development etc.) gestartet wird. Für spätere Tests kann man sich also leicht eine eigene Entwicklungsumgebung erstellen. Wir haben jetzt die Produktionsumgebung installiert und starten diese nun.

npm ist ein Paketmanager für Javascript und wird mit node.js geliefert.

npm start --production

Erster Start des Blogs

Man kann nun bereits die Ghost-Installation über http://127.0.0.1:2368 ansurfen. LAN-IPs sollten auch funktionieren, da Ghost an jeder IP auf diesem Port lauscht.
Nachdem du einen ersten Blick in die Oberfläche geworfen hast, kannst du noch die Admin-Oberfläche unter http://127.0.0.1:2368/ghost testen, bevor es weiter geht.

Dort kannst du auch einen Admin-Account anlegen.

Konfiguration von Ghost

Nun muss Ghost noch eingerichet werden. Beim erstmaligen Start wird eine Datei namens config.js im Hauptverzeichnis von Ghost abgelegt. Diese enthält die gesamte Konfiguration von Ghost. Dort kannst du z.B. Einstellungen für E-Mail vornehmen, damit Ghost dir ein neues Passwort setzen kann, solltest du deins vergessen haben.

Du siehst hier meine Config mit Kommentaren zu den wichtigsten Einstellungen.

// # Ghost Configuration
// Setup your Ghost install for various environments
// Documentation can be found at http://support.ghost.org/config/

var path = require('path'),
    config;

config = {
    // ### Production
    // When running Ghost in the wild, use the production environment
    // Configure your URL and mail settings here
    production: {
        url: 'http://linuxfrickeln.de', // URL zu deinem Blog
        urlSSL: 'https://linuxfrickeln.de', // SSL-URL
        mail: {
        from: '"Web Admin" <mailmaster@linuxfrickeln.de>', // Absender Name und Mailadresse
        transport: 'SMTP', // Protokoll für Mail
            options: {
                host: 'localhost', // Mailserver
                port: 25,
                auth: {
                    user: 'mailmaster',// SMTP User
                    pass: 'pass' // SMTP Passwort
                }
            }
        },
        database: {
            client: 'sqlite3',
            connection: {
                filename: path.join(__dirname, '/content/data/ghost.db')
            },
            debug: false
        },

        server: {
            // Host to be passed to node's `net.Server#listen()`
            host: '127.0.0.1', // Server für Ghost... natürlich dieser hier
            // Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT`
            port: '4369' // Port... frei wählbar, muss später im nginx angegeben werden
        }
    }

Automatischer Start

Da Ghost kein Init-Script oder Ähnliches mitbringt, müssen wir uns selbst helfen. Ich vermute aber, dass dies in einer der nächsten Versionen ergänzt wird. Es gibt hierfür mehrere Möglichkeiten. Du kannst dir eine aussuchen (ich empfehle supervisor für Debian 7 und systemd-Units für Debian 8).

...mit supervisor

Diese Möglichkeit nutze ich persönlich am liebsten. Es gibt nur einen Python-Prozess der gestaret werden muss. Darauf baut die komplette Ghost-Installation samt eigenem Webserver auf. Deshalb ist es völlig ausreichend, supervisor diesen Prozess verwalten zu lassen. Wir verzichten somit auf Init-Scripts und andere Selbst geschriebene Bastellösungen.

Wir haben supervisor oben bereits installiert. Jetzt müssen wir eine Config für den Blog anlegen. Das geht mit vim /etc/supervisor/conf.d/linuxfrickeln.de.conf. Darin fügst du jetzt folgenden Inhalt ein und passt ihn entsprechend an (Webserver-Pfad, Domainname, user etc.).

[program:linuxfrickeln.de]
command = node /usr/share/nginx/www/linuxfrickeln.de/index.js
directory = /usr/share/nginx/www/linuxfrickeln.de/
user = lf-blog
autostart = true
autorestart = true
stdout_logfile = /var/log/supervisor/linuxfrickeln.de_access.log
stderr_logfile = /var/log/supervisor/linuxfrickeln.de_error.log
environment = NODE_ENV="production"

Anschließend noch per service supervisord restart den Dienst neu starten, damit die neue Config aktiviert wird. Unter Debian Jessie führst du den Neustart mit systemctl restart supervisord aus. Falls du mehrere Konfigurationen in dem conf.d-Verzeichnis von supervisor hast, kannst du auch mit supervisorctl restart linuxfrickeln.de nur eine einzelne Config neu starten.

...mit systemd und Debian 8/Jessie

Ich bin ja ein Freund von Veränderungen und neuen Dingen. systemd ist da keine Ausnahme, es ist allerdings ein Monster an Funktionen. Solltest du Debian 8 nutzen, kannst du bereits systemd verwenden. Bei Debian 7 kann dieser nachinstalliert werden. Informier dich aber sehr genau über die Änderungen, die systemd am System durchführt und wie es zu bedienen ist.

Was du jetzt siehst, ist eine systemd-Unit. Damit kann ein Service ähnlich einem Init-Script eingerichtet werden. Durch eine systemd-Unit hat man aber bei richtiger Konfiguration mehr Möglichkeiten, einen Prozess oder Dienst zu steuern. Ich verwende hier ein relativ einfaches Beispiel.

vim /etc/systemd/system/linuxfrickeln.service

[Unit]
Description=Linuxfrickeln.de Ghostblog
After=syslog.target
After=network.target

[Service]
User=lf-blog
Group=lf-blog
ExecStart=/usr/local/bin/node /usr/share/nginx/www/linuxfrickeln.de/index.js
Type=forking
TimeoutSec=10
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

Den Service noch mit systemctl enable linuxfrickeln.service aktivieren, damit er beim Boot gestartet wird.

Nginx als Proxy einrichten

Aus dem Ghost Howto...

Do not run Ghost on port 80 directly. This is considered a security risk. We always recommend using a proxy such as nginx.

Du solltest also einen sicheren und gut gepflegten Webserver verwenden. Dieser kann so eingerichet werden, dass er intern auf den Ghostblog weiterleitet. Von außerhalb deines Servers ist nur der Webserver sichtbar, dessen Sicherheitslücken in bekanntem Debian Tempo geschlossen werden. Du kannst also eine veraltete Version von Ghost laufen lassen, solange dein Webserver aktuell ist ohne Sicherheitsbedenken haben zu müssen.

Ich verwende hier Nginx, du kannst natürlich auch jeden anderen Webserver deines Vertrauens einsetzen. Nginx hat einige Vorteile gegenüber herkömmlichen Webservern und wird immer häufiger eingesetzt. Darauf werde ich in einem der nächsten Artikel näher eingehen.

Jetzt aber meine Config für Nginx. Natürlich mit SSL!

server {
    listen 80;
    server_name linuxfrickeln.de www.linuxfrickeln.de;

    # Redirect to ssl site
    return 301 https://www.linuxfrickeln.de$request_uri;
}

server {
    listen 443;
    server_name linuxfrickeln.de www.linuxfrickeln.de;
    root /usr/share/nginx/www/linuxfrickeln.de;

    # reverse proxy, lookup local blog
    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:4369;
    }

    # ssl parameter and own dhparams
    ssl on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'AES256+EECDH:AES256+EDH';
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout  5m;
    ssl_dhparam /etc/nginx/ssl/dh4096.pem;
    add_header Strict-Transport-Security max-age=535680000;

    ssl_certificate /etc/nginx/ssl/linuxfrickeln.de/linuxfrickeln.de_bundled_2015.crt;
    ssl_certificate_key /etc/nginx/ssl/linuxfrickeln.de/linuxfrickeln.de_2015.key;

    access_log      /var/log/nginx/linuxfrickeln.de.access.log;
    error_log       /var/log/nginx/linuxfrickeln.de.error.log;
}

Diese Config bekommt bei SSLLabs die Note A+ (Stand: 31.08.2015). Das SSL ist also ausreichend sicher eingerichtet. Die Wertung kann allerdings mit Bekanntwerden von Sicherheitslücken und Ähnlichem abwerten. Diesen Test sollte man regelmäßig durchführen.

Hast du Hinweise oder Fragen zum Setup? Dann ab damit in die Kommentare. Ich freue mich drauf!