Installing Yack
Introduction
Yack runs on Docker, on one of these:
- AWS, one host or three, provisioned and installed using provided scripts.
- Your own host, Linux or an Apple Mac.
Both start from the same files (Common resources). After the destination-specific instructions, the remaining sections in this guide apply generally.
Common resources
A handful of loose files, such as the docker-compose definitions and the
bin/ scripts that start, stop and manage Yack, are shipped inside the yack
image, so each release carries its own. To extract them, with Docker and
bash on your own machine (on AWS, the one you install from; otherwise the
host Yack runs on), in a new directory, called <INSTALL_DIR> below:
mkdir yack && cd yack # this is <INSTALL_DIR>, e.g. ~/yack
id=$(docker create --pull=always thoughtbreak/yack:stable) && docker cp "$id:/opt/yack-dist/." . && docker rm "$id"
Every command in this guide runs from <INSTALL_DIR>, and every relative
path in it is relative to <INSTALL_DIR>. On AWS there are two: yours, on
the machine you install from, and each host's, ~/yack, which the install
makes.
On AWS
You need Docker and AWS credentials on your machine, a Route 53 hosted zone, an EC2 key pair and a sign-in client (In detail lists them).
TL;DR
In <INSTALL_DIR>, with the common resources extracted (above):
# Optional: the IAM policy for a provisioning user of your own, for an administrator to attach
./aws-bootstrap.sh --policy --app your-org-yack --region eu-west-2 > your-org-yack-provision-policy.json
# Once per AWS account and region, as an administrator
./aws-bootstrap.sh --region eu-west-2
# Your settings: copy the template, then edit .env as its opening comments
# say - set REALM, a sign-in client and, in its "On AWS" section, AWS_REGION,
# YACK_ADMIN, AWS_KEY_PAIR and AWS_APP (AWS_ZONE too when your Route 53
# hosted zone isn't REALM less its first label); change anything else you want to
cp .env.example .env
# Provision AWS and install Yack (aws/prod remembers the deployment's settings after)
./aws-install.sh prod
# Optional: demo data, over ssh through Systems Manager (see In detail for ~/.ssh/config)
ssh yack.example.com 'cd yack && bin/bootstrap-demo.sh jo@example.com'
In detail
One command, run on your own machine, provisions Yack's AWS stacks and
installs Yack on them: ./aws-install.sh. It uses the
thoughtbreak/yack-provision image matching the selected release, which
carries the stacks and the tools to deploy them. For one
deployment, <ENV> (e.g. prod), it makes three stacks:
YackHostsStack-<ENV>: a VPC, the host (m8g.large by default, a Graviton type: 2 vCPUs and 8 GB, enough for several rooms of a handful of people;AWS_INSTANCE_TYPE=c8g.xlargedoubles the CPU for all-hands meetings with many cameras; Graviton transcribes more slowly than x86, soAWS_BATCH=true, or an x86 type such asm6i.large, suits a host that records a lot; a 100 GB data volume, an Elastic IP, the DNS record for your domain) or, withAWS_HOSTS=3, two app hosts (m8g.large) behind a load balancer and a support host (t3.large); their IAM role; and, withAWS_BATCH=true, AWS Batch to run media processing off the hosts.YackDataStack-<ENV>: the attachments bucket (uploads malware-scanned by GuardDuty, unreadable until clean), the recordings bucket and the backups bucket (the hosts may add backups, never delete them; they expire after 14 days). Kept when the stack is deleted.YackMailStack-<ZONE>: sending mail through Amazon SES from your zone's domain. New SES accounts send only to verified addresses until you ask AWS for production access (SES console).
You need, in the account and region you choose:
- Docker on the machine you provision from, and AWS credentials there: an
administrator's, or better a user of its own with just the rights Yack's
provisioning needs, which
./aws-bootstrap.sh --policy --app your-org-yack --region ...prints as one IAM policy for an administrator to attach (bootstrapping, the first time per account and region, needs an administrator either way). - A Route 53 hosted zone for your domain or its parent (for
yack.example.com, by default the zoneexample.com;AWS_ZONEnames another, e.g.AWS_ZONE=yack.example.comto put Yack at the zone's own name). - An EC2 key pair, for ssh to the hosts should you want it.
- A free VPC: each deployment takes one, and a region allows five by default (Service Quotas, "VPCs per Region").
- A sign-in client, Google's, Microsoft's or both (Sign-in providers),
with the redirect URI
https://<REALM>/auth/google/callbackor.../auth/microsoft/callback.
With these files copied out of the image on your machine (above), copy
<INSTALL_DIR>/.env.example to <INSTALL_DIR>/.env and edit it as its
opening comments say.
Then run ./aws-bootstrap.sh (once per account and region) and
./aws-install.sh, as in the TL;DR.
Both scripts, with no arguments, explain their options; --profile picks an
AWS CLI profile. ./aws-install.sh reads .env, or --settings <FILE>:
the deployment's settings (AWS_REGION, YACK_ADMIN, AWS_KEY_PAIR,
AWS_APP, AWS_ZONE, AWS_HOSTS, AWS_INSTANCE_TYPE, AWS_BATCH) as well
as Yack's, each explained there; an option of the same meaning (--region,
--admin ...) overrides one for that run. AWS_APP prefixes every name
(default yack); bucket names are global, so choose your own. CDK asks
before creating IAM roles; answer y. YACK_ADMIN is your first
superadmin, activated by their first sign-in.
./aws-install.sh saves your .env settings, and the secrets it generates,
in AWS Systems Manager Parameter Store under /<APP>/<ENV>/env/. It installs
Yack into ~/yack on each host (its <INSTALL_DIR>), with timers for backups, certificate
renewal and upgrades, starts it and makes the superadmin. Each host keeps
the install's log in ~/yack/install.log.
Your settings live in AWS; <INSTALL_DIR>/.env on your machine is your copy of them, and the one
place you change them. Four things to know:
- Change a setting: edit
<INSTALL_DIR>/.env, then./aws-install.sh prod --settings-only. Each host has it within a minute or two, one at a time, with no stack changes..envis the whole of your settings: one you delete from it is removed from AWS too (you're shown which, and asked). - Change the stacks (
AWS_BATCH,AWS_INSTANCE_TYPE, ...): edit.env, then./aws-install.sh prod; it applies your settings too. The region can't change, nor can one host become three; a newYACK_ADMINadds another superadmin. - On a new machine (or if
<INSTALL_DIR>is lost): in a new<INSTALL_DIR>with the common resources,./aws-install.sh prod --pull --region eu-west-2(and--app, if notyack) restores<INSTALL_DIR>/aws/prodand your settings, the deployment's among them, into<INSTALL_DIR>/.env, from AWS. The secrets Yack generates never leave AWS, so nothing is lost with this machine. - Remove it:
./aws-install.sh prod --uninstalldeletes the deployment for good - its hosts, its data (recordings, backups, attachments) and its settings in AWS, and<INSTALL_DIR>/aws/prod- after you type its name.
<INSTALL_DIR>/aws/<ENV> remembers the deployment's settings (AWS_ZONE, AWS_KEY_PAIR ...), and
Parameter Store the secrets, so nothing is generated twice. It leaves an
installed host's release to its upgrades; --reinstall copies this release
over it. Files you put in <INSTALL_DIR>/aws/<ENV>/local/ reach each
host's ~/yack/local/: local/demo-users.csv adds your own people to the demo dataset (see Loading
data). A directory is one deployment's, and a deployment can't change
between one host and three in place.
To ssh to a host, Systems Manager stands in for an open port. With the AWS
CLI's Session Manager plugin installed, add an entry per host to
~/.ssh/config, with HostName the instance id from YackHostsStack-<ENV>'s
outputs (HostInstanceId, or HostAInstanceId ... with three hosts):
Host yack.example.com
HostName i-0123456789abcdef0
User ec2-user
IdentityFile ~/.ssh/your-org-yack.pem
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p"
./aws-install.sh does everything that you would do on your own host:
settings, domain, certificate, start, timers and superadmin.
On your own host
Run everything from <INSTALL_DIR>, and always use its bin/ scripts
rather than calling docker compose directly — they source bin/env.sh, which derives a few settings (e.g.
DATABASE_URL, JANUS_API_URL) from your .env that plain docker compose up won't compute on its own. The certificate (2. Get a TLS
certificate) is the one exception, run with bin/env.sh sourced.
TL;DR
You need a Linux host or an Apple Mac with Docker (on a Mac, Docker Desktop with 12 GB of memory), a domain pointing at it, every port in Prerequisites reaching it, and a sign-in client: Google's, Microsoft's or both (Sign-in providers). Details in 1. Configure to 4. Make yourself a superadmin, and for a Mac, Mac specifics.
In <INSTALL_DIR>, with the common resources extracted (above):
# Your settings: copy the template, then edit .env as its opening comments say.
# Without AWS you also set REALM, LETSENCRYPT_EMAIL, the secrets (random
# strings: openssl rand -base64 48) and ATTACHMENTS_UNSCANNED=true (no S3 to
# scan uploads); on a Mac also UPGRADE_ENABLED=false, and PUBLIC_HTTP_PORT if
# the router forwards port 80 to another port
cp .env.example .env
# Once you've set REALM and the rest in .env, fit the config to your domain:
(. bin/env.sh && bin/localise.sh)
# A certificate, then Yack, then yourself as its superadmin
(. bin/env.sh && docker compose -f docker-compose-certbot.yml up --abort-on-container-exit)
bin/start.sh
bin/add-superadmin.sh you@example.com
# On Linux: timers for certificate renewal, backups and upgrades (uses sudo)
bin/install-timers.sh
On Linux, Yack then renews its certificate, backs up and upgrades itself. On
a Mac, upgrade with bin/upgrade-local.sh, and renew the certificate with
bin/renew-cert.sh every couple of months.
Prerequisites
- A Linux host, or an Apple Mac, with Docker and the Docker Compose plugin
(
docker compose versionshould print v2.x), and 8 GB of memory for Yack (transcription and the PII sidecar need most of it). - A DNS A record for your domain pointing at this host's public IP.
- Inbound access on TCP 80 and 443 (HTTP-01 cert challenge and the app
itself), TURN on 3478 (UDP/TCP), 5349 (TCP) and UDP 49160-49200, and
Janus media on UDP 10002-10200 (defaults; see
bin/env.sh). - A sign-in client: a Google Cloud OAuth 2.0 Client ID, a Microsoft Entra app registration, or both (Sign-in providers).
1. Configure
On a host of your own, in <INSTALL_DIR>, with the common resources extracted (above):
cp .env.example .env
Required settings in .env read VAR=${VAR:?message}; replace each with a
literal value, or leave it and export the value yourself (shell profile,
systemd EnvironmentFile, secrets manager). Anything missing stops the
bin/ scripts with an error naming it.
The required values, and where they come from:
REALM— the public domain this instance is served from.LETSENCRYPT_EMAIL— registered with Let's Encrypt for your certificate.MONGO_*— pick your own passwords; they provision the database on first boot.MONGOT_PASSWORD— another password of your own, for the search service's database user (see Database below).SECRET_KEY_BASE— generate one withopenssl rand -base64 48.- A sign-in provider, at least one:
GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET,MICROSOFT_CLIENT_ID/MICROSOFT_CLIENT_SECRET(Sign-in providers). JANUS_*_SECRET/TURN_SECRET— any random strings.
Database
MongoDB runs as MongoDB Community Edition with mongot, MongoDB's search
service, as two containers (docker-compose-mongo.yml); mongot needs
MONGOT_PASSWORD. The data lives in <INSTALL_DIR>/data/dbs/prod/, which
<INSTALL_DIR>/data/dbs/current links to. Keep the
disk well under 90% full: around there mongot pauses building search
indexes, leaving message search and @Yack without results.
Your domain
The nginx and coturn config ship with thoughtbreak.com as a placeholder
domain. With REALM set, fit them to it (./aws-install.sh does this for
you):
(. bin/env.sh && bin/localise.sh)
2. Get a TLS certificate
Before starting Yack for the first time, obtain a Let's Encrypt cert for
REALM (this needs port 80 reachable from the internet):
(. bin/env.sh && docker compose -f docker-compose-certbot.yml up --abort-on-container-exit)
This writes the certificate under <INSTALL_DIR>/etc/letsencrypt/live/<REALM>/, which
the nginx and TURN configs already point at.
Renewals: bin/renew-cert.sh re-runs certbot and reloads nginx. On Linux,
run bin/install-timers.sh (it uses sudo) to install the systemd timers
that renew daily, back up every 6 hours (Backups) and carry out upgrades
(Upgrades); ./aws-install.sh runs it for you. A Mac has no timers (Mac
specifics).
3. Start Yack
bin/start.sh
This brings up mongo, mongot, janus, turn, nginx, the pii and
media-processing sidecars, and the yack app itself. Check . bin/env.sh && dockercompose ps to confirm everything is healthy.
Stop with bin/stop.sh, restart with bin/restart.sh.
4. Make yourself a superadmin
Make yourself a superadmin, so you can sign in and administer Yack -
the account activates when you first sign in, and takes its
name from the address (jo.bloggs@ is Jo Bloggs):
bin/add-superadmin.sh you@example.com
Mac specifics
Yack runs on one Apple Mac with Docker Desktop, as on a Linux host:
its images are built for arm64 too, and on macOS bin/env.sh adds
docker-compose-mac.yml, which publishes Janus's and coturn's ports
rather than using Linux host networking. Follow 1. Configure onwards, in an
<INSTALL_DIR> of its own, with these differences:
- Docker Desktop needs at least 12 GB of memory (its Settings, Resources).
- Let's Encrypt's challenge always comes to port 80. If that isn't the
Mac's, forward the router's port 80 to another, say 90, and set
PUBLIC_HTTP_PORT=90. For people outside your network, the router also forwards to the Mac TCP 443, TURN's 3478 (UDP/TCP), 5349 (TCP) and UDP 49160-49200, and Janus's UDP 10002-10200, and the Mac mustn't sleep. - There are no systemd timers, so
bin/install-timers.shdoesn't apply: setUPGRADE_ENABLED=false, upgrade by hand withbin/upgrade-local.sh(Upgrades), and runbin/renew-cert.sh(the certificate lasts 90 days) and, withBACKUP_TARGETa directory,bin/backup.shyourself. - Attachments need S3 for malware scanning;
ATTACHMENTS_UNSCANNED=truekeeps them on the Mac's disk, unscanned, where you trust everyone who can upload.
Sign-in providers
People sign in with Google, with Microsoft (personal accounts, and work or school accounts), or with either: the welcome page offers each provider whose client is set. An admin adds each person by email address. The first sign-in links that provider's account to them, provided the provider has verified the address; later sign-ins find them by that account, and keep their email in step with the provider's. Admins can unlink an account in Manage users, for someone who changes accounts.
Google: in Google Cloud Console, APIs & Services, create an OAuth 2.0 Client
ID (Web application) with authorized redirect URI
https://<REALM>/auth/google/callback (add :<PUBLIC_YACK_PORT> if not
443), and set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
Microsoft (free with Microsoft Entra ID; any Azure account has a tenant): at entra.microsoft.com, App registrations, New registration:
- Supported account types: "Accounts in any organizational directory and
personal Microsoft accounts" (or narrower, matching
MICROSOFT_TENANT). - Redirect URI: Web,
https://<REALM>/auth/microsoft/callback(add:<PUBLIC_YACK_PORT>if not 443). - Certificates & secrets: a new client secret. It expires (24 months at most): renew it, and the setting, before then.
- Token configuration, Add optional claim, ID:
emailandxms_edov. The second says a work or school account's email domain is verified by its organisation; without it such accounts can't be matched by email, so can't sign in the first time. Personal accounts' addresses, confirmed by Microsoft, are trusted without it.
Set MICROSOFT_CLIENT_ID (the Application (client) ID) and
MICROSOFT_CLIENT_SECRET (the secret's value). MICROSOFT_TENANT (default
common) narrows who may sign in: organizations (work or school only),
consumers (personal only), or one directory's tenant id (only its people).
Out of office from Google Calendar
People can have their out of office come from their Google Calendar's out-of-office events instead of booking it in Yack, each choosing on the Out of office page. Yack reads only those events' times, never their titles, with each person's consent. It needs Google sign-in (above), on the same client:
- In Google Cloud Console, enable the Google Calendar API for the client's project.
- OAuth consent screen: user type Internal (your Google Workspace only), so
Google needn't review the calendar scope; add the scope
https://www.googleapis.com/auth/calendar.events.readonly. For its home page, privacy policy and terms of service it can take Yack's own,https://<REALM>/,https://<REALM>/docs/privacy.htmlandhttps://<REALM>/docs/terms.html, or your organisation's. - The client: add the authorized redirect URI
https://<REALM>/ooo/google/callback(with:<PUBLIC_YACK_PORT>if not 443). - Set
OOO_GOOGLE_SYNC_ENABLED=true.
Google tells Yack of changes at https://<REALM>/webhooks/google-calendar;
Yack also checks every 30 minutes, which is all an installation Google can't
reach over HTTPS gets.
Loading data
With Yack running and yourself its superadmin, load if you like the bundled synthetic demo dataset, or your own users and teams (on AWS, over ssh: On AWS, In detail):
# Demo data, with one real admin account (and any people of your own listed
# in <INSTALL_DIR>/local/demo-users.csv, in users.csv's columns, alongside the demo's):
bin/bootstrap-demo.sh you@example.com # then embeds its chat, so @Yack can draw on it
# Your own data, from CSV files anywhere on the host:
bin/bootstrap-users.sh teams.csv users.csv
teams.csv has the columns name,type,door_policy (type core or task;
door policy open, knock or locked, default knock); users.csv has
name,email,team,role,extra_teams (team the user's core team; role user,
admin or superadmin, default user; extra teams separated by ;). Both
are safe to re-run: teams match by name and users by email.
Stopping and starting
On AWS, ./aws-install.sh NAME --stop stops the installation's hosts, for
when it isn't needed for a while: their disks, the database, your settings
and its address are kept, and the hosts' compute is no longer charged (the
load balancer, addresses and disks still are). --start starts them again
and waits until Yack answers. In case of trouble, --restart does both:
the hosts turned off and on again, on fresh hardware.
Logs and support
On AWS, every host's logs go to CloudWatch Logs in your account, in the
log group /yack/<env> (or your --app in place of yack), one stream per
host and service, where Logs Insights searches them all at once. They can
hold personal data (names, sign-in email addresses, rooms), so they're kept
30 days, then deleted; RETENTION_LOGS in .env changes that (applied by
./aws-install.sh). Elsewhere, each host keeps its own: dockercompose logs.
Thoughtbreak's support has no access to your installation unless you grant
it, and then only what you grant, in your account, with every use in your
CloudTrail. In .env, then ./aws-install.sh:
SUPPORT_ACCESS=logs # read this installation's logs; or shell, to
# also open sessions on its hosts, each recorded
# to the /yack/<env>/sessions log group
SUPPORT_ACCESS_ACCOUNT=123456789012 # Thoughtbreak's AWS account, which we give you
SUPPORT_ACCESS_UNTIL=2026-12-31 # optional: it ends after this day
SUPPORT_ACCESS=off and ./aws-install.sh revoke it, as does deleting the
role yack-<env>-support in the IAM console.
Without AWS, run this on the host and send us the file it writes: each service's log (by default the last 24 hours), the release and the services' state, and the names, never the values, of your settings:
bin/support-bundle.sh [--since 24h]
Upgrades
The Release notes say what each release brings.
Yack upgrades itself. When the release tagged stable on Docker Hub
changes, the app plans an upgrade for your window (23:00-02:00 UTC by
default), with at least half an hour of it left and at a moment when nobody
is publishing audio or video and no recording is unfinished, and the
yack-upgrade timer (bin/install-timers.sh) carries it out: it pulls the
new images, backs up, stops Yack and saves its database, swaps the
release's files into <INSTALL_DIR> (never .env, data/ or
etc/letsencrypt/), restarts
and checks Yack answers, rolling back if it doesn't.
Every upgrade is a short outage, usually a minute or two. Some releases
also migrate the database, after which older releases refuse to start on
it; if such a release fails, the rollback restores the database saved
just before it, losing anything written in between (nobody can use Yack
then anyway). The saved database stays in <INSTALL_DIR>/.upgrade/db.archive.gz until
the next upgrade. Superadmins get a message with the outcome, including any new
settings to consider (described in .env.example); Upgrades in the
settings menu shows the latest. A new setting always has a default, and
a feature needing a new secret stays off until you set it.
UPGRADE_ENABLED=falseturns upgrades off.UPGRADE_TAG=main-140pins a release;stablefollows the latest.UPGRADE_WINDOW=23-2sets the window, in whole UTC hours, so at least one; equal hours (e.g.0-0) mean any time.- The agent's log:
journalctl -u yack-upgrade; its working files, and the files the last upgrade replaced, are in<INSTALL_DIR>/.upgrade/.
Yack never moves to an older release than it runs. On AWS, to upgrade now
rather than wait for the window (even with upgrades off), or to a
particular release, from <INSTALL_DIR> on the machine you installed from:
./aws-upgrade.sh prod [--release main-180]
It upgrades just as above, though not during a call or an unfinished recording, and follows the upgrade until it ends.
The timer needs to run bin/install-timers.sh with passwordless sudo to
refresh timers a release changes; without it, the upgrade notes that you
should run it yourself.
Where nothing upgrades unattended (a Mac, or UPGRADE_ENABLED=false), one
host upgrades by hand, in the same way and with the same rollback:
bin/upgrade-local.sh [main-190] # stable's release by default
It pulls the release's images (refusing ones not built for this machine,
or an older release than this one), backs up if BACKUP_TARGET is set,
stops Yack and saves its database to <INSTALL_DIR>/.upgrade/db.archive.gz,
swaps the release's files in (keeping the replaced ones in
<INSTALL_DIR>/.upgrade/previous),
restarts and waits for Yack to answer; if it doesn't, the files, and the
database if it was migrated, go back and the old release restarts. It
doesn't run the release's upgrade/run.sh, which is for Linux hosts.
Backups
Set BACKUP_TARGET in <INSTALL_DIR>/.env to an s3:// bucket or a directory, then
bin/backup.sh runs every 6 hours from the yack-backup timer
(bin/install-timers.sh): it writes a gzipped mongodump --oplog of the
whole instance, an archive of <INSTALL_DIR>/data/uploads and a copy of .env, stamped
with the time. On AWS, BACKUP_TARGET is the backups bucket, where they
expire after 14 days; otherwise expire old backups yourself, e.g. with a
bucket lifecycle rule, since they hold personal data. .env holds every
secret the installation needs, so encrypt the bucket (or keep the directory
private: backups there are written readable only by their owner).
bin/restore.sh [<STAMP>] restores the database and uploads from the latest
backup, or the one named, after asking; Yack recreates its search indexes
when it restarts. It leaves .env alone, so a backup can be restored onto
another host. bin/restore.sh --env [<STAMP>] restores only .env, keeping
the current one as <INSTALL_DIR>/.env.before-restore-<time>. To rebuild a
lost host: extract the common resources into a new <INSTALL_DIR>, write a
.env there with just REALM and BACKUP_TARGET, run
bin/restore.sh --env, then bin/start.sh and bin/restore.sh.