WebDAV unter Nginx einrichten

Der freie Webserver Nginx beherrscht nicht nur das gewöhnliche Ausliefern von Daten über HTTP und HTTPS, sondern verfügt daneben über weitere Module. Mit einem dieser Module kann WebDAV für eine Ressource bereitgestellt werden.

WebDAV steht dabei für Web-based Distributed Authoring and Versioning und basiert auf HTTP. Über WebDAV können Dateien im Internet bereitgestellt werden. Unter anderem ist WebDAV deshalb so interessant weil es die gleichen Ports wie HTTP nutzt und somit in den seltensten Fällen blockiert wird. Im ersten Schritt sollte das benötigte Modul installiert werden:

apt install libnginx-mod-http-dav-ext

Zur Nutzung des Modules für WebDAV muss die Konfiguration der jeweiligen Seite unter /etc/nginx/sites-available/ angepasst werden. In diesem Beispiel wäre dies:

nano /etc/nginx/sites-available/example

Zur dieser Konfigurationsdatei wird folgende Konfiguration hinzugefügt:

server {
        listen   443 ssl;
        listen [::]:443 ssl;

        ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;

        root /var/www/example;

        server_name example.org;

        location / {
                dav_methods     PUT DELETE MKCOL COPY MOVE;
                dav_ext_methods   PROPFIND OPTIONS;
                dav_access    user:rw group:rw all:rw;

                autoindex     on;
        }
}

In diesem Fall wird für die Domain example.org die WebDAV-Unterstützung aktiviert. Dateien können hierbei ohne weitere Authentifizierung herunter- und hochgeladen werden. Soll WebDAV abgesichert werden, so geschieht das über den Basic authentication. Dazu wird dem location-Part folgendes hinzugefügt:

auth_basic "restricted";
auth_basic_user_file /var/www/example/.htpasswd;

Die .htpasswd-Datei kann mit dem Tool htpasswd erstellt werden:

htpasswd -c .htpasswd nutzer1

Bei der Nutzung wird das gewünschte Passwort erfragt. Soll ein weiterer Nutzer hinzugefügt werden, so muss der Parameter -c entfernt werden:

htpasswd .htpasswd nutzer2

Anschließend wird die Konfiguration von Nginx mittels:

service nginx reload

aktualisiert. Danach kann WebDAV für die Ressource verwendet werden.

Mixed Content identifizieren

Nach der Umstellung einer Webseiten auf HTTPS stand ich vor dem Problem das einige der Webseiten Warnungen bezüglich Mixed Content anzeigten. Mixed Content beschreibt dabei den Umstand das z.B. bei einer Seite welche mit HTTPS aufgerufen wird, weitere Inhalte per HTTP – also unverschlüsselt – nachgeladen werden.

Die Entwicklertools von Chrome

Die Entwicklertools von Chrome

Um den Mixed Content zu identifizieren können die Entwicklertools von Chrome genutzt werden. Wenn beim Laden einer Webseite die Console der Entwicklertools geöffnet ist erscheint dort eine entsprechende Meldung. Anschließend kann man sich des Problems annehmen.

HTTPS für Gogs aktivieren

Nach der Installation von Gogs läuft dieses standardmäßig über unverschlüsseltes HTTP. Um dies zu ändern muss die app.ini welche sich im Verzeichnis gogs/custom/conf/ befindet bearbeitet werden:

nano app.ini

In der Sektion Server welche für gewöhnlich so aussieht:

[server]
DOMAIN = example.org
HTTP_PORT = 3000
ROOT_URL = http://example.org:300/
DISABLE_SSH = false
SSH_PORT = 22
OFFLINE_MODE = false

müssen einige Änderungen vorgenommen werden. Die Schlüssel PROTOCOL, CERT_FILE und KEY_FILE werden hinzugefügt und die ROOT_URL angepasst. Danach sollte die Server-Sektion in etwa so aussehen:

[server]
DOMAIN = example.org
HTTP_PORT = 3000
PROTOCOL = https
ROOT_URL = https://example.org:300/
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
DISABLE_SSH = false
SSH_PORT = 22
OFFLINE_MODE = false

