Upgrade und Migration von Redmine – Teil 2 – Thin und Nginx

Da der eingebaute Webrick-Server nicht unbedingt für den Produktivbetrieb geeignet ist bzw. dessen Einsatz nicht empfohlen wird, fehlen noch die restlichen Komponenten, bestehend aus Thin und Nginx. Thin wird als ein schneller und einfacher Rails Server bezeichnet.

Warum Thin und nicht Puma, Unicorn, Passenger oder sonstige? Dazu gibt es etliche “X vs. Y”-Seiten, bis hin zu ausführlichen Vergleichen. Letztlich habe ich mich für Thin entschieden, weil auf dem alten Redmine-Server bereits Thin lief und ich die Konfiguration recht einfach übernehmen konnte.

Thin

Auch bei Thin fiel die Wahl auf die Version der Linux-Distribution, insofern waren Thin und Nginx schnell installiert:

sudo apt install thin nginx

Das Konfigurationsverzeichnis von Thin ist in /etc/ zu finden, in der aktuellen Variante unter /etc/thin2.3/. Bei der bis dato verwendeten Ubuntu Version 14.04 LTS war es noch unter /etc/thin1.8/, dies kann sich also mit weiteren Versionssprüngen wiederum ändern.

Die initiale Konfigurationsdatei von Thin lässt sich recht einfach generieren, ist jedoch auch danach noch änderbar, da es sich nur um ein Yaml-File handelt. Das folgende Kommando wurde für die Generierung genutzt:

$ sudo thin config --config /etc/thin2.3/redmine.yml --chdir /vol/www/redmine \
--environment production --socket /var/run/thin/redmine.sock \
--daemonize --log /var/log/thin/redmine.log \
--pid /var/run/thin/redmine.pid \
--user redmine --group redmine --servers 4 --prefix

Wrote configuration to /etc/thin2.3/redmine.yml

Dieser Schritt war somit erfolgreich, die generierte Datei ist nun unter /etc/thin2.3/redmine.yml zu finden:

---
chdir: "/vol/www/redmine" 
environment: production
timeout: 30
log: "/var/log/thin/redmine.log" 
pid: "/var/run/thin/redmine.pid" 
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
socket: "/var/run/thin/redmine.sock" 
daemonize: true
user: redmine
group: redmine
servers: 4
prefix: "/"

Da Thin hier die Verzeichnisse /var/run/thin für die Sockets und /var/log/thin für die Logfiles benutzt, dieser zunächst jedoch nicht existieren, müssen sie angelegt und mit den entsprechenden Rechten für den User “redmine” versehen werden.

$ sudo mkdir /var/log/thin
$ sudo mkdir /var/run/thin
$ sudo chown redmine:redmine /var/log/thin/
$ sudo chown redmine:redmine /var/run/thin/

Ein erster Test zeigt durchaus vielversprechende Meldungen:

$ sudo /etc/init.d/thin start
[start] /etc/thin2.3/redmine.yml ...
Starting server on /var/run/thin/redmine.0.sock ...

Starting server on /var/run/thin/redmine.1.sock ...

Starting server on /var/run/thin/redmine.2.sock ...

Starting server on /var/run/thin/redmine.3.sock ...

Läuft Thin wirklich?

$ ps ax | grep thin
  409 ?        Sl     0:03 thin server (/var/run/thin/redmine.0.sock)
  422 ?        Sl     0:03 thin server (/var/run/thin/redmine.1.sock)
  438 ?        Sl     0:03 thin server (/var/run/thin/redmine.2.sock)
  448 ?        Sl     0:03 thin server (/var/run/thin/redmine.3.sock)

Ok, gilt dasselbe auch nach einem Reboot? Leider nicht – hier spielt die Einbindung des /var/run bzw. /run-Verzeichnisses als tmpfs eine Rolle, denn das benötigte Verzeichnis /var/run/thin gehörte wieder dem User root und nicht redmine.

Um diesem Umstand Abhilfe zu schaffen – und auch dies hatte ich bereits aus der vorherigen Konfiguration übernommen, ist im Skript unter /etc/init.d/thin eine Zeile hinzugefügt, hier der entsprechende Ausschnitt:

 

[...]
DAEMON=/usr/bin/thin
SCRIPT_NAME=/etc/init.d/thin

