Unmanaged JackTrip Studio Servers

This article steps you through the process of setting up your own server to host studio sessions

JackTrip Studio Sessions are normally powered by cloud computing servers managed by JackTrip Labs. This is completely transparent so that no IT skills are required, but availability is limited to certain locations worldwide. Unmanaged studio servers utilize infrastructure that you provide, which can be located anywhere in the world. Both offer all the same features and functionality and work exactly the same for anyone who joins your studio sessions.

Most things you need to set up your own unmanaged server is bundled into our JackTrip studio container image. If you are not familiar with containers or cloud-native computing, we recommend starting with Docker's Getting Started Guide.

In its simplest form, you can run the studio container directly from a command line using one of the examples provided. However, in order for things to work properly, it's also necessary to configure an HTTPS (encrypted) web proxy that forwards HTTP (unencrypted) traffic to port 8000.

There are many different ways to do this, and the best way depends on your own unique network and preferences. The details of configuring a web proxy are beyond the scope of this guide, but we'll step you through a few examples using Docker below to help get you started.

Basic Requirements

If you meet all of these requirements and have questions or run into problems, we are happy to help! Please file a support ticket.

  1. Managing a studio server requires advanced IT skills, including a strong understanding of things like cloud-native computing, network routing and firewalls, ingress, DNS, TLS, etc. If you are unfamiliar or uncomfortable with any of these topics, we encourage you to use our fully managed studio servers instead.
  2. You must have a paid subscription plan to host unmanaged studio servers (free trial and coupon minutes are OK). While there are no limits on maximum participants or session duration, your plan's concurrent session limits do still apply.
  3. You must have a fully-qualified domain name (FQDN) with DNS pointing to your server. Check out nip.io and sslip.io if you don't have this. They both resolve for example, A-B-C-D.nip.io to A.B.C.D.
  4. Your server must have a Linux container runtime available. A modern Linux server distribution is strongly recommended, but not strictly required. When using other operating systems, virtualization is likely to get in the way of realtime CPU priorities, resulting in additional audio glitches.
  5. Your server should have the following resources available:
    1. 2-4 vCPUs for each 5 participants. More compute is used for recording, live streaming, etc.
    2. About 2GB memory.
    3. About 2GB disk space. This is only used while recording and live streaming.
    4. Enough network capacity for all participants (a few Mbps each).
  6. Your firewall must allow direct access to your server from the Internet (and your own computer, in case it is on the same LAN/WAN) via the following ports:
    1. TCP ports 443, 4464, 7881 and 3478
    2. UDP ports 22124 and 3478
    3. UDP ports 61000-61099 (at least one for each participant)
    4. UDP ports 50000-50099 (at least one for each participant)

Migrating Your Studio

The first thing that you will need to do is create a new studio, if you haven't already done so. Next, open your studio dashboard and go to the "Settings" tab. Find the "Server Settings" pane and select "Unmanaged." A dialog will appear asking for your server's hostname. Enter your FQDN and confirm.

After migrating, the Server Settings will display two environment variables that you'll need to provide to the studio container: JACKTRIP_STUDIO_ID and JACKTRIP_STUDIO_TOKEN.

Finally, select and follow the steps in one of these examples:

You Already Have a TLS Key and Certificate

This example assumes that you would like to use an existing TLS key and certificate for your FQDN, and that you are using Docker for container orchestration.

  1. Create a new directory called "studio" and save your PEM-encoded TLS key to a file named "server.key" and your certificate to a file named "server.crt". Note that you need to provide a complete certificate chain so that for example the following command succeeds:
    openssl verify -untrusted <( { openssl x509 >/dev/null; cat; } < server.crt ) server.crt
  2. Create a new "default.conf.template" file with the following contents:
    ## Basic Settings
    tcp_nopush on;
    tcp_nodelay on;
    types_hash_max_size 2048;
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    gzip off;


    ## SSL Settings
    ssl_certificate /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/private/server.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;


    ## Connection upgrade for websockets
    map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
    }


    ## Forward 443/tcp to studio container port 8000
    server {
    listen 443 ssl;
    server_name ${JACKTRIP_STUDIO_HOST};
    location / {
    proxy_pass http://${JACKTRIP_STUDIO_HOST}:8000;
    proxy_buffers 100 128k;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    }
    }
  3. Create a new "compose.yaml" file with the following contents:
    services:
    nginx:
    image: nginx
    container_name: nginx
    ports:
    - "443:443"
    environment:
    - JACKTRIP_STUDIO_HOST=REPLACE_WITH_FQDN
    volumes:
    - ./server.key:/etc/ssl/private/server.key:z
    - ./server.crt:/etc/ssl/certs/server.crt:z
    - ./default.conf.template:/etc/nginx/templates/default.conf.template:z
    studio:
    image: jacktrip/studio
    container_name: studio
    privileged: true
    shm_size: '128M'
    cap_add:
    - sys_nice
    ulimits:
    rtprio: 95
    network_mode: host
    environment:
    - JACKTRIP_STUDIO_ID=REPLACE_WITH_STUDIO_ID
    - JACKTRIP_STUDIO_TOKEN=REPLACE_WITH_STUDIO_TOKEN
    Replace "REPLACE_WITH_FQDN" with your server's fully-qualified domain name.
    Replace "REPLACE_WITH_STUDIO_ID" with your JACKTRIP_STUDIO_ID environment variable.
    Replace "REPLACE_WITH_STUDIO_TOKEN" with your JACKTRIP_STUDIO_TOKEN environment variable.
  4. You should now be able to start up your studio server by running:
    docker-compose up -d
  5. Test to make sure the containers are running and TLS works

    $ docker ps
    CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                                           NAMES
    8585286181bc   nginx             "/docker-entrypoint.…"   45 seconds ago   Up 45 seconds   80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   nginx
    c90d6fc28a48   jacktrip/studio   "/sbin/init"             45 seconds ago   Up 45 seconds                                                   studio


    $ curl https://REPLACE_WITH_FQDN/ping
    {"status":"OK"}
  6. You are now ready to join your unmanaged studio!

    To stop the server after you are finished, run:
    docker-compose down

Using Let's Encrypt to Handle TLS for You

This example uses the popular certbot software and Let's Encrypt service to obtain a new TLS certificate for your server, which is automatically rotated. It's based on guidance from this Medium article which we recommend reading first for additional context. In fact, you may want to set up a basic web server by following those instructions, before attempting to do it for your studio.

Note that this example also requires having TCP port 80 accessible from the Internet.

  1. Create a new directory called "studio"
  2. Create a new "default.conf" file with the following contents:
    ## Basic Settings
    tcp_nopush on;
    tcp_nodelay on;
    types_hash_max_size 2048;
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    gzip off;


    ## SSL Settings
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;


    ## Connection upgrade for websockets
    map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
    }

    ## This is used by certbot for domain validation
    server {
    listen 80;
    server_name REPLACE_WITH_FQDN;

    location /.well-known/acme-challenge/ {
    root /var/www/certbot;
    }

    location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    }
    }

    ## Forward 443/tcp to studio container port 8000
    server {
    listen 443 ssl;
    server_name REPLACE_WITH_FQDN;

    # Certificates generated by Let's Encrypt
    ssl_certificate /etc/letsencrypt/live/REPLACE_WITH_FQDN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/REPLACE_WITH_FQDN/privkey.pem;

    # Let's Encrypt best practice configs for nginx
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
    proxy_pass http://REPLACE_WITH_FQDN:8000;
    proxy_buffers 100 128k;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    }
    }
    Replace "REPLACE_WITH_FQDN" with your server's fully-qualified domain name.
  3. Create a new "compose.yaml" file with the following contents:
    services:
    nginx:
    image: nginx
    container_name: nginx
    ports:
    - "80:80"
    - "443:443"
    volumes:
    - ./data/certbot/conf:/etc/letsencrypt:z
    - ./data/certbot/www:/var/www/certbot:z
    - ./default.conf:/etc/nginx/conf.d/default.conf:z
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    certbot:
    image: certbot/certbot
    volumes:
    - ./data/certbot/conf:/etc/letsencrypt:z
    - ./data/certbot/www:/var/www/certbot:z
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
    studio:
    image: jacktrip/studio
    container_name: studio
    privileged: true
    shm_size: '128M'
    cap_add:
    - sys_nice
    ulimits:
    rtprio: 95
    network_mode: host
    environment:
    - JACKTRIP_STUDIO_ID=REPLACE_WITH_STUDIO_ID
    - JACKTRIP_STUDIO_TOKEN=REPLACE_WITH_STUDIO_TOKEN
    Replace "REPLACE_WITH_STUDIO_ID" with your JACKTRIP_STUDIO_ID environment variable.
    Replace "REPLACE_WITH_STUDIO_TOKEN" with your JACKTRIP_STUDIO_TOKEN environment variable.
  4. Create a bootstrap certificate for "the chicken or the egg problem" (from Medium article):
    1. Download the script to your working directory as init-letsencrypt.sh:

      curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh
    2. Edit the script to add in your domain(s) and your email address.

    3. Then run chmod +x init-letsencrypt.sh and ./init-letsencrypt.sh.

  5. You should now be able to start up your studio server by running:
    docker-compose up -d
  6. Test to make sure the containers are running and TLS works

    $ docker ps
    CONTAINER ID   IMAGE             COMMAND                  CREATED              STATUS              PORTS                                                                      NAMES
    391547e7d2a9   jacktrip/studio   "/sbin/init"             About a minute ago   Up About a minute                                                                              studio
    74fd54feb41a   certbot/certbot   "/bin/sh -c 'trap ex…"   About a minute ago   Up About a minute   80/tcp, 443/tcp                                                            example2-certbot-1
    4afbcc334962   nginx             "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   nginx

    $ curl https://REPLACE_WITH_FQDN/ping
    {"status":"OK"}
  7. You are now ready to join your unmanaged studio!

    To stop the server after you are finished, run:
    docker-compose down

Troubleshooting

If the nginx container fails to start, or the curl ping fails, check logs by running:

docker logs nginx

You can tail all logs for the studio container by running:

docker exec -it studio journalctl -f

It can sometimes be helpful to narrow things down to a specific service. For example , you can tail logs for just the "jacktrip" audio server by running:

docker exec -it studio journalctl -u jacktrip -f

Please feel free to also file a support ticket for help.