Nach fast einer Woche probieren und erstellen von etwa einem dutzend Images und Containern habe ich es just auf Heilgabend 2020 endlich geschafft Open Streaming Platform in einem Podman Container hinter einem Apache 2 Proxy zum laufen zu bringen! Yay!
Hier ist nun eine kleine Anleitung wie ich das gemacht habe.
Anmerkung: Ich habe das ganze in einem OpenSUSE Hostsystem realisiert. Unter Umständen müssen für ander Hostsysteme einige Anpassungen vorgenommen werden.
Dockerfile erstellen:
Ich habe mir folgendes Dockerfile mit den benötigten Packeten zusammengestellt.
MySQL konnte ich nicht dazu nehmen da dies beim Erstellen des Images immer zu einem Fehler und Abbruch geführt hat.
#Download base image ubuntu
FROM ubuntu:latest
LABEL maintainer="PMJ <info@pmj.rocks>"
ARG TZ=Europe/Zurich
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& apt-get update \
&& apt-get install -y init \
&& apt-get install -y apt-utils \
&& apt-get install -y git wget unzip make python3 python3-dev python3-pip python3-setuptools build-essential libpcre3 libpcre3-dev libssl-dev libpq-dev redis gunicorn python3-gunicorn uwsgi-plugin-python3 logrotate ffmpeg nano curl dialog sudo telnet \
&& ln -s /usr/bin/gunicorn /usr/local/bin/gunicorn
CMD [ "/sbin/init" ]
Image erstellen:
Dann erstellt man das Image wie folgt:
podman build --format=docker -t pmj/ospinstall .
Dies dauerte bei mir zwischen 7-10 Minuten.
Container erstellen:
Der Container muss zwingen detached erstellt werden da sonst systemd mit der falschen PID startet!
podman run -t -d \
-p 8585:80 \
-p 8553:443 \
-p 1935:1935 \
-p 5222:5222 \
--mount type=bind,source=/srv/osp/www,target=/var/www \
--restart always \
--cap-add MKNOD \
--name osp pmj/ospinstall
Anmerkung: Ich bin mir nicht ganz sicher welche Ports tatsächlich geöffnet werden müssen, definitiv aber die Ports 80, 443 und 1935!
Da ich zuerst Probleme hatte den Chat zum laufen zu bringen, habe ich auch noch die Ports 5222 und 5269 geöffnet.
Das Problem lag aber daran, dass ich in den Settings von OSP zuerst alles auf http anstatt https laufen liess.
Die Ports 5222 (Client) und 5269 (Server) müssen grundsätzlich nur geöffnet werden, wenn man sich mit einem externen XMPP-Client oder -Server in die Stream-Chats einklinken will.
Configs
Wer auch gerne die Konfiguration ausserhalb des Containers haben möchte um nicht ständig innerhalb des Containers zwischen den Verzeichnissen hin und her wechseln will, der/die kann noch folgende Mounts einbinden:
--mount type=bind,source=/srv/osp/config/nginx,target=/usr/local/nginx/conf \
--mount type=bind,source=/srv/osp/config/ejabberd,target=/usr/local/ejabberd/conf \
--mount type=bind,source=/srv/osp/config/osp,target=/opt/osp/conf
Logs
Wer auch gerne die Logs ausserhalb des Containers haben möchte um nicht ständig innerhalb des Containers zwischen den Verzeichnissen hin und her wechseln will, der/die kann noch folgende Mounts einbinden:
--mount type=bind,source=/srv/osp/logs/osp,target=/opt/osp/logs \
--mount type=bind,source=/srv/osp/logs/ejabberd,target=/usr/local/ejabberd/logs \
--mount type=bind,source=/srv/osp/logs/nginx,target=/usr/local/nginx/logs
Templates
Um eigene Templates zu erstellen bzw. die installierten Templates besser bearbeiten zu können, kann auch der Templatepfad gemountet werden:
--mount type=bind,source=/srv/osp/templates,target=/opt/osp/templates
Apache 2 Reverse Proxy:
Ich habe Apache wie folgt konfiguriert:
<VirtualHost *:80>
ServerName your.streaming.domain
ErrorLog /path/to/your/your.streaming.domain_error_log
CustomLog /path/to/your/your.streaming.domain_access_log combined
RewriteEngine on
# OPENSTREAMINGPLATFORM
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://127.0.0.1:8585%{REQUEST_URI}" [P]
# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode
# keep the host
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8585/ retry=0
ProxyPassReverse / http://127.0.0.1:8585/
</VirtualHost>
<VirtualHost *:443>
ServerName your.streaming.domain
ErrorLog /path/to/your/your.streaming.domain_error_log
CustomLog /path/to/your/your.streaming.domain_access_log combined
RewriteEngine on
SSLEngine on
SSLCertificateFile /path/to/your/your.streaming.domain-ssl.cert
SSLCertificateKeyFile /path/to/your/your.streaming.domain-ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
# OPENSTREAMINGPLATFORM
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://127.0.0.1:8585%{REQUEST_URI}" [P]
# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode
# Container uses a unique non-signed certificate
SSLProxyEngine On
SSLProxyVerify None
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
# keep the host
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8585/ retry=0
ProxyPassReverse / http://127.0.0.1:8585/
</VirtualHost>
Let's Encrypt
Damit eJabberd erstens von aussen erreichbar ist und zweitens die Zertifikate erstellen lassen kann, muss man für alle 3 subdomains eine eigene vHost Konfiguration anlegen und zwar sowohl für http wie auch für https.
<VirtualHost *:80 *:443>
ServerName conference.your.streaming.domain
SSLEngine on
SSLCertificateFile /path/to/your/your.streaming.domain-ssl.cert
SSLCertificateKeyFile /path/to/your/your.streaming.domain-ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode
# Container uses a unique non-signed certificate
SSLProxyEngine On
SSLProxyVerify None
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
# keep the host
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8585/ retry=0
ProxyPassReverse / http://127.0.0.1:8585/
</VirtualHost>
<VirtualHost *:80 *:443>
ServerName proxy.your.streaming.domain
SSLEngine on
SSLCertificateFile /path/to/your/your.streaming.domain-ssl.cert
SSLCertificateKeyFile /path/to/your/your.streaming.domain-ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode
# Container uses a unique non-signed certificate
SSLProxyEngine On
SSLProxyVerify None
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
# keep the host
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8585/ retry=0
ProxyPassReverse / http://127.0.0.1:8585/
</VirtualHost>
<VirtualHost *:80 *:443>
ServerName pubsub.your.streaming.domain
SSLEngine on
SSLCertificateFile /path/to/your/your.streaming.domain-ssl.cert
SSLCertificateKeyFile /path/to/your/your.streaming.domain-ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode
# Container uses a unique non-signed certificate
SSLProxyEngine On
SSLProxyVerify None
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
# keep the host
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8585/ retry=0
ProxyPassReverse / http://127.0.0.1:8585/
</VirtualHost>
Nach der Installtion von OSP müssen in der /usr/local/nginx/conf/locations/ejabberd.conf
folgende Zeilen hinzugefügt werden...
location /.well-known/ {
proxy_pass http://localhost:5280/.well-known/;
}
...und unter /usr/local/nginx/conf/servers
eine neue Datei ejabberd.conf
mit folgendem Inhalt angelegt werden.
# Ejabberd Reverse Proxy Config to Allow for ejabberd acme-challenge
# Uncomment and change server_name to match
server {
listen 80;
server_name conference.your.streaming.domain;
location / {
proxy_pass http://localhost:5280;
}
}
server {
listen 80;
server_name proxy.your.streaming.domain;
location / {
proxy_pass http://localhost:5280;
}
}
server {
listen 80;
server_name pubsub.your.streaming.domain;
location / {
proxy_pass http://localhost:5280;
}
}
Anmerkung: Damit Let's Encrypt sowohl für eJabberd als auch für meinen Proxy ein Zertifikat erstellt bzw. die Challenge durchführen kann musste ich einen extra Host definieren, der als Hauptdomain die Challenge auch für die anderen Domains akzeptieren kann.
Diese Domain habe ich dann Let's Encrypt als Hauptdomain übergeben und die anderen als zusatzliche Domains in das Zertifikat schreiben lassen.
<VirtualHost *:80>
ServerName acme.your.streaming.domain
DocumentRoot /path/to/your/public_html
DirectoryIndex index.html index.htm index.php index.php4 index.php5
</VirtualHost>
OSP installieren
Sobald der Container läuft kann man OSP wie folgt installieren...
...Einloggen in den Container...
podman exec -ti osp bash
... und dann das Installationsskript ausführen...
cd /opt
git clone https://gitlab.com/Deamos/flask-nginx-rtmp-manager.git
cd flask-nginx-rtmp-manager
sudo bash osp-config.sh
Bei mir benötigte das Skript bis zu 20 Minuten bis es abgeschlossen war!
Zwischendurch muss man die Domain eingeben auf welcher OSP schlussendlich erreichbar sein soll.
Anmerkung: Bei mir hat es das Skript nicht ganz geschafft die gunicorn worker sauber zu starten.
Dies kann man mit der eingabe von
systemctl
überprüfen.
Ausser dem systemd-logind.service
sollte kein Eintrag Rot dargestellt werden.
Falls die Worker nicht oder nur teilweise gestartet wurden kann man einfach OSP iwe folgt neu starten
systemctl restart osp.target
Nun kann man die Installation durch Aufrufen der gewählten Domain abschliessen und dann anfangen zu Streamen.
Happy Streaming!
ps: Graceful
Es kann sein, dass der Container beim Herunterfahren länger als die standardmässig eingestellten 10 Sekunden benötigt und dann einfach per SIGKILL runterfährt.
Dem kann man entgegenwirken indem man dem stop-Befehl noch die Optione -t=30 (oder 60, was man auch immer für sinnvoll hält) hinzufügt.
podman stop -t=30 osp