# new: test existence of directory and set rights
test -e /var/run/thin || install -m 755 -o redmine -g redmine -d /var/run/thin

# Exit if the package is not installed
[...]

Nach einem erneuten Reboot wurde auch Thin wieder gestartet, insofern – Ziel erreicht.

Nginx

Als letzte Komponente fehlt noch Nginx. Nginx ist als Reverse-Proxy konfiguriert. Anfragen, die nicht von Nginx selbst beantwortet werden können, etwa statische Dateien wie Bilder, CSS-Files o.ä., werden an Thin weiter geleitet. Daneben könnte Nginx auch weitere Anwendungen bzw. virtuelle Hosts unterstützen, was jedoch auf der hier eingerichteten Redmine-VM nicht zum Einsatz kommt.

Um genau zu sein, wird auch nicht direkt auf den Redmine-Nginx zugegriffen, sondern davor wiederum befindet sich ein weiterer Nginx als Reverse-Proxy, der einerseits den Einstieg von außerhalb des internen Netzes darstellt und andererseits als SSL-Proxy dient und z.B. auch den Redirect bei unverschlüsselten Anfragen auf die https-Seite übernimmt. Die SSL-Konfiguration inkl. Zertifikatsverwaltung etc. ist somit zentral auf einer Nginx-Instanz hinterlegt. Diese “äußere Instanz” bedient insofern auch mehrere virtuelle Hosts, die jeweils zu den einzelnen Diensten weiterleiten.

Für den Betrieb von Nginx gibt es immerhin einige Anleitungen, eine davon findet sich sogar in der Dokumentation von Redmine. Ich habe die bestehende Konfiguration weitestgehend übernommen. Die zu findenden Konfigurationsbeispiele unterscheiden sich marginal in Details, im Folgenden ist die für meinen Einsatz lauffähige Konfiguration zu finden.

Zunächst werden keine weiteren vhosts von Nginx benötigt, daher befindet sich die gesamte Webserver-Konfiguration in der Datei /etc/nginx/sites-available/default.

Zunächst wird der Upstream, d.h. Proxy und deren Ziele definiert, der Bereich befindet sich oben außerhalb aller anderen Abschnitte:

upstream redmine {
    server unix:/var/run/thin/redmine.0.sock;
    server unix:/var/run/thin/redmine.1.sock;
    server unix:/var/run/thin/redmine.2.sock;
    server unix:/var/run/thin/redmine.3.sock;
}

Da Redmine bzw. Thin vier Sockets bereit stellt, werden diese allesamt angesprochen.

Im Bereich “server” halten sich die Änderungen gegenüber der Standard-Konfiguration ebenfalls in Grenzen. Zunächst ist das Document-Root geändert, anschließend wird die Weiterleitung an den Upstream-Proxy eingerichtet:

server {

        # [...]
        
        # replaced existing root folder definition
        root /vol/www/redmine/public;
        index index.html;
        
        # [...]
        
        Location / {
                # commented out 
                #try_files $uri $uri/ =404;

                if (-f $request_filename/index.html) {
                        rewrite (.*) $1/index.html break;
                }

                if (-f $request_filename.html) {
                        rewrite (.*) $1.html break;
                }

                if (!-f $request_filename) {
                        proxy_pass http://redmine;
                        break;
                }
                # [...]
        }

}

Achtung – copy&paste ist hier suboptimal. Die gesamte Datei ist größer, ich habe mich hier auf die Änderung der Inhalte beschränkt. D.h. alle anderen Bestandteile sind zunächst erhalten geblieben, auch die Standard-Konfiguration bzgl. Server-Name oder listen-Direktive, dabei reicht es “default_server” mit Port 80 bestehen zu lassen, da die Konfiguration des “echten” Server-Namens in der “außeren” Nginx-Instanz stattfindet.

Für die Konfiguration des Proxy gibt es noch einige spezifische Config-Variablen, die innerhalb der Datei redmine.conf im Verzeichnis /etc/nginx/conf.d/redmine.conf platziert sind. In der globalen Nginx-Konfigurationsdatei /etc/nginx/nginx.conf werden u.a. alle auf *.conf endenden Dateien im conf.d-Verzeichnis automatisch included.

Die Datei redmine.conf hat folgenden Inhalt:

