diff --git a/Makefile b/Makefile index 4a44c215..2db1ead1 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ DOCKER_EDITOR = -f docker-compose.editor.yml DOCKER_FRONTEND = -f docker-compose.frontend.yml DOCKER_LOCAL = -f docker-compose.yml -f docker-compose.local.yml DOCKER_DEPLOY_DEV = -f docker-compose.yml -f docker-compose.deploy.dev.yml -DOCKER_ALL_FILES = $(DOCKER_LOCAL) $(DOCKER_EDITOR) $(DOCKER_FRONTEND) -f docker-compose.deploy.dev.yml +DOCKER_DEPLOY_LIVE = -f docker-compose.yml -f docker-compose.deploy.live.yml +DOCKER_ALL_FILES = $(DOCKER_LOCAL) $(DOCKER_EDITOR) $(DOCKER_FRONTEND) -f docker-compose.deploy.dev.yml -f docker-compose.deploy.live.yml venv: caster-back/venv/touchfile @@ -60,6 +61,11 @@ docker-deploy-dev: docker compose $(DOCKER_DEPLOY_DEV) build docker compose $(DOCKER_DEPLOY_DEV) up -d +docker-deploy-live: + docker compose $(DOCKER_ALL_FILES) stop + docker compose $(DOCKER_DEPLOY_LIVE) build + docker compose $(DOCKER_DEPLOY_LIVE) up -d + docker-stop: docker compose $(DOCKER_ALL_FILES) stop diff --git a/README.md b/README.md index ee1b6a8f..8da3a968 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,6 @@ passworrd | `admin` ### Network -As the connection of WebRTC relies on delicate network routing we deploy the Janus service in docker network mode `host` instead of `bridge` which puts every service behind a NAT. -The `host` method has the disadvantage that every port we expose within our container is also exposed on our host which an lead to port clashes as well as security problems so please be sure that the firewall is set up correctly. - As WebRTC only works within a SSL environment we use a nginx reverse proxy to forward the port `8089` to the local port `8088` which is the http version of the Janus server. By doing this we can let nginx handle the SSL context and not need to embed this into Janus. diff --git a/caster-back/gencaster/settings/deploy_live.py b/caster-back/gencaster/settings/deploy_live.py new file mode 100644 index 00000000..2b2cec6a --- /dev/null +++ b/caster-back/gencaster/settings/deploy_live.py @@ -0,0 +1,61 @@ +""" +Deploy Live +=========== + +Settings for deploying "*production*" environment on the server via Docker. +""" + +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration + +from .base import * # noqa + +CSRF_TRUSTED_ORIGINS = [ + "https://live.gencaster.org", + "https://backend.live.gencaster.org", + "https://editor.live.gencaster.org", +] + +DEBUG = False + +ALLOWED_HOSTS = [ + "*.gencaster.org", + "gencaster.org", + "live.gencaster.org", + "editor.live.gencaster.org", + "backend.live.gencaster.org", + "localhost", + "127.0.0.1", +] + +CORS_ALLOWED_ORIGINS = [ + "https://editor.live.gencaster.org", + "https://live.gencaster.org", + "https://backend.live.gencaster.org", +] + +SESSION_COOKIE_DOMAIN = ".live.gencaster.org" +CSRF_COOKIE_DOMAIN = ".live.gencaster.org" + +CORS_ALLOW_CREDENTIALS = True + +SESSION_COOKIE_SAMESITE = None + +CSRF_COOKIE_SECURE = True + + +if SENTRY_DSN := os.environ.get("SENTRY_DSN_CASTER_BACK", None): + print("### SENTRY LOGGING ACTIVE ###") + sentry_sdk.init( + dsn=SENTRY_DSN, + integrations=[ + DjangoIntegration(), + ], + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + # We recommend adjusting this value in production. + traces_sample_rate=0.2, + # If you wish to associate users to errors (assuming you are using + # django.contrib.auth) you may enable sending PII data. + send_default_pii=True, + ) diff --git a/caster-sound/Dockerfile b/caster-sound/Dockerfile index cd8a5b8d..beca7cc2 100644 --- a/caster-sound/Dockerfile +++ b/caster-sound/Dockerfile @@ -144,7 +144,9 @@ RUN git clone --depth 1 --branch "v0.11.8" https://github.com/meetecho/janus-gat make configs && \ rm -rf /root/janus-gateway -RUN apk add parallel +# moreutils contains sponge which is needed for this +# https://stackoverflow.com/a/74551579/3475778 +RUN apk add parallel moreutils # ------------------ STATIC HTML FILES # are served via a python http server - only for debugging diff --git a/caster-sound/caster-sound.conf b/caster-sound/caster-sound.conf index 41544592..7bb11a81 100644 --- a/caster-sound/caster-sound.conf +++ b/caster-sound/caster-sound.conf @@ -25,7 +25,8 @@ stdout_logfile=/root/sclang.log stderr_logfile=/root/sclang.log [program:janus] -command=/opt/janus/bin/janus +# inject the env variable into the config before starting +command=sh -c "envsubst '$JANUS_PUBLIC_IP' < /opt/janus/etc/janus/janus.jcfg | sponge /opt/janus/etc/janus/janus.jcfg && /opt/janus/bin/janus" user=root priority=40 startsecs=10 diff --git a/caster-sound/janus.jcfg b/caster-sound/janus.jcfg index 82315feb..a7644b18 100644 --- a/caster-sound/janus.jcfg +++ b/caster-sound/janus.jcfg @@ -214,7 +214,7 @@ media: { ipv6 = true ipv6_linklocal = true #min_nack_queue = 500 - #rtp_port_range = "20000-40000" + rtp_port_range = "10000-10200" #dtls_mtu = 1200 #no_media_timer = 1 #slowlink_threshold = 4 @@ -268,8 +268,8 @@ media: { # be used for gathering candidates, and enable or disable the # internal libnice debugging, if needed. nat: { - # stun_server = "stun.l.google.com" - # stun_port = 19302 + stun_server = "stun.l.google.com" + stun_port = 19302 # nice_debug = false full_trickle = false #ice_nomination = "regular" @@ -300,7 +300,7 @@ nat: { # Multiple public IP addresses can be specified as a comma separated list # if the Janus is deployed in a DMZ between two 1-1 NAT for internal and # external users. - nat_1_1_mapping = "195.201.163.94" + nat_1_1_mapping = "$JANUS_PUBLIC_IP" #keep_private_host = true # You can configure a TURN server in two different ways: specifying a diff --git a/docker-compose.deploy.dev.yml b/docker-compose.deploy.dev.yml index f84f8631..888f4cb9 100644 --- a/docker-compose.deploy.dev.yml +++ b/docker-compose.deploy.dev.yml @@ -18,8 +18,6 @@ services: - static:/home/gencaster/static:rw - ./data:/data - ./data:/home/gencaster/media - extra_hosts: - - "host.docker.internal:host-gateway" osc_backend: volumes: @@ -33,14 +31,16 @@ services: - 7000:7000/udp sound: - network_mode: host env_file: - vars.env - vars.deploy.dev.env + ports: + - 8090:8090 # debug frontend + - 8088:8088 # janus server + - 10000-10200:10000-10200 volumes: - ./data:/data - ./caster-sound/janus.jcfg:/opt/janus/etc/janus/janus.jcfg - # - ./caster-sound/janus.plugin.audiobridge.jcfg:/opt/janus/etc/janus/janus.plugin.audiobridge.jcfg nginx: image: nginx:1.23-alpine diff --git a/docker-compose.deploy.live.yml b/docker-compose.deploy.live.yml new file mode 100644 index 00000000..6ddd5fab --- /dev/null +++ b/docker-compose.deploy.live.yml @@ -0,0 +1,89 @@ +version: '3.9' + +volumes: + static: +services: + database: + env_file: + - vars.env + - vars.deploy.live.env + - .secrets.env + + backend: + env_file: + - vars.env + - vars.deploy.live.env + - .secrets.env + volumes: + - static:/home/gencaster/static:rw + - ./data:/data + - ./data:/home/gencaster/media + extra_hosts: + - "host.docker.internal:host-gateway" + + osc_backend: + volumes: + - ./data:/data + - ./data:/home/gencaster/media + env_file: + - vars.env + - vars.deploy.live.env + - .secrets.env + ports: + - 7000:7000/udp + + sound: + env_file: + - vars.env + - vars.deploy.live.env + ports: + - 8090:8090 # debug frontend + - 8088:8088 # janus server + - 10000-10200:10000-10200 + volumes: + - ./data:/data + - ./caster-sound/janus.jcfg:/opt/janus/etc/janus/janus.jcfg + + nginx: + image: nginx:1.23-alpine + volumes: + - ./nginx.deploy.conf:/etc/nginx/conf.d/default.conf + - static:/static/:ro + - ./data:/home/gencaster/media + ports: + - 8081:80 + depends_on: + - backend + + editor: + platform: linux/amd64 + build: + context: caster-editor + dockerfile: Dockerfile.deploy + args: + - BACKEND_URL=https://backend.live.gencaster.org + - SENTRY_DSN_CASTER_EDITOR=https://4f4b994233384dc3a79ec1a4fea3cd80@o4504548423565312.ingest.sentry.io/4505476421386240 + ports: + - 3001:80 + environment: + - HOST=0.0.0.0 + - PORT=3001 + - BACKEND_URL="https://backend.live.gencaster.org" + depends_on: + - backend + + frontend: + platform: linux/amd64 + build: + context: caster-front + dockerfile: Dockerfile.deploy + args: + - BACKEND_URL=https://backend.live.gencaster.org + - JANUS_URL=https://sound.live.gencaster.org/janus + - SENTRY_DSN_CASTER_FRONT=https://cf06c7d74e1644cab833acf57ae598b3@o4504548423565312.ingest.sentry.io/4505476517396480 + ports: + - 3000:80 + environment: + - NGINX_HOST=0.0.0.0 + depends_on: + - backend diff --git a/docker-compose.yml b/docker-compose.yml index 7c299e61..9cab5c26 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,8 @@ services: env_file: - vars.env - .secrets.env + depends_on: + - database command: ['python', '-m', 'osc_server.server'] sound: diff --git a/docs/deployment.rst b/docs/deployment.rst index 4f37536f..3e256db7 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -1,21 +1,11 @@ Deployment ========== -The only supported way to deploy Gencaster is by using Docker. -This allows for easier development but also introduces some challenges regarding WebRTC communication and CPU realtime priority. - Docker ------ -As WebRTC relies on a peer-to-peer connection it is necessary to run the streaming container :ref:`caster-sound` in ``host`` mode as otherwise the connection can not be initiated because of a lack of proper IP propagation because otherwise the Docker network acts as a NAT. -For more information regarding this topic refer to the `Mozilla Documentation `_. - -.. important:: - - ``host`` mode uses ports on the host machine directly rather than forwarding them from the Docker NAT. - The result is: **it is only possible to run ONE instance of Gencaster on a server**. - Also all necessary ports need to be free on the host. - +As the setup of the streaming stack is delicate the only supported way of deployment is via `docker compose` which automates most of the setup procedure. +Yet it is still necessary to provide some config files which are described here. ``.secrets.env`` ^^^^^^^^^^^^^^^^ diff --git a/vars.deploy.dev.env b/vars.deploy.dev.env index 84a920a6..417eba94 100644 --- a/vars.deploy.dev.env +++ b/vars.deploy.dev.env @@ -1,7 +1,7 @@ -SUPERCOLLIDER_HOST=host.docker.internal +SUPERCOLLIDER_HOST=sound DJANGO_SETTINGS_MODULE="gencaster.settings.deploy_dev" -BACKEND_OSC_HOST=localhost +BACKEND_OSC_HOST=osc_backend # this is needed during build time so change it in # docker-compose.deploy.dev.yml as well if this changes diff --git a/vars.deploy.live.env b/vars.deploy.live.env new file mode 100644 index 00000000..a3b9977a --- /dev/null +++ b/vars.deploy.live.env @@ -0,0 +1,13 @@ +SUPERCOLLIDER_HOST=sound + +DJANGO_SETTINGS_MODULE="gencaster.settings.deploy_live" +BACKEND_OSC_HOST=osc_backend + +# this is needed during build time so change it in +# docker-compose.deploy.dev.yml as well if this changes +BACKEND_URL="https://backend.live.gencaster.org" + +JANUS_PUBLIC_IP=213.133.101.74 + +SUPERCOLLIDER_USE_INPUT=1 +SUPERCOLLIDER_NUM_STREAMS=15