Nachdem die Konfiguration gespeichert wurde muss das passende Zertifikat erzeugt werden:

cd custom
mkdir https
cd https
./gogs cert -ca=true -duration=8760h0m0s -host=example.org

Damit ist Gogs nach einem Neustart des Service per HTTPS und damit verschlüsselt erreichbar.

Das Icecast-Protokoll

Bei Icecast handelt es sich um einen freien Streamingserver. Der Server nimmt ein Signal entgegen und streamt es über einen Mountpoint, mit welchem sich die Nutzer des Servers verbinden um den Stream zu hören. Leider ist das Icecast-Protokoll nicht wirklich gut dokumentiert. Stattdessen wird darauf verwiesen, das der Quellcode verfügbar ist. Mit diesem Artikel soll diesem Problem ein wenig Abhilfe geschaffen werden. Das Icecast-Protokoll ist streng genommen einfaches HTTP. Wenn ein Eingangssignal zu einem Icecast-Server gestreamt sendet die Streamingquelle einen HTTP-Request (am Beispiel von butt):

PUT /stream123 HTTP/1.1
Authorization: Basic c291cmNlOmhhY2ttZQ==
User-Agent: butt 0.1.14
Content-Type: audio/mpeg
ice-name: no name
ice-public: 0
ice-audio-info: ice-bitrate=128;ice-channels=2;ice-samplerate=44100

Bei Mixxx würde dieser Request so aussehen:

SOURCE /stream123 HTTP/1.0
Authorization: Basic c291cmNlOmhhY2ttZQ==
User-Agent: libshout/2.0.0
Content-Type: application/ogg
ice-name: 
ice-public: 0
ice-url: http://www.mixxx.org
ice-genre: Live Mix
ice-audio-info: bitrate=128
ice-description:

Den SOURCE-Request den Mixxx hier anwendet ist seit der Version 2.4 des Icecast-Server veraltet und sollte nicht mehr genutzt werden. Stattdessen soll der PUT-Request verwendet werden. Wie man hier sehen kann erfolgt die Authentifizierung über das Basic Authentication Scheme (auch als HTTP Basic Authentication bekannt). In dem Request sind eine Reihe von ice-* Parametern zu finden:

ice-audio-info
Der Parameter ice-audio-info übermittelt eine Schlüssel-Wert-Liste von Audioinformationen. Die Parameter werden dabei durch ein Semikolon getrennt, das ganze könnte z.B. so aussehen:

channels=2;samplerate=48000;

Die Parameter müssen dabei mit der URL-Kodierung kodiert werden.

ice-bitrate
Der Parameter ice-bitrate setzt die Bitrate des Streams.

ice-description
Ist die Beschreibung des Streams nicht mit dem Tag stream-description definiert, so kann die Beschreibung über den Parameter ice-description eingestellt werden.

ice-genre
Ist das Genre des Streams nicht mit dem Tag genre definiert, so kann dies über den Parameter ice-genre eingestellt werden.

ice-name
Ist der Streamname nicht mit dem Tag stream-name definiert, so kann dies über den Parameter ice-name eingestellt werden.

ice-public
In der Konfiguration gibt es das Attribut public, welches angibt ob der Stream in einem öffentlichen Verzeichnis auftauchen soll. Ist der Public-Tag für den Mountpoint nicht definiert, kann dies über den Parameter ice-public gesetzt werden.

ice-url
Ist die URL des Streams nicht mit dem Tag stream-url definiert, so kann dies über den Parameter ice-url eingestellt werden.

Daneben gibt es noch den Content-Type welcher die Art des Streams definiert. Auf diesen Request antwortet der Icecast-Server (wenn die Authentifizierung korrekt ist) mit einem:

HTTP/1.0 200 OK

Statt dem Statuscode 200 sind noch eine Reihe weiteres Codes als Antwort möglich:

401 You need to authenticate
Die Authentifizierungsdaten sind nicht korrekt.

403 Content-type not supported
Streamformat wird von Icecast nicht unterstützt.

403 No Content-type given
Der Quellclient sendete kein Content-Type mit, dies wird allerdings zwingend benötigt.

403 internal format allocation problem
Internes Problem von Icecast mit dem gewählten Formatplugin.

403 too many sources connected
Das in der Konfiguration definierte Limit an gleichzeitig verbundenen Clients wurde überschritten.

403 Mountpoint in use
Der gewählte Mountpoint ist bereits in Benutzung.

500 Internal Server Error
Ein interner Fehler im Icecastserver, auf Clientseite gibt es für diesen Fehler keine Lösung.

Eine Besonderheit ist der Statuscode 100 (Continue) welcher gesendet wird, wenn der Client einen Request mit folgendem Inhalt gesendet hat:

Request: 100-continue

Mit dem Statuscode bestätigt der Server das der Client weiter Daten senden kann. Danach beginnt der Quellclient mit dem häppchenweisen senden des Ogg Vorbis- oder MP3-Stream – das bedeutet das eine MP3 nicht am Stück gesendet wird, sondern in Häppchen welche das Fortschreiten des Streams widerspiegeln. Beim Empfangen eines Streams passiert effektiv das selbe. Der Client (z.B. VLC) sendet dem Server einen GET-Request:

GET /stream123 HTTP/1.1
Host: 10.63.48.119:8000
User-Agent: VLC/2.2.1 LibVLC/2.2.1
Range: bytes=0-
Connection: close
Icy-MetaData: 1

Darauf antwortet der Icecast-Server mit mit:

HTTP/1.0 200 OK
Server: Icecast 2.4.0
Date: Thu, 02 Jul 2015 10:13:50 GMT
Content-Type: audio/ogg
Cache-Control: no-cache
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Pragma: no-cache
ice-audio-info: samplerate=44%2e100;channels=1;quality=0
icy-pub:1

Anschließend sendet der Icecast-Server die Audiodaten an den Client, welche dieser wiedergibt.

Selbstsigniertes Zertifikat erstellen und bei Nginx einbinden

Für verschlüsselte HTTP Verbindungen benötigt man ein Zertifikat. Dieses kann man sich von einer Zertifizierungsstelle (Certificate Authority, CA) ausstellen lassen. Der Haken an der Sache ist das dies Geld kostet (CACert und StartCom mal außen vor gelassen). Eine Alternative hierzu wäre es das Zertifikat selbst zu erstellen. Bei Diensten die man nur für einen kleinen Nutzerkreis z.B. für die Familie hostet, ist es auch vertretbar die Zertifikatswarnung im Browser über sich ergehen zu lassen. Für die Zertifikate wird ein Ordner erstellt und in diesen gewechselt:

mkdir /etc/nginx/ssl
cd /etc/nginx/ssl

Nun werden das Zertifikat und der Certificate Signing Request erstellt:

openssl genrsa -out example.key 2048
openssl req -new -key example.key -out example.csr

Bei der Erstellung des Certificate Signing Request müssen einige Daten angegeben werden:

Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Mecklenburg-Vorpommern
Locality Name (eg, city) []:Neubrandenburg 
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Inc
Organizational Unit Name (eg, section) []:Skunk works
Common Name (e.g. server FQDN or YOUR name) []:example.org
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Nun muss das Zertifikat noch signiert werden, bevor wir es verwenden können:

openssl x509 -req -days 730 -in example.csr -signkey example.key -out example.crt

In diesem Fall ist das Zertifikat 730 Tage, also zwei Jahre gültig. Da die Signierung nun abgeschlossen ist, kann das Zertifikat in Nginx eingebunden werden. Dazu öffnen wir die Datei „/etc/nginx/sites-available/example“, wobei „example“ hier natürlich für die entsprechende Konfigurationsdatei steht. Dort sollte die SSL Konfiguration vorgenommen werden:

server {
        listen 443 ssl;

        root /var/www/example/root;
        index index.html index.htm;
 
        server_name .example.org;

        ssl_certificate /etc/nginx/ssl/example.crt;
        ssl_certificate_key /etc/nginx/ssl/example.key;
}

Nach dem Aktualisieren der Konfiguration mittels:

service nginx restart

ist die verschlüsselte Verbindung für die eingerichtete Seite aktiv und kann genutzt werden.

Weitere Informationen gibt es unter:
http://nginx.org/en/docs/http/configuring_https_servers.html