proxy_set_header   Host $http_host;
proxy_set_header   X-Real-IP $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header   X-Forwarded-Proto $scheme;

client_max_body_size       10m;
client_body_buffer_size    128k;

proxy_connect_timeout      90;
proxy_send_timeout         90;
proxy_read_timeout         90;

proxy_buffer_size          4k;
proxy_buffers              4 32k;
proxy_busy_buffers_size    64k;
proxy_temp_file_write_size 64k;

Danach muss Nginx nur noch neu gestartet werden:

$ sudo /etc/init.d/nginx restart
[ ok ] Restarting nginx (via systemctl): nginx.service.

Damit war Redmine vom internen Netz bereits erreichbar, und zwar mittels http://<hostname>/ . Perfekt, so sollte es sein!

Danach hieß es nur noch, den “äußeren” Nginx-Proxy umzustellen, was sich auf eine Änderung der IP-Adresse im upstream-Abschnitt beschränkte.

Nach der Umstellung mussten nur noch die Browser-Caches gelöscht werden, weil sich dort noch einige ältere Dateien befanden, die die neue Redmine-Version doch etwas merkwürdig aussehen ließen. Danach lief alles wieder wie zuvor, nur mit aktueller Software, sowohl bzgl. der zugrunde liegenden Linux-Distribution als natürlich auch Redmine.

Optimierungen

Redmine ist funktional, aber das Default-Design ist nicht das schönste. Glücklicherweise läßt sich dies mit entsprechenden Themes schnell ändern. Einige meines Erachtens empfehlenswerte Themes werden von RedmineUP angeboten, leider muss man dort vor dem Download seine Mailadresse hinterlegen, aber die Themes sind tatsächlich einen Blick wert. Das gilt auch für die teilweise kostenlosen Plugins.

Nach dem Download eines Themes beschränkt sich die Installation auf die Kopie in das themes-Verzeichnis und das Setzen der Rechte sowie anschließendes Umstellen im “Administrations”-Bereich unter “Administration” -> “Konfiguration” -> “Anzeige”. Sofern das Theme erfolgreich installiert wurde, sollte es in der Select-Box bei “Design-Stil” auftauchen.

Im Beispiel die Installation des Themes mit dem Namen “a1”:

$ cd /vol/www/redmine/public/themes
$ sudo unzip /home/geschke/a1_theme-1_1_3.zip
Archive:  /home/geschke/a1_theme-1_1_3.zip
   creating: a1/
[...]
  inflating: a1/stylesheets/buttons.css

$ sudo chown -R redmine:redmine a1

Die Installation von Plugins setzt meist noch ein Durchlaufen einer Datenbank-Migration voraus, folgendes Beispiel installiert das Checklist-Plugin (ebenfalls von RedmineUP):

# als User redmine ausführen! 

$ cd /vol/www/redmine/plugins/
$ unzip /home/geschke/redmine_checklists-3_1_5-light.zip

$ cd /vol/www/redmine

$ bundle exec rake redmine:plugins NAME=redmine_checklists RAILS_ENV=production

Danach Thin neu starten:

$ sudo /etc/init.d/thin restart

Das war es auch schon!

Redmine läuf wie gewünscht und sieht inzwischen durchaus ansprechend aus. Weitere Optimierungen, Design-Anpassungen können jederzeit durchgeführt werden. Was die Plugins anbetrifft, eine kleine Warnung vorweg – es gibt hervorragende Plugins, die fortlaufend weiterentwickelt und gut unterstützt werden. Andere hingegen sind eher mit Vorsicht zu genießen. Vor Installation eines neuen, möglicherweise umfangreicheren Plugins würde ich immer einen Test durchführen, dazu z.B. die gesamte VM clonen und die Kopie einsetzen, um neue Plugins zu testen. Der Aufwand, ein möglicherweise fehlerhaftes Plugin wieder sorgfältig zu entfernen wiegt weit mehr als der Aufwand, eine identische Kopie einer VM zum Laufen zu bringen. Und nicht zuletzt bleibt somit die produktive Installation so sauber wie möglich.

Das war’s zum Thema Redmine und dessen Migration bzw. Upgrade, über Ergänzungen, Hinweise bzw. allgemein Feedback freue ich mich jederzeit!

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Tags: