ShareLaTex Docker Image – Einrichtung unter Debian 8 inkl. aller TeXLive Pakete und systemd

ShareLaTex Web Editor

ShareLaTex ist eine Online-Plattform, auf welcher ihr alleine oder gemeinsam an einem LaTex Dokument arbeiten könnt. Zudem könnt ihr auch direkt „in der Cloud“ euer LaTex bauen und als PDF herunterladen. Also eventuell praktisch für all diejenigen, die oft mit LaTex arbeiten 😉

Das tolle an ShareLaTex ist, das es eine kostenlose, openSource Community Edition gibt, die man ohne allzu großen Aufwand selber hosten kann. Wie das geht und ein paar kleine Tricks bei der Einrichtung erkläre ich in diesem Beitrag.

Als Grundlage nehme ich ein Debian 8 System. ShareLaTex stellt Docker-Container zur Verfügung, mithelfe derer die Einrichtung ein Kinderspiel ist. Dazu müsst ihr aber zuerst Docker und Docker Compose auf eurem System einrichten. Falls ihr dies schon getan habt, könnt ihr diese Schritte einfach überspringen.

1. Docker einrichten

Von Docker gibt es zwei Edition: CE (Community Edition) und EE (Enterprise Edition). Wir werden die Community Edition verwenden. Dazu habe ich hier einfach ganz kurz die offizielle Anleitung zusammengefasst:

Führt zunächst die folgenden vier Befehle als root aus. Der erste Befehl löscht eventuell vorhanden (alte) Bestandteile von Docker, der zweite installierte benötigte Pakete, der dritte fügt den offiziellen GPG Key von Docker und der letzte das eigentliche Repository eurem System hinzu..

$ apt-get remove docker docker-engine
$ apt-get install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
$ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

Anschließend müsst ihr eurere Paketliste aktualisieren und schon könnt ihr Docker installieren.

$ apt-get update
$ apt-get install docker-ce

Nun müsst ihr noch Docker Compose installierne. Dieses Tool hilft euch später die Docker Container zu starten. Dabei handelt es sich um ein Python Tool, das ihr einfach über pip installieren könnt. Falls ihr pip noch nicht installiert habt, führt einfach folgenden Befehl aus:

$ apt-get install python-pip

Nun könnt ihr Docker Compose mit folgendem Befehl installieren

$ pip install docker-compose

Nun habt ihr auf eurem Debian System ein funktionierendes Docker mit Docker Compose installiert. Als nächstes könnt ihr nun ShareLaTex einrichten.

2. ShareLaTex installieren

ShareLaTex braucht zwei externe Dienste: MongoDB und Redis. Da diese nicht unbedingt auf einem System standardmäßig installiert sind, werden diese Dienste ebenfalls über Docker zur Verfügung gestellt. Damit sich diese Abhängigkeiten einfacher verwalten lassen, gibt es Docker Compose. Dieses Tool startet automatisch alle benötigten Container und hängt diese in ein gemeinsames Netzwerk.

ShareLaTex stellt in ihrem Github eine passende Datei zur Verfügung, die diese Abhängigkeiten beschreibt und mit derer Docker Compose das System später mit einem Befehl starten kann. Dazu erstellen wir zunächst ein Verzeichnis und laden die Datei herunter:

$ mkdir /etc/sharelatex
$ cd /etc/sharelatex
$ wget https://raw.githubusercontent.com/sharelatex/sharelatex/master/docker-compose.yml

Diese Datei enthält nun alle Informationen und wir könnten nun schon ShareLaTex starten. In der aktuellen Konfiguration werden jedoch alle Daten im Benutzerverzeichnis gespeichert, was wir ändern wollen. Dafür legen wir zunächst ein neues Verzeichnis /var/lib/sharelatex (mit entsprechenden Unterverzeichnissen an), indem wir die Daten der einzelnen Diensten ablegen wollen:

$ mkdir /var/lib/sharelatex
$ mkdir /var/lib/sharelatex/data
$ mkdir /var/lib/sharelatex/mongodb
$ mkdir /var/lib/sharelatex/redis

Nun müssen wir Docker Compomse mitteilen, dass die Daten dort abgelegt werden sollen. Dazu öffnen wir die yml-Datei und bearbeiten diese:

$ mcedit /etc/sharelatex/docker-compose.yml

Dort findet sich recht weit oben folgende Zeile:

volumes:
    - ~/sharelatex_data:/var/lib/sharelatex

Diese Zeile legt den Speicherort der ShareLaTex Installation fest, die erste Pfadangabe ist das Verzeichnis auf dem Host, die zweite Pfadangabe das Verzeichnis innerhalb des Containers. Achtung: NIEMALS die zweite Pfadangabe ändern, diese gibt den internen Pfad im Docker Image an! Wenn ihr diesen Pfad ändert werden Daten nicht mehr richtig abgesichert und bei einem Neustart des Containers gehen diese Daten verloren.

Diese Zeile ändern wir wie folgt ab:

volumes:
    - /var/lib/sharelatex/data:/var/lib/sharelatex

Nun werden alle Daten von ShareLaTex nicht mehr innerhalb des Benutzerordners gespeichert, sondern in dem von uns vorher angelegten Ordner. Das gleiche machen wir für mongodb und redis. Aus den Zeilen…

volumes:
    - ~/mongo_data:/data/db

[...]

volumes:
    - ~/redis_data:/data

… machen wir:

volumes:
    - /var/lib/sharelatex/mongodb:/data/db

[...]

volumes:
    - /var/lib/sharelatex/redis:/data

Wenn kein weiterer Dienst auf Port 80 (http) lauscht, können wir ShareLaTex nun das erste mal starten. Dafür wechseln wir in das angelegte Konfigurations-Verzeichnis und starten Docker Compose. Falls ihr andere Dienste auf Port 80 habt die ihr nicht beenden wollt, fahrt zunächst mit der Konfiguration fort und starten ShareLaTex einfach später zum ersten Mal 😉

$ cd /etc/sharelatex
$ docker-compose up

Beim ersten mal kann dies einige Minuten dauern, da Docker Compose zunächst die benötigen Docker Container herunterladen muss. Nachdem alle Container heruntergeladen und gestartet sind, ist ShareLaTex erreichbar. Geht dazu einfach in einen Browser, gebt die IP eures Servers ein und ihr solltet die Startseite von ShareLaTex sehen. Nun habt ihr noch keine Benutzer angelegt und eure Installation noch nicht eingerichtet. Dazu beendet den Container zunächst wieder durch einmaliges drücken von Strg+C. Danach sollte Docker Compose die Container ordentlich herunterfahren. Danach können wir ShareLaTex konfigurieren, wie das geht erfahrt ihr im nächsten Kapitel.

3. ShareLaTex einrichten

Nachdem wir unser ShareLaTex Docker Image wieder beendet haben gehen wir zur Konfiguration über. Dazu schauen wir uns das yml-File etwas genauer an.

$ mcedit /etc/sharelatex/docker-compose.yml

Die erste für uns wichtige Zeile ist die folgende:

ports:
    - 80:80

Diese Zeile legt fest, welche Ports des Docker Images „nach außen“ hin geöffnet werden, also vom Internet aus erreichbar sind. Die erste Zahl ist das Port, von dem aus weitergeleitet werden soll (und von wo aus der Dienst erreichbar sein wird), die zweite Zahl hinter dem Doppelpunkt gibt das Port an, an welches die Anfrage innerhalb des Docker Images weitergeleitet wird. In diesem Fall werden alle Anfragen an Port 80 weitergeleitet an Port 80 innerhalb des Docker Images. Würde man diese Zeil z.B. durch 8089:80 ersetzen, würden alle Anfragen an Port 8089 des Servers an Port 80 innerhalb des Containers weitergeleitet. Will man mit dieser Konfiguration ShareLaTex öffnen, muss man in seinem Browser folgendes eingeben: [IP-SERVER]:8080.

Wollt ihr später einen wie in Kapitel 4 beschriebenen HTTPS Reverse Proxy einrichten, so darf dieser Port nicht von außen erreichbar sein, da die Seite ansonsten auch unverschlüsselt aufrufbar wäre. Daher müsst ihr das Port noch explizit an eine IP-Adresse binden, in diesem Fall an die Loopback IP-Adresse. Der Eintrag sieht dann wie folgt aus: 127.0.0.1:8089:80. Danach ist das Port nur noch lokal auf der Maschine erreichbar und nicht mehr über das Internet. Dies Art der Portfreigabe steht im Kontrast zur Freigabemethode der Ports bei z.B. MongoDB. In der Konfiguration ist dazu folgendes vermerkt:

expose:
    - 27017

Auch wenn expose eher nach „freigeben“ klingt, so wird in diesem Fall der Port 27017 nur (!) im intern Dockernetzwerk freigeben, ist von außen also nicht zu erreichen und muss nicht gesondert abgesichert werden. Diese Einstellung sollte auch auf jeden Fall beibehalten werden, da die Dienste ausschließlich vom Docker Image ShareLaTex benötigt werden.

Scrollt man etwas weiter runter findet man eine große Sektion environment:. In diesem Abschnitt wird ShareLaTex konfiguriert. Ein Teil der Konfigurationsparameter sind bereits voreingestellt, aber auskommentiert. Die meisten Einstellungen sind selbsterklärend und benötigen auch keine weiteren Anpassung. Hier mal ein Ausschnitt aus meiner Konfiguration. Zusätzlich hab ich noch den Parameter zum ändern der Sprache der Oberfläche hinzugefügt sowie zwei Einstellungen, um später einen wie in Kapitel 4 beschrieben HTTPS Reverse Proxy einzurichten.

environment:
    SHARELATEX_MONGO_URL: mongodb://mongo/sharelatex
    SHARELATEX_REDIS_HOST: redis
    SHARELATEX_APP_NAME: ShareLaTex
           
    # https nur (!) wenn ihr einen HTTPS Reverse Proxy eingerichtet habt, ansonsten http
    SHARELATEX_SITE_URL: https://latex.domain.tld
    SHARELATEX_NAV_TITLE: domain.tld - Meine ShareLaTex Installation
    # SHARELATEX_HEADER_IMAGE_URL: http://somewhere.com/mylogo.png
    SHARELATEX_ADMIN_EMAIL: NAME@gmail.com

    SHARELATEX_LEFT_FOOTER: '[{"text": "Powered by <a href=\"https://github.com/sharelatex/sharelatex\">ShareLaTeX</a>"}]'
    SHARELATEX_RIGHT_FOOTER: '[{"text": "rechter Footer Text"} ]'

    SHARELATEX_EMAIL_FROM_ADDRESS: "NAME@gmail.com"

    # Nur setzten wenn ein HTTPS Reverse Proxy (wie in Kapitel 4) eingerichtet ist
    SHARELATEX_BEHIND_PROXY: 'true'
    SHARELATEX_SECURE_COOKIE: 'true'

    # Setzt die Sprache der Seite auf Deutsch
    SHARELATEX_SITE_LANGUAGE: 'de'

    SHARELATEX_EMAIL_SMTP_HOST: smtp.gmail.com
    SHARELATEX_EMAIL_SMTP_PORT: 465
    SHARELATEX_EMAIL_SMTP_SECURE: 'true'
    SHARELATEX_EMAIL_SMTP_USER: NAME@gmail.com
    SHARELATEX_EMAIL_SMTP_PASS: DEIN_PASSWORT
    # SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH: 'true'
    # SHARELATEX_EMAIL_SMTP_IGNORE_TLS: 'false'
    SHARELATEX_CUSTOM_EMAIL_FOOTER: "<div>ShareLaTex Installation von NAME </div>"

4. nginx als HTTPS Reverse Proxy

Ich gehe davon aus, dass bereits nginx installiert und konfiguriert ist sowie ein gültiges Zertifikat für die Domain vorliegt. Angenommen, ihr wollt eure ShareLaTex Installation unter der Domain latex.domain.tld betreiben, dann legt ihr am besten ein Konfigurationsfile unter /etc/nginx/sites-enabled/latex.domain.tld an und tragt dort folgendes ein:

server {
	listen       80;
	listen       [::]:80;

	server_name  latex.domain.tld;

	location /.well-known/acme-challenge/ {
		default_type "text/plain";
		alias /var/www/lets_encrypt/.well-known/acme-challenge/;
	}

	location / {
		return              301 https://$server_name$request_uri;
	}
}

server {

	listen 443 ssl spdy;
	listen [::]:443  ssl spdy;
		
	server_name latex.domain.tld;

	ssl on;
	ssl_certificate           /etc/nginx/certs/fullchain;
	ssl_certificate_key       /etc/nginx/certs/key;
	ssl_dhparam /etc/nginx/certs/dhparam.pem;
	ssl_session_timeout 30m;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

	ssl_prefer_server_ciphers   on;
	ssl_ciphers EECDH+AESGCM:EDH+AESGCM:EECDH:EDH:!MD5:!RC4:!LOW:!MEDIUM:!CAMELLIA:!ECDSA:!DES:!DSS:!3DES:!NULL;

	ssl_session_cache shared:SSL:10m;
	ssl_stapling on;
	ssl_stapling_verify on;

	proxy_set_header X-Forwarded-For $remote_addr;

	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
	server_tokens off;

	add_header X-Frame-Options SAMEORIGIN;
	add_header X-Content-Type-Options nosniff;
	client_max_body_size 50M;

	location / {
		proxy_pass http://localhost:8089;

		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_read_timeout 3m;
		proxy_send_timeout 3m;

		access_log      /var/log/nginx/latex.access.log;
		error_log       /var/log/nginx/latex.error.log;        
	}

	location /.well-known/acme-challenge/ {
		alias /var/www/lets_encrypt/.well-known/acme-challenge/;
	}
}

Die hervorgehobenen Zeilen sind diejenigen, die ihr für eure Installation anpassen müsst. Zudem sind bereits die Redirects für Let’s Ecnrypt eingebaut, falls ihr dieses nutzt. Danach müsst ihr nur noch nginx neu starten und die Konfiguration wird übernommen.

$ service nginx restart

Nun könnt ihr auch wieder euren ShareLaTex Container starten. Dazu wechselt ihr in das Config-Verzeichnis von ShareLaTex und führt Docker Composer aus, diesmal jedoch mit einem speziellen Parameter, sodass alles im Hintergrund startet:

$ cd /etc/sharelatex
$ docker-compose up -d

Nun startet ShareLaTex im Hintergrund und sollte über https://latex.domain.tld erreichbar sein. Zu guter letzt müsst ihr nur noch den ersten Administrator anlegen, damit ihr euch im Webinterface anmelden könnt. Dazu führt ihr einfach folgenden Befehl aus:

$ docker exec sharelatex /bin/bash -c "cd /var/www/sharelatex; grunt user:create-admin --email NAME@gmail.com"

Daraufhin werdet ihr nach einem Passwort für den Benutzer gefragt. Nachdem ihr das Passwort zweimal bestätigt habt, habt ihr nun den ersten Administrator-Account angelegt. Mit diesem könnt ihr euch nun im Webinterface anmelden um z.B. weitere Nutzer hinzuzufügen oder erste LaTex-Dokumente anzulegen. Wie ihr eure ShareLaTex Instanz am besten über systemd verwaltet, erfahrt ihr im nächsten Kapitel.

5. systemd einrichten

Als nächstes möchten wir noch, dass sich unsere ShareLaTex Instanz automatisch startet, sobald der Server startet. Falls ihr ShareLaTex aktuell am laufen habt, solltet ihr dieses zuerst beenden:

$ cd /etc/sharelatex
$ docker-compose down

Um ShareLaTex automatisch mit dem Server zu starten nutzen wir unter Debian 8 systemd. Dazu legen wir zunächst eine Service-Beschreibung für ShareLaTex unter /etc/systemd/system/sharelatex.service an, die wie folgt aussieht:

[Unit]
Description=ShareLaTex Docker Container
After=docker.service

[Service]
Type=simple
WorkingDirectory=/etc/sharelatex
ExecStart=/usr/local/bin/docker-compose -f /etc/sharelatex/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /etc/sharelatex/docker-compose.yml down

[Install]
WantedBy=multi-user.target

Anschließend müssen wir dem System noch den neuen Service bekannt machen und aktivieren, danach können wir unsere ShareLaTex Instanz auch schon starten

$ systemctl enable sharelatex
$ systemctl daemon-reload
$ service sharelatex start

Nun könnt ihr im Webbrowser eure eigene ShareLaTex Instanz erreichen, euch als Administrator anmelden und munter loslegen 🙂

6. Alle LaTex Pakte verfügbar machen

Einen kleinen Nachteil hat die aktuelle Installation aber noch: Es sind kaum LaTex-Pakete vorhanden. Um Speicherplatz zu sparen, sind nur die nötigsten Pakete vorhanden, was oftmals störend sein kann, da Pakete nicht „on-the-fly“ nachinstalliert werden. Daher ist es sinnvoll, einfach alle Pakete in dem Container zu installieren, womit ihr dann quasi jedes LaTex-Dokument kompilieren könnt. Aber Achtung: Alle Pakete können ohne Probleme 10-15GB Festplattenspeicher belegen!

Das installieren aller Pakete kann einige Stunden in Anspruch nehmen, daher empfiehlt es sich den Befehl innerhalb einer „screen“-Session laufen zu lassen, sodass man die SSH-Verbindung zum Server beenden kann ohne den Prozess zu verlieren. Falls ihr screen noch nicht installiert habt, installiert es einfach mit einem flotten apt-get 😉

Öffnet danach eine neue „screen“-Session und führt folgenden Befehl durch:

$ screen
$ docker exec sharelatex tlmgr install scheme-full

Dieser Befehl dauert nun einige Stunden. Ihr könnt euer SSH-Fenster dabei einfach schließen. Wenn ihr euch wieder mit dem Server verbindet, gebt einfach

$ screen -r

ein und ihr seht den aktuellen Fortschritt der Installation aller Pakete. Sind nun alle Pakete installiert, so beendet die screen-Session durch Eingabe von exit. Nun sind alle Pakete in ShareLaTex verfügbar. Das Problem ist nur, dass sie nach einem Neustart verloren sind, da Änderungen an einem Docker-Container nicht permanent sind. Daher liegen die Datenverzeichnisse auch außerhalb des Containers. Um die Änderungen nun permanent zu machen, muss man diese „commiten“. Dazu braucht ihr die aktuelle ID eures Containers mit ShareLaTex, die ihr mit folgendem Befehl herausfinden könnt:

$ docker ps

Die Ausgabe sieht z.B. wie folgt aus, die erste Zeile ist dabei die Container ID die wir benötigen:

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                    NAMES
db3f710138c3        sharelatex/sharelatex   "/sbin/my_init"          10 minutes ago      Up 10 minutes       127.0.0.1:8089->80/tcp   sharelatex
611bb04399e4        mongo                   "/entrypoint.sh mo..."   10 minutes ago      Up 10 minutes       27017/tcp                mongo
9abfdb03b5b4        redis                   "docker-entrypoint..."   10 minutes ago      Up 10 minutes       6379/tcp                 redis

In diesem Fall hat unser ShareLaTex Container die ID db3f710138c3. Diese merken wir uns und führen nun folgenden Befehl aus, um die Änderungen im Container (das Installieren aller Pakete) zu commiten und daraus ein neues Docker Image zu erstellen:

$ docker commit -m "installing all latex packages" db3f710138c3 sharelatex/sharelatex:v3

Dieser Befehl kann einige Minuten in Anspruch nehmen. Danach habt ihr aber ein neues Docker Image von ShareLaTex, dass alle LaTex Pakete beinhaltet. Nun müssen wir nur noch ShareLaTex standardmäßig mit diesem Image starten. Dazu bearbeiten wir einfach die Docker Konfigurationsdatei von ShareLaTex unter /etc/sharelatex/docker-compose.yml und ändern die Zeilen „image“ wie folgt ab:

version: '2'
services:
    sharelatex:
        restart: always
        image: sharelatex/sharelatex:v3
[...]

Unser Image haben wir mit der Versionsnummer „v3“ versehen, dieses startet ShareLaTex nun automatisch. Problematisch ist nur das Updaten jetzt. Ohne diese Änderungen würden Updates automatisch ausgespielt werden. Durch unsere Manipulation der Versionsnummer geschieht dies nun nicht mehr. Wollen wir ShareLaTex updaten, müssen wir diese Manipulation rückgängig machen, das neue Docker Image herunterladen, wieder alle Pakete manuell installieren und anschließend wieder die Versionsnummer manipulieren. Falls jemand einen bessere Möglichkeit kennt, nur her damit.

Aber das war es dann, nun solltet ihr eine voll funktionsfähige ShareLaTex Installation haben, die sämtliche LaTex Pakete beinhaltet, automatisch startet und verschlüsselt abrufbar ist. Viel Spaß damit! 😀

3 thoughts to “ShareLaTex Docker Image – Einrichtung unter Debian 8 inkl. aller TeXLive Pakete und systemd”

  1. Vielen Dank für den Blogbeitrag! Er hat mir sehr weitergeholfen.
    Leider scheint jedoch die Einbettung im Abschnitt 4. nginx als HTTPS Reverse Proxy, nicht mehr zu funktionieren. Kann es sein, dass da ein Link nicht mehr funktioniert?

    Vielen Dank sonst!

      1. Ups, mein Fehler, passt doch alles.
        Nachdem ich nochmal geschaut habe, habe ich kapiert, dass man draufklicken muss und per JavaScript dann der Code ausgefahren wird. War davor zu blöd für diese Einsicht und habe gedacht es sei ein Link auf ein PlainText-File, dass ich daher versucht habe in einem neuen Tab zu öffnen.
        Vielen, vielen Dank für diesen Blog-Artikel! Er hat mir sehr viel geholfen, weil bei mir die Einrichtung des Compose-Files mit nginx-proxy Probleme gemacht hat.

Schreibe einen Kommentar

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