Initial commit

main
Jerry Aldrich 4 years ago
commit a3f2df9045
  1. 4
      .gitignore
  2. 317
      CHANGELOG.md
  3. 203
      LICENSE
  4. 42
      Makefile
  5. 19
      README.md
  6. 12
      base-java/Dockerfile
  7. 27
      base/Dockerfile
  8. 2
      base/rootfs/etc/apt/apt.conf.d/99local
  9. 0
      base/rootfs/etc/cont-finish.d/.gitkeep
  10. 0
      base/rootfs/etc/cont-init.d/.gitkeep
  11. 10
      base/rootfs/etc/cont-init.d/01-set-timezone
  12. 0
      base/rootfs/etc/fix-attrs.d/.gitkeep
  13. 0
      base/rootfs/etc/services.d/.gitkeep
  14. 7
      base/rootfs/fix-permissions.sh
  15. 10
      base/rootfs/install-devtools.sh
  16. 16
      base/rootfs/pre-init.sh
  17. 3
      base/rootfs/usr/bin/apt-cleanup
  18. 8
      base/rootfs/usr/bin/apt-dpkg-wrap
  19. 4
      base/rootfs/usr/bin/tpl
  20. 257
      docker-compose.yml
  21. 381
      env.example
  22. 16
      etherpad.yml
  23. 11
      examples/README.md
  24. 26
      examples/kubernetes/README.md
  25. 145
      examples/kubernetes/deployment.yaml
  26. 17
      examples/kubernetes/jvb-service.yaml
  27. 32
      examples/kubernetes/web-service.yaml
  28. 18
      examples/traefik-v2/README.md
  29. 269
      examples/traefik-v2/docker-compose.yml
  30. 17
      examples/traefik/README.md
  31. 180
      examples/traefik/docker-compose.yml
  32. 21
      gen-passwords.sh
  33. 36
      jibri.yml
  34. 53
      jibri/Dockerfile
  35. 60
      jibri/rootfs/defaults/config.json
  36. 33
      jibri/rootfs/defaults/logging.properties
  37. 60
      jibri/rootfs/etc/cont-init.d/10-config
  38. 4
      jibri/rootfs/etc/opt/chrome/policies/managed/managed_policies.json
  39. 5
      jibri/rootfs/etc/services.d/10-xorg/run
  40. 5
      jibri/rootfs/etc/services.d/20-icewm/run
  41. 9
      jibri/rootfs/etc/services.d/30-jibri/run
  42. 15
      jicofo/Dockerfile
  43. 143
      jicofo/rootfs/defaults/jicofo.conf
  44. 21
      jicofo/rootfs/defaults/logging.properties
  45. 24
      jicofo/rootfs/etc/cont-init.d/10-config
  46. 8
      jicofo/rootfs/etc/services.d/jicofo/run
  47. 50
      jigasi.yml
  48. 17
      jigasi/Dockerfile
  49. 18
      jigasi/rootfs/defaults/logging.properties
  50. 150
      jigasi/rootfs/defaults/sip-communicator.properties
  51. 50
      jigasi/rootfs/etc/cont-init.d/10-config
  52. 9
      jigasi/rootfs/etc/services.d/jigasi/run
  53. 15
      jvb/Dockerfile
  54. 65
      jvb/rootfs/defaults/jvb.conf
  55. 14
      jvb/rootfs/defaults/logging.properties
  56. 5
      jvb/rootfs/defaults/sip-communicator.properties
  57. 25
      jvb/rootfs/etc/cont-init.d/10-config
  58. 7
      jvb/rootfs/etc/services.d/jvb/run
  59. 70
      prosody/Dockerfile
  60. 184
      prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua
  61. 172
      prosody/rootfs/defaults/prosody.cfg.lua
  62. 26
      prosody/rootfs/defaults/saslauthd.conf
  63. 78
      prosody/rootfs/etc/cont-init.d/10-config
  64. 2
      prosody/rootfs/etc/sasl/xmpp.conf
  65. 2
      prosody/rootfs/etc/services.d/10-saslauthd/run
  66. 3
      prosody/rootfs/etc/services.d/prosody/run
  67. 27
      prosody/rootfs/prosodyctl-certdir-permission-fix.patch
  68. 72
      release.sh
  69. BIN
      resources/docker-jitsi-meet.png
  70. 1
      resources/docker-jitsi-meet.xml
  71. BIN
      resources/jitsi-docker.png
  72. 24
      web/Dockerfile
  73. 26
      web/rootfs/defaults/default
  74. 8
      web/rootfs/defaults/ffdhe2048.txt
  75. 92
      web/rootfs/defaults/meet.conf
  76. 67
      web/rootfs/defaults/nginx.conf
  77. 306
      web/rootfs/defaults/settings-config.js
  78. 28
      web/rootfs/defaults/ssl.conf
  79. 50
      web/rootfs/defaults/system-config.js
  80. 95
      web/rootfs/etc/cont-init.d/10-config
  81. 10
      web/rootfs/etc/services.d/cron/run
  82. 3
      web/rootfs/etc/services.d/nginx/run

4
.gitignore vendored

@ -0,0 +1,4 @@
*.swp
.env
.env.bak
docker-compose.override.yml

@ -0,0 +1,317 @@
## stable-5390-3
Based on stable release 5390-3.
* a698da5 misc: add jicofo reservation env variables to compose
* 86c3022 web: brandingDataUrl -> dynamicBrandingUrl
* 88e950d jicofo: fix healthcheck
* 493cbdd misc: fix typo
* e12d7f2 web : Add DESKTOP_SHARING_FRAMERATE_MIN and MAX env vars
* fa98a31 examples: fix k8s example
* 88d1034 doc: add port to PUBLIC_URL
* c876b40 doc: update CHANGELOG
* 5cf14b0 misc: working on latest
## stable-5390-2
Based on stable release 5390-2.
* 3e04fb4 prosody: fix lobby when authentication is enabled
* 24781e3 misc: working on latest
## stable-5390-1
Based on stable release 5390-1.
* 3ac5397 misc: working on latest
## stable-5390
Based on stable release 5390.
* 0f541c8 jicofo: migrate to new config
* 12823cb prosody: fix jibri recording websocket error
* 7594ea2 jigasi: add ability to control SIP default room for incoming calls
* b0e653a jigasi: fix when using authentication
* 4564170 misc: working on latest
## stable-5142-4
Based on stable release 5142-4.
* 6f7b2b4 prosody: add internal domain name to default cross-domains list
* ada7b95 jvb: fix check for JVB_TCP_HARVESTER_DISABLED
* a7fb101 jibri: don't provide a non-existing finalizer path
* d013053 jibri: add missing dependency for `kill` command
* 0b25141 web: Add ENABLE_HSTS flag to disable strict-transport-security header
* f856037 web: add more config options
* eedac14 web: add ability to disable IPv6
* af6f3ac doc: update CHANGELOG
* e3bb5c1 misc: working on latest
## stable-5142-3
**Important:** This release should fix some update problems users found in -1 and -2 versions. The main problem observed is the introduction of XMPP WebSockets, which requires extra configuration for the /xmpp-wesocket route if a reverse proxy is used in front of this setup. Pure docker-compose installations don't need any changes.
Based on stable release 5142-3.
* c2c6460 prosody: fix cross-domain WS default value
* 8261f72 jicofo,jigase: add ability to extend the config file
* 6a4887d web: use env variables to set worker processes and connections
* 5679578 prosody: add env var to config cross domain settings
* effb30b prosody: always rebuild configs on start
* 905d431 jicofo,jigasi: always rebuild configs on start
* c52b64a misc: working on latest
## stable-5142-2
Based on stable release 5142-2.
* 700c04a web: properly handle acme.sh return codes
* 4cb181c web: install acme certs to persistent storage
* 1d2c68a web: fix running acme.sh on the right home directory
* 5c44a84 misc: stop using apt-key, it's deprecated
* 5f06c3a doc: update CHANGELOG
* 0f780b4 misc: working on latest
## stable-5142-1
**Important:** This release includes 2 major changes: migrating the base image to Debian Buster and replacing certbot with acme.sh for getting Letś Encrypt certificates. Please report any problems you find!
Based on stable release 5142-1.
* b0cb4a1 web: update TLS config to Mozilla security guidelines
* 0601212 web: replace certbot with acme.sh
* 43f678d build: refactor Makefile
* b00f92a web: use Python 3 only for certbot
* 880b9b0 core: update base image to Debian Buster
* ba01190 web: prevent s6 from restarting cron if it shouldn't be run
* 42a4346 etherpad: use official image and making skin full width
* c36c4d0 web: always rebuild nginx configs on start
* aea4411 Adds private server.
* 6b69576 web: add ability to configure tokenAuthUrl
* ff6d9bc Fix websocket
* e5746ae misc: add ENABLE_PREJOIN_PAGE to .env
* 465816b web,prosody: turn on XMPP WebSocket by default
* d747bfb web,prosody: add XMPP WebSocket / Stream Management support
* 130eb55 jvb: migrate to new config file
* 5290499 doc: updated link for running behind NAT
* 7cb470c misc: support/encourage usage of ShellCheck
* 04a210f misc: working on latest
## stable-5142
Based on stable release 5142.
* 7ab45bb web: add ability to configure prejoin page
* 0c95794 jvb: regenerate config on every boot
* 3ef2221 jvb: add ability to set the WS domain with an env var
* 79d2601 jvb: add ability to specify set the WS_SERVER_ID with an env var
* b277926 jvb: make colibri websocket endpoints dynamic for multiple jvbs
* 991f695 web: remove no longer needed settings
* 8b7cbc3 revert "jicofo: no auth URL in JWT auth mode"
* 33b386b jvb: add missing variable to docker-compose
* 087f024 web: configure brandingDataUrl with env variables
* a404653 web: configure startAudioOnly using environment variable
* e195cbf jvb: make jvb apis available from outside the container
* 409cade web: configure Matomo using environment variables
* b731c60 doc: update CHANGELOG
* 0fbf3b7 misc: working on latest
## stable-5076
**Important:** Starting with this release config.js is autogenerated with every container boot.
In addition, bridge channels now using WebSocket. Some setups may break on upgrade.
Based on stable release 5076.
* 5ceaf5f web: add IPv6 support
* aff3775 xmpp: allow recorders to bypass lobby
* ad5625b jvb: switch to WebSocket based bridge channels
* 8110336 web: add ability to configure the nginx resolver
* 2f47518 jicofo: no auth URL in JWT auth mode
* c149463 web: build config.js on each boot
* c792bbc base: update frep
* bec928c prosody: configure lobby on the guest domain is necessary
* bcbd977 jicofo: pass XMPP_MUC_DOMAIN through docker-compose.yml
* 8f9caa4 jicofo: set XMPP_MUC_COMPONENT_PREFIX
* 2a0120d web: set security headers also for non HTTPS
* e6586f2 jvb: set LOCAL_ADDRESS to the correct local IP (#630)
* 97f5e75 base: optimize size
* b78c89e misc: minor Dockerfile Improvements
* a754519 misc: working on latest
## stable-4857
Based on stable release 4857.
* a81ad73 prosody: add support for lobby
* baed605 web: fix removing closed captions button if transcription is enabled
* edecacd etherpad: add ability to use a external server
* a7563d4 jvb: use JVB_TCP_PORT for exposing the port
* b235ea1 prosody: disable s2s module
* 1d428a8 prosody: use a 2-stage build
* 613c26c misc: working on latest
* 4d72ee3 release: stable-4627-1
* 22b7063 examples: update Traefik v1 example
* 1381b08 prosody: fix installing dependdencies
* 2900c11 misc: add extra line to tag message
* c57a84b misc: working on latest
## stable-4627-1
Based on stable release 4627-1.
* 1381b08 prosody: fix installing dependdencies
* 2900c11 misc: add extra line to tag message
* c57a84b misc: working on latest
## stable-4627
Based on stable release 4627.
* fdf5030 prosody: update configuration
* afafe23 prosody: shrink container size
* 8e7ea34 base: fix setting timezone
* 58441ae doc: update README
* 3c12526 etherpad: update to version 1.8.4
* 0038e71 jibri: install extra dependency
* 0615ed6 doc: add missing volumes to quick start
* 2781865 doc: clarify usage of gen-passwords.sh
* a8d0b6c build: add PHONY target for "release"
* d4a35a6 misc: working on latest
## stable-4548-1
Based on stable release 4548-1.
* abf2f73 jicofo: fix setting incorrect auth URL scheme for JWT
* 3472ab0 jicofo: add ability to configure health checks
* ec3622b jibri: install jitsi-upload-integrations by default
* 0e7bc91 etherpad: pin image version
* 4fa50b9 jwt: do not load token_verification module with disabled authentication
* b0d76a2 jibri: add jq dep for upload integrations
* 53b58fd jvb: add jq, curl deps for graceful_shutdown.sh
* 2d063ad doc: update installation instructions
* e73df5f misc: working on latest
## stable-4548
Based on stable release 4548.
* a79fc0c misc: add release script
* 0f0adc8 compose: add image tag to compose files
* 0177765 misc: fix config volumes to work with SELinux
* eae3f5c jibri: chrome/driver 78 as a stopgap
* 78df6a4 doc: delete unnecessary dot
* 4426ed8 jibri: fix case when /dev/snd is not bound (https://github.com/jitsi/docker-jitsi-meet/issues/240#issuecomment-610422404)
* 125775a web: fix WASM MIME type
* e70975e web: enable GZIP compression for more file types
* 774aba5 misc: set ddefault timezone to UTC
* 3c3fc19 prosody: enable speaker stats and conferene duration modules
* f911df2 jvb: set JVB_TCP_MAPPED_PORT default value
* 1205170 jvb: allow `TCP_HARVESTER_MAPPED_PORT` to be configured
* f7796a1 prosody: add volume /prosody-plugins-custom to docker-compose
* d44230e prosody: use hashed xmpp auth
## stable-4416
Based on stable release 4416.
* b039b29 web: use certbot-auto
* b95c95d web: improve nginx configuration
* 2dd6b99 k8s: specify namespace for secret
* 7aa2d81 ldap: avoid unnecessary copy
* e1b47db exampless: update Traefik v2 example with UDP
* 0940605 doc: fix typos and minor grammar issues in README
* 1c4b11c doc: correct minor mistake
* c06867b doc: added steps for updating kernel manually in AWS installation
* dc46215 web: remove DHE suites support
* 367621f prosody: remove no longer needed patch
* 34e6601 doc: clarify acronym
* 2c95ab7 web: revert using PUBLIC_URL for BOSH URL
* 7fd7e2b Add docker-compose.override.yml to .gitignore (#438)
* 67a941b misc: update gen-passwords.sh shell code
* 4e2cec6 misc: add configurable service restart policy
* 729f9d2 doc: fix typo in env.example
## stable-4384(-1)
**Important security note:** Previous releases included default passwords for
system accounts, and users who didn't change them are at risk of getting
the authentication system circumvented by an attacker using a system account
with the default password. Please update and use the provided script
(instructions on the README) to generate a strong password for each system
account.
Thanks joernchen for the security report.
<hr/>
Based on stable release 4384.
* 768b6c4 security: fail to start if using the old default password
* 1ffd472 security: add script to generate strong passwords
* a015710 security: don't provide default passwords
* aaec22d jigasi: fix typo in config
* ebfa142 docs: fix grammar and typos
* bab77e0 doc: update env.example
* 7652807 examples: traefik v2
* 10983b4 prosody: prevent item-not-found error in certain cases
* 3524a52 base: fail to start the container if the init script fails
* 7c0c795 jicofo: only configure Jigasi brewery if Jigasi is configured
* 40c2920 build: add prepare command
* 93ba770 prosody: fix installing prosody from the right repository
* 3c07d76 doc: improve wording of README
* ed410d9 doc: fix typo
* fabfb2a doc: fix typo
* 5e6face web: use PUBLIC_URL for etherpaad base and BOSH URLs
* 264df04 jvb: switch to using Jitsi's STUN server by default
* 655cf6b web,prosody,jvb: prepare for new stable release
* ebb4536 doc: update CHANGELOG
* 06c3a83 doc: fix references to running behind NAT in the README
## stable-4101-2
Based on stable release 4101.
* b15bb28 prosody: update to latest stable version
* 75cb31b doc: add build instructions to README
* 25dbde9 doc: fix typo
* badc2d4 doc: add examples/README
* f6f6ca6 Merge branch 'dev'
* 52a1449 doc: clarify DOCKER_HOST_ADDRESS
* f26c9e6 prosody: fix ldap config template
* cd4a071 web: check for certbot's success and exit in case of a failure
* dea8d6c doc: fix typo
* 573c6fa doc: update diagrams
* 29125fd examples: add minimal example to run jitsi behind traefik
## stable-4101-1
Based on stable release 4101.
* b0def9a prosody: use epoll backend
* 8fa9f94 web: update nginx config from upstream
* 2f17380 doc: clarify account registration command
* edfd8f2 ldap: actually fix anonymous binds (Fixes #234)
* f4ac7cc misc: remove bogus quotation marks
* 0a68be1 jibri: start once jicofo has started
* 76acc65 doc: add tip re. ports to open on firewall to README
* e92a00c ldap: fix anonymous binds
* df40447 ldap: add option for ldap starttls support
* 1ebc535 doc: make localhost link in README clickable
* 33abdf3 doc: add mkdir -p ~/.jitsi-meet-cfg/... to README
* 2c93dce doc: fix typo in README
* d7bb2e6 doc: clarify HTTP vs HTTPS in README
* a1df1e0 Revert "prosody: fix restart loop on rolling deployment"
* 986071b jigasi: add missing transcription volumes to dockerfile
* 01eca74 jigasi: generate google cloud credentials from env vars
* cc2c042 prosody: fix restart loop on rolling deployment
* 5423a8a examples: adding simple kubernetes example
* 6eebabd jicofo: set owner jicofo rights for /config directory
* 69ba9ff jigasi: Updates jigasi client default options.
* 2b9a13b jicofo: add support of reservation REST API
* 8bfe7fb jicofo: add support of reservation REST API
* 9b17c05 web: fix letsencrypt renewal
* 6234a18 web: fix letsencrypt renewal

@ -0,0 +1,203 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,42 @@
FORCE_REBUILD ?= 0
JITSI_RELEASE ?= stable
JITSI_BUILD ?= latest
JITSI_REPO ?= jitsi
JITSI_SERVICES ?= base base-java web prosody jicofo jvb jigasi jibri
BUILD_ARGS := --build-arg JITSI_REPO=$(JITSI_REPO) --build-arg JITSI_RELEASE=$(JITSI_RELEASE)
ifeq ($(FORCE_REBUILD), 1)
BUILD_ARGS := $(BUILD_ARGS) --no-cache
endif
all: build-all
release: tag-all push-all
build:
docker build $(BUILD_ARGS) --progress plain --tag $(JITSI_REPO)/$(JITSI_SERVICE) $(JITSI_SERVICE)/
$(addprefix build_,$(JITSI_SERVICES)):
$(MAKE) --no-print-directory JITSI_SERVICE=$(patsubst build_%,%,$@) build
tag:
docker tag $(JITSI_REPO)/$(JITSI_SERVICE):latest $(JITSI_REPO)/$(JITSI_SERVICE):$(JITSI_BUILD)
push:
docker push $(JITSI_REPO)/$(JITSI_SERVICE):latest
docker push $(JITSI_REPO)/$(JITSI_SERVICE):$(JITSI_BUILD)
%-all:
@$(foreach SERVICE, $(JITSI_SERVICES), $(MAKE) --no-print-directory JITSI_SERVICE=$(SERVICE) $(subst -all,;,$@))
clean:
docker-compose stop
docker-compose rm
docker network prune
prepare:
docker pull debian:buster-slim
FORCE_REBUILD=1 $(MAKE)
.PHONY: all build tag push clean prepare release $(addprefix build_,$(JITSI_SERVICES))

@ -0,0 +1,19 @@
# Jitsi Meet on Docker
![](resources/jitsi-docker.png)
[Jitsi](https://jitsi.org/) is a set of Open Source projects that allows you to easily build and deploy secure videoconferencing solutions.
[Jitsi Meet](https://jitsi.org/jitsi-meet/) is a fully encrypted, 100% Open Source video conferencing solution that you can use all day, every day, for free — with no account needed.
This repository contains the necessary tools to run a Jitsi Meet stack on [Docker](https://www.docker.com) using [Docker Compose](https://docs.docker.com/compose/).
## Installation
The installation manual is available [here](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker).
## TODO
* Support container replicas (where applicable).
* TURN server.

@ -0,0 +1,12 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base
ENV JAVA_SYS_PROPS "-Djava.util.prefs.userRoot=/root"
RUN \
mkdir -p /usr/share/man/man1 && \
wget -q https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public -O /etc/apt/trusted.gpg.d/openjdk.asc && \
echo "deb https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ buster main" > /etc/apt/sources.list.d/openjdk.list && \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y adoptopenjdk-8-hotspot-jre && \
apt-cleanup

@ -0,0 +1,27 @@
FROM debian:buster-slim
ARG JITSI_RELEASE=stable
ARG FREP_VERSION=1.3.11
ENV S6_READ_ONLY_ROOT 1
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2
COPY rootfs /
RUN \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y apt-transport-https apt-utils ca-certificates gnupg wget && \
wget -qO - https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz | tar xfz - -C / && \
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key -O /etc/apt/trusted.gpg.d/jitsi.asc && \
wget -q https://github.com/subchen/frep/releases/download/v$FREP_VERSION/frep-$FREP_VERSION-linux-amd64 -O /usr/bin/frep && \
echo "deb https://download.jitsi.org $JITSI_RELEASE/" > /etc/apt/sources.list.d/jitsi.list && \
echo "deb http://ftp.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/backports.list && \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get dist-upgrade -y && \
apt-cleanup && \
chmod +x /usr/bin/frep && \
/install-devtools.sh
RUN mkdir /config
ENTRYPOINT [ "/pre-init.sh" ]

@ -0,0 +1,2 @@
APT::Install-Recommends "false";
APT::Install-Suggests "false";

@ -0,0 +1,10 @@
#!/usr/bin/with-contenv bash
if [[ ! -z "$TZ" ]]; then
if [[ -f /usr/share/zoneinfo/$TZ ]]; then
ln -sf /usr/share/zoneinfo/$TZ /etc/localtime
echo "$TZ" > /etc/timezone
else
echo "WARNING: $TZ is not a valid time zone."
fi
fi

@ -0,0 +1,7 @@
#!/bin/bash
chown 1001:0 -R /config /var/log /var/lib /etc/jitsi
chmod g=u -R /config /var/log /var/lib /etc/localtime /etc/timezone /etc/s6 /etc/jitsi /etc/passwd /run /root /usr/bin
# File should delete itself
rm -- "$0"

@ -0,0 +1,10 @@
#!/bin/bash
if [[ "$JITSI_RELEASE" == "unstable" ]]; then
apt-dpkg-wrap apt-get update;
apt-dpkg-wrap apt-get install -y jq procps curl vim iputils-ping net-tools;
apt-cleanup;
fi
# File should delete itself
rm -- "$0"

@ -0,0 +1,16 @@
#!/bin/sh
# set user for s6
sed -i "s/\${3}/$(id -u)/g" /usr/bin/fix-attrs
# workaround around mounts taking too much time
while ! mkdir -p /run/s6; do sleep 1; done
# set username
if ! whoami > /dev/null 2>&1; then
if [ -w /etc/passwd ]; then
echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd
fi
fi
exec /init

@ -0,0 +1,3 @@
#!/bin/sh
rm -rf /var/lib/apt/lists/

@ -0,0 +1,8 @@
#!/bin/sh
export LC_ALL=C
export DEBIAN_FRONTEND=noninteractive
bin=$1
shift
exec "$bin" "$@"

@ -0,0 +1,4 @@
#!/bin/bash
exec frep $1:-

@ -0,0 +1,257 @@
version: '3'
services:
# Frontend
web:
image: jitsi/web:latest
restart: ${RESTART_POLICY}
ports:
- '${HTTP_PORT}:8080'
- '${HTTPS_PORT}:4443'
volumes:
- ${CONFIG}/web:/config:Z
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z
environment:
- ENABLE_LETSENCRYPT
- ENABLE_HTTP_REDIRECT
- ENABLE_HSTS
- ENABLE_XMPP_WEBSOCKET
- DISABLE_HTTPS
- LETSENCRYPT_DOMAIN
- LETSENCRYPT_EMAIL
- LETSENCRYPT_USE_STAGING
- PUBLIC_URL
- TZ
- AMPLITUDE_ID
- ANALYTICS_SCRIPT_URLS
- ANALYTICS_WHITELISTED_EVENTS
- BRIDGE_CHANNEL
- CALLSTATS_CUSTOM_SCRIPT_URL
- CALLSTATS_ID
- CALLSTATS_SECRET
- CHROME_EXTENSION_BANNER_JSON
- CONFCODE_URL
- CONFIG_EXTERNAL_CONNECT
- DEPLOYMENTINFO_ENVIRONMENT
- DEPLOYMENTINFO_ENVIRONMENT_TYPE
- DEPLOYMENTINFO_USERREGION
- DIALIN_NUMBERS_URL
- DIALOUT_AUTH_URL
- DIALOUT_CODES_URL
- DROPBOX_APPKEY
- DROPBOX_REDIRECT_URI
- DYNAMIC_BRANDING_URL
- ENABLE_AUDIO_PROCESSING
- ENABLE_AUTH
- ENABLE_CALENDAR
- ENABLE_FILE_RECORDING_SERVICE
- ENABLE_FILE_RECORDING_SERVICE_SHARING
- ENABLE_GUESTS
- ENABLE_IPV6
- ENABLE_LIPSYNC
- ENABLE_NO_AUDIO_DETECTION
- ENABLE_P2P
- ENABLE_PREJOIN_PAGE
- ENABLE_WELCOME_PAGE
- ENABLE_CLOSE_PAGE
- ENABLE_RECORDING
- ENABLE_REMB
- ENABLE_REQUIRE_DISPLAY_NAME
- ENABLE_SIMULCAST
- ENABLE_STATS_ID
- ENABLE_STEREO
- ENABLE_SUBDOMAINS
- ENABLE_TALK_WHILE_MUTED
- ENABLE_TCC
- ENABLE_TRANSCRIPTIONS
- ETHERPAD_PUBLIC_URL
- ETHERPAD_URL_BASE
- GOOGLE_ANALYTICS_ID
- GOOGLE_API_APP_CLIENT_ID
- INVITE_SERVICE_URL
- JICOFO_AUTH_USER
- MATOMO_ENDPOINT
- MATOMO_SITE_ID
- MICROSOFT_API_APP_CLIENT_ID
- NGINX_RESOLVER
- NGINX_WORKER_PROCESSES
- NGINX_WORKER_CONNECTIONS
- PEOPLE_SEARCH_URL
- RESOLUTION
- RESOLUTION_MIN
- RESOLUTION_WIDTH
- RESOLUTION_WIDTH_MIN
- START_AUDIO_ONLY
- START_AUDIO_MUTED
- DISABLE_AUDIO_LEVELS
- ENABLE_NOISY_MIC_DETECTION
- START_BITRATE
- DESKTOP_SHARING_FRAMERATE_MIN
- DESKTOP_SHARING_FRAMERATE_MAX
- START_VIDEO_MUTED
- TESTING_CAP_SCREENSHARE_BITRATE
- TESTING_OCTO_PROBABILITY
- XMPP_AUTH_DOMAIN
- XMPP_BOSH_URL_BASE
- XMPP_DOMAIN
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_RECORDER_DOMAIN
- TOKEN_AUTH_URL
networks:
meet.jitsi:
aliases:
- ${XMPP_DOMAIN}
# XMPP server
prosody:
image: jitsi/prosody:latest
restart: ${RESTART_POLICY}
expose:
- '5222'
- '5347'
- '5280'
volumes:
- ${CONFIG}/prosody/config:/config:Z
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
environment:
- AUTH_TYPE
- ENABLE_AUTH
- ENABLE_GUESTS
- ENABLE_LOBBY
- ENABLE_XMPP_WEBSOCKET
- GLOBAL_MODULES
- GLOBAL_CONFIG
- LDAP_URL
- LDAP_BASE
- LDAP_BINDDN
- LDAP_BINDPW
- LDAP_FILTER
- LDAP_AUTH_METHOD
- LDAP_VERSION
- LDAP_USE_TLS
- LDAP_TLS_CIPHERS
- LDAP_TLS_CHECK_PEER
- LDAP_TLS_CACERT_FILE
- LDAP_TLS_CACERT_DIR
- LDAP_START_TLS
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_MODULES
- XMPP_MUC_MODULES
- XMPP_INTERNAL_MUC_MODULES
- XMPP_RECORDER_DOMAIN
- XMPP_CROSS_DOMAIN
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JIGASI_XMPP_USER
- JIGASI_XMPP_PASSWORD
- JIBRI_XMPP_USER
- JIBRI_XMPP_PASSWORD
- JIBRI_RECORDER_USER
- JIBRI_RECORDER_PASSWORD
- JWT_APP_ID
- JWT_APP_SECRET
- JWT_ACCEPTED_ISSUERS
- JWT_ACCEPTED_AUDIENCES
- JWT_ASAP_KEYSERVER
- JWT_ALLOW_EMPTY
- JWT_AUTH_TYPE
- JWT_TOKEN_AUTH_MODULE
- LOG_LEVEL
- PUBLIC_URL
- TZ
networks:
meet.jitsi:
aliases:
- ${XMPP_SERVER}
# Focus component
jicofo:
image: jitsi/jicofo:latest
restart: ${RESTART_POLICY}
volumes:
- ${CONFIG}/jicofo:/config:Z
environment:
- AUTH_TYPE
- BRIDGE_AVG_PARTICIPANT_STRESS
- BRIDGE_STRESS_THRESHOLD
- ENABLE_AUTH
- ENABLE_AUTO_OWNER
- ENABLE_CODEC_VP8
- ENABLE_CODEC_VP9
- ENABLE_CODEC_H264
- ENABLE_RECORDING
- ENABLE_SCTP
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS
- JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT
- JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT
- JICOFO_ENABLE_HEALTH_CHECKS
- JICOFO_SHORT_ID
- JICOFO_RESERVATION_ENABLED
- JICOFO_RESERVATION_REST_BASE_URL
- JIBRI_BREWERY_MUC
- JIBRI_REQUEST_RETRIES
- JIBRI_PENDING_TIMEOUT
- JIGASI_BREWERY_MUC
- JIGASI_SIP_URI
- JVB_BREWERY_MUC
- MAX_BRIDGE_PARTICIPANTS
- OCTO_BRIDGE_SELECTION_STRATEGY
- TZ
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_SERVER
depends_on:
- prosody
networks:
meet.jitsi:
# Video bridge
jvb:
image: jitsi/jvb:latest
restart: ${RESTART_POLICY}
ports:
- '${JVB_PORT}:${JVB_PORT}/udp'
- '${JVB_TCP_PORT}:${JVB_TCP_PORT}'
volumes:
- ${CONFIG}/jvb:/config:Z
environment:
- DOCKER_HOST_ADDRESS
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_SERVER
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JVB_BREWERY_MUC
- JVB_PORT
- JVB_TCP_HARVESTER_DISABLED
- JVB_TCP_PORT
- JVB_TCP_MAPPED_PORT
- JVB_STUN_SERVERS
- JVB_ENABLE_APIS
- JVB_WS_DOMAIN
- JVB_WS_SERVER_ID
- PUBLIC_URL
- TZ
depends_on:
- prosody
networks:
meet.jitsi:
aliases:
- jvb.meet.jitsi
# Custom network so all services can communicate using a FQDN
networks:
meet.jitsi:

@ -0,0 +1,381 @@
# shellcheck disable=SC2034
# Security
#
# Set these to strong passwords to avoid intruders from impersonating a service account
# The service(s) won't start unless these are specified
# Running ./gen-passwords.sh will update .env with strong passwords
# You may skip the Jigasi and Jibri passwords if you are not using those
# DO NOT reuse passwords
#
# XMPP component password for Jicofo
JICOFO_COMPONENT_SECRET=
# XMPP password for Jicofo client connections
JICOFO_AUTH_PASSWORD=
# XMPP password for JVB client connections
JVB_AUTH_PASSWORD=
# XMPP password for Jigasi MUC client connections
JIGASI_XMPP_PASSWORD=
# XMPP recorder password for Jibri client connections
JIBRI_RECORDER_PASSWORD=
# XMPP password for Jibri client connections
JIBRI_XMPP_PASSWORD=
#
# Basic configuration options
#
# Directory where all configuration will be stored
CONFIG=~/.jitsi-meet-cfg
# Exposed HTTP port
HTTP_PORT=8000
# Exposed HTTPS port
HTTPS_PORT=8443
# System time zone
TZ=UTC
# Public URL for the web service (required)
#PUBLIC_URL=https://meet.example.com:8443
# IP address of the Docker host
# See the "Running behind NAT or on a LAN environment" section in the Handbook:
# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker#running-behind-nat-or-on-a-lan-environment
#DOCKER_HOST_ADDRESS=192.168.1.1
# Control whether the lobby feature should be enabled or not
#ENABLE_LOBBY=1
# Show a prejoin page before entering a conference
#ENABLE_PREJOIN_PAGE=0
# Enable the welcome page
#ENABLE_WELCOME_PAGE=1
# Enable the close page
#ENABLE_CLOSE_PAGE=0
# Disable measuring of audio levels
#DISABLE_AUDIO_LEVELS=0
# Enable noisy mic detection
#ENABLE_NOISY_MIC_DETECTION=1
#
# Let's Encrypt configuration
#
# Enable Let's Encrypt certificate generation
#ENABLE_LETSENCRYPT=1
# Domain for which to generate the certificate
#LETSENCRYPT_DOMAIN=meet.example.com
# E-Mail for receiving important account notifications (mandatory)
#LETSENCRYPT_EMAIL=alice@atlanta.net
# Use the staging server (for avoiding rate limits while testing)
#LETSENCRYPT_USE_STAGING=1
#
# Etherpad integration (for document sharing)
#
# Set etherpad-lite URL in docker local network (uncomment to enable)
#ETHERPAD_URL_BASE=http://etherpad.meet.jitsi:9001
# Set etherpad-lite public URL (uncomment to enable)
#ETHERPAD_PUBLIC_URL=https://etherpad.my.domain
# Name your etherpad instance!
ETHERPAD_TITLE=Video Chat
# The default text of a pad
ETHERPAD_DEFAULT_PAD_TEXT=Welcome to Web Chat!\n\n
# Name of the skin for etherpad
ETHERPAD_SKIN_NAME=colibris
# Skin variants for etherpad
ETHERPAD_SKIN_VARIANTS=super-light-toolbar super-light-editor light-background full-width-editor
#
# Basic Jigasi configuration options (needed for SIP gateway support)
#
# SIP URI for incoming / outgoing calls
#JIGASI_SIP_URI=test@sip2sip.info
# Password for the specified SIP account as a clear text
#JIGASI_SIP_PASSWORD=passw0rd
# SIP server (use the SIP account domain if in doubt)
#JIGASI_SIP_SERVER=sip2sip.info
# SIP server port
#JIGASI_SIP_PORT=5060
# SIP server transport
#JIGASI_SIP_TRANSPORT=UDP
#
# Authentication configuration (see handbook for details)
#
# Enable authentication
#ENABLE_AUTH=1
# Enable guest access
#ENABLE_GUESTS=1
# Select authentication type: internal, jwt or ldap
#AUTH_TYPE=internal
# JWT authentication
#
# Application identifier
#JWT_APP_ID=my_jitsi_app_id
# Application secret known only to your token
#JWT_APP_SECRET=my_jitsi_app_secret
# (Optional) Set asap_accepted_issuers as a comma separated list
#JWT_ACCEPTED_ISSUERS=my_web_client,my_app_client
# (Optional) Set asap_accepted_audiences as a comma separated list
#JWT_ACCEPTED_AUDIENCES=my_server1,my_server2
# LDAP authentication (for more information see the Cyrus SASL saslauthd.conf man page)
#
# LDAP url for connection
#LDAP_URL=ldaps://ldap.domain.com/
# LDAP base DN. Can be empty
#LDAP_BASE=DC=example,DC=domain,DC=com
# LDAP user DN. Do not specify this parameter for the anonymous bind
#LDAP_BINDDN=CN=binduser,OU=users,DC=example,DC=domain,DC=com
# LDAP user password. Do not specify this parameter for the anonymous bind
#LDAP_BINDPW=LdapUserPassw0rd
# LDAP filter. Tokens example:
# %1-9 - if the input key is user@mail.domain.com, then %1 is com, %2 is domain and %3 is mail
# %s - %s is replaced by the complete service string
# %r - %r is replaced by the complete realm string
#LDAP_FILTER=(sAMAccountName=%u)
# LDAP authentication method
#LDAP_AUTH_METHOD=bind
# LDAP version
#LDAP_VERSION=3
# LDAP TLS using
#LDAP_USE_TLS=1
# List of SSL/TLS ciphers to allow
#LDAP_TLS_CIPHERS=SECURE256:SECURE128:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC
# Require and verify server certificate
#LDAP_TLS_CHECK_PEER=1
# Path to CA cert file. Used when server certificate verify is enabled
#LDAP_TLS_CACERT_FILE=/etc/ssl/certs/ca-certificates.crt
# Path to CA certs directory. Used when server certificate verify is enabled
#LDAP_TLS_CACERT_DIR=/etc/ssl/certs
# Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps://
# LDAP_START_TLS=1
#
# Advanced configuration options (you generally don't need to change these)
#
# Internal XMPP domain
XMPP_DOMAIN=meet.jitsi
# Internal XMPP server
XMPP_SERVER=xmpp.meet.jitsi
# Internal XMPP server URL
XMPP_BOSH_URL_BASE=http://xmpp.meet.jitsi:5280
# Internal XMPP domain for authenticated services
XMPP_AUTH_DOMAIN=auth.meet.jitsi
# XMPP domain for the MUC
XMPP_MUC_DOMAIN=muc.meet.jitsi
# XMPP domain for the internal MUC used for jibri, jigasi and jvb pools
XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
# XMPP domain for unauthenticated users
XMPP_GUEST_DOMAIN=guest.meet.jitsi
# Comma separated list of domains for cross domain policy or "true" to allow all
# The PUBLIC_URL is always allowed
#XMPP_CROSS_DOMAIN=true
# Custom Prosody modules for XMPP_DOMAIN (comma separated)
XMPP_MODULES=
# Custom Prosody modules for MUC component (comma separated)
XMPP_MUC_MODULES=
# Custom Prosody modules for internal MUC component (comma separated)
XMPP_INTERNAL_MUC_MODULES=
# MUC for the JVB pool
JVB_BREWERY_MUC=jvbbrewery
# XMPP user for JVB client connections
JVB_AUTH_USER=jvb
# STUN servers used to discover the server's public IP
JVB_STUN_SERVERS=meet-jit-si-turnrelay.jitsi.net:443
# Media port for the Jitsi Videobridge
JVB_PORT=10000
# TCP Fallback for Jitsi Videobridge for when UDP isn't available
JVB_TCP_HARVESTER_DISABLED=true
JVB_TCP_PORT=4443
JVB_TCP_MAPPED_PORT=4443
# A comma separated list of APIs to enable when the JVB is started [default: none]
# See https://github.com/jitsi/jitsi-videobridge/blob/master/doc/rest.md for more information
#JVB_ENABLE_APIS=rest,colibri
# XMPP user for Jicofo client connections.
# NOTE: this option doesn't currently work due to a bug
JICOFO_AUTH_USER=focus
# Base URL of Jicofo's reservation REST API
#JICOFO_RESERVATION_REST_BASE_URL=http://reservation.example.com
# Enable Jicofo's health check REST API (http://<jicofo_base_url>:8888/about/health)
#JICOFO_ENABLE_HEALTH_CHECKS=true
# XMPP user for Jigasi MUC client connections
JIGASI_XMPP_USER=jigasi
# MUC name for the Jigasi pool
JIGASI_BREWERY_MUC=jigasibrewery
# Minimum port for media used by Jigasi
JIGASI_PORT_MIN=20000
# Maximum port for media used by Jigasi
JIGASI_PORT_MAX=20050
# Enable SDES srtp
#JIGASI_ENABLE_SDES_SRTP=1
# Keepalive method
#JIGASI_SIP_KEEP_ALIVE_METHOD=OPTIONS
# Health-check extension
#JIGASI_HEALTH_CHECK_SIP_URI=keepalive
# Health-check interval
#JIGASI_HEALTH_CHECK_INTERVAL=300000
#
# Enable Jigasi transcription
#ENABLE_TRANSCRIPTIONS=1
# Jigasi will record audio when transcriber is on [default: false]
#JIGASI_TRANSCRIBER_RECORD_AUDIO=true
# Jigasi will send transcribed text to the chat when transcriber is on [default: false]
#JIGASI_TRANSCRIBER_SEND_TXT=true
# Jigasi will post an url to the chat with transcription file [default: false]
#JIGASI_TRANSCRIBER_ADVERTISE_URL=true
# Credentials for connect to Cloud Google API from Jigasi
# Please read https://cloud.google.com/text-to-speech/docs/quickstart-protocol
# section "Before you begin" paragraph 1 to 5
# Copy the values from the json to the related env vars
#GC_PROJECT_ID=
#GC_PRIVATE_KEY_ID=
#GC_PRIVATE_KEY=
#GC_CLIENT_EMAIL=
#GC_CLIENT_ID=
#GC_CLIENT_CERT_URL=
# Enable recording
#ENABLE_RECORDING=1
# XMPP domain for the jibri recorder
XMPP_RECORDER_DOMAIN=recorder.meet.jitsi
# XMPP recorder user for Jibri client connections
JIBRI_RECORDER_USER=recorder
# Directory for recordings inside Jibri container
JIBRI_RECORDING_DIR=/config/recordings
# The finalizing script. Will run after recording is complete
#JIBRI_FINALIZE_RECORDING_SCRIPT_PATH=/config/finalize.sh
# XMPP user for Jibri client connections
JIBRI_XMPP_USER=jibri
# MUC name for the Jibri pool
JIBRI_BREWERY_MUC=jibribrewery
# MUC connection timeout
JIBRI_PENDING_TIMEOUT=90
# When jibri gets a request to start a service for a room, the room
# jid will look like: roomName@optional.prefixes.subdomain.xmpp_domain
# We'll build the url for the call by transforming that into:
# https://xmpp_domain/subdomain/roomName
# So if there are any prefixes in the jid (like jitsi meet, which
# has its participants join a muc at conference.xmpp_domain) then
# list that prefix here so it can be stripped out to generate
# the call url correctly
JIBRI_STRIP_DOMAIN_JID=muc
# Directory for logs inside Jibri container
JIBRI_LOGS_DIR=/config/logs
# Disable HTTPS: handle TLS connections outside of this setup
#DISABLE_HTTPS=1
# Redirect HTTP traffic to HTTPS
# Necessary for Let's Encrypt, relies on standard HTTPS port (443)
#ENABLE_HTTP_REDIRECT=1
# Send a `strict-transport-security` header to force browsers to use
# a secure and trusted connection. Recommended for production use.
# Defaults to 1 (send the header).
# ENABLE_HSTS=1
# Enable IPv6
# Provides means to disable IPv6 in environments that don't support it (get with the times, people!)
#ENABLE_IPV6=1
# Container restart policy
# Defaults to unless-stopped
RESTART_POLICY=unless-stopped
# Authenticate using external service or just focus external auth window if there is one already.
# TOKEN_AUTH_URL=https://auth.meet.example.com/{room}

@ -0,0 +1,16 @@
version: '3'
services:
# Etherpad: real-time collaborative document editing
etherpad:
image: etherpad/etherpad:1.8.6
restart: ${RESTART_POLICY}
environment:
- TITLE=${ETHERPAD_TITLE}
- DEFAULT_PAD_TEXT=${ETHERPAD_DEFAULT_PAD_TEXT}
- SKIN_NAME=${ETHERPAD_SKIN_NAME}
- SKIN_VARIANTS=${ETHERPAD_SKIN_VARIANTS}
networks:
meet.jitsi:
aliases:
- etherpad.meet.jitsi

@ -0,0 +1,11 @@
# Community Examples
The examples contained in this directory have been provided by the community
and allow users to run the container setup in scenarios other than the
default one (using Docker Compose).
Since they are maintained by the community, they may not provide the same
features as the default setup.
No support is provided for these, but if you found a bug and can fix it
we'll be happy to accept a Pull-Request to fix it!

@ -0,0 +1,26 @@
# Install guide for kubernetes
This guide will deploy jitsi in the most simple way: as several containers in a single pod. This is enough to start in case your hardware is enough. If you need to scale components to severa instance, you'll have to modify it to use several services and pods.
Create a namespace to deploy jitsi to:
`kubectl create namespace jitsi`
Add the secret with secret values (replace `...` with some random strings):
`kubectl create secret generic jitsi-config -n jitsi --from-literal=JICOFO_COMPONENT_SECRET=... --from-literal=JICOFO_AUTH_PASSWORD=... --from-literal=JVB_AUTH_PASSWORD=... `
Deploy the service to listen for JVB UDP traffic on all cluster nodes port 30300:
`kubectl create -f jvb-service.yaml`
Now we can deploy the rest of the application. First modify the `DOCKER_HOST_ADDRESS` env value in deployment.yaml to point to one of nodes in your cluster (or load-balancer for all nodes if you have one), and then deploy it:
`kubectl create -f deployment.yaml`
To expose the webapp, we can use Ingress (replace the `host` value with your actual hostname):
`kubectl create -f web-service.yaml`
You can either use "https" or "http" service port, depending on whether your ingress allows self-signed certs.

@ -0,0 +1,145 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: jitsi
name: jitsi
namespace: jitsi
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
k8s-app: jitsi
template:
metadata:
labels:
k8s-app: jitsi
spec:
containers:
- name: jicofo
image: jitsi/jicofo
imagePullPolicy: Always
env:
- name: XMPP_SERVER
value: localhost
- name: XMPP_DOMAIN
value: meet.jitsi
- name: XMPP_AUTH_DOMAIN
value: auth.meet.jitsi
- name: XMPP_MUC_DOMAIN
value: muc.meet.jitsi
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.meet.jitsi
- name: JICOFO_COMPONENT_SECRET
valueFrom:
secretKeyRef:
name: jitsi-config
key: JICOFO_COMPONENT_SECRET
- name: JICOFO_AUTH_USER
value: focus
- name: JICOFO_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: jitsi-config
key: JICOFO_AUTH_PASSWORD
- name: TZ
value: America/Los_Angeles
- name: JVB_BREWERY_MUC
value: jvbbrewery
- name: prosody
image: jitsi/prosody
imagePullPolicy: Always
env:
- name: XMPP_DOMAIN
value: meet.jitsi
- name: XMPP_AUTH_DOMAIN
value: auth.meet.jitsi
- name: XMPP_MUC_DOMAIN
value: muc.meet.jitsi
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.meet.jitsi
- name: JICOFO_COMPONENT_SECRET
valueFrom:
secretKeyRef:
name: jitsi-config
key: JICOFO_COMPONENT_SECRET
- name: JVB_AUTH_USER
value: jvb
- name: JVB_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: jitsi-config
key: JVB_AUTH_PASSWORD
- name: JICOFO_AUTH_USER
value: focus
- name: JICOFO_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: jitsi-config
key: JICOFO_AUTH_PASSWORD
- name: TZ
value: America/Los_Angeles
- name: JVB_TCP_HARVESTER_DISABLED
value: "true"
- name: web
image: jitsi/web
imagePullPolicy: Always
env:
- name: XMPP_SERVER
value: localhost
- name: JICOFO_AUTH_USER
value: focus
- name: XMPP_DOMAIN
value: meet.jitsi
- name: XMPP_AUTH_DOMAIN
value: auth.meet.jitsi
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.meet.jitsi
- name: XMPP_BOSH_URL_BASE
value: http://127.0.0.1:5280
- name: XMPP_MUC_DOMAIN
value: muc.meet.jitsi
- name: TZ
value: America/Los_Angeles
- name: JVB_TCP_HARVESTER_DISABLED
value: "true"
- name: jvb
image: jitsi/jvb
imagePullPolicy: Always
env:
- name: XMPP_SERVER
value: localhost
- name: DOCKER_HOST_ADDRESS
value: <Set the address for any node in the cluster here>
- name: XMPP_DOMAIN
value: meet.jitsi
- name: XMPP_AUTH_DOMAIN
value: auth.meet.jitsi
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.meet.jitsi
- name: JVB_STUN_SERVERS
value: stun.l.google.com:19302,stun1.l.google.com:19302,stun2.l.google.com:19302
- name: JICOFO_AUTH_USER
value: focus
- name: JVB_TCP_HARVESTER_DISABLED
value: "true"
- name: JVB_AUTH_USER
value: jvb
- name: JVB_PORT
value: "30300"
- name: JVB_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: jitsi-config
key: JVB_AUTH_PASSWORD
- name: JICOFO_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: jitsi-config
key: JICOFO_AUTH_PASSWORD
- name: JVB_BREWERY_MUC
value: jvbbrewery
- name: TZ
value: America/Los_Angeles

@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
labels:
service: jvb
name: jvb-udp
namespace: jitsi
spec:
type: NodePort
externalTrafficPolicy: Cluster
ports:
- port: 30300
protocol: UDP
targetPort: 30300
nodePort: 30300
selector:
k8s-app: jitsi

@ -0,0 +1,32 @@
apiVersion: v1
kind: Service
metadata:
labels:
service: web
name: web
namespace: jitsi
spec:
ports:
- name: "http"
port: 8080
targetPort: 8080
- name: "https"
port: 4443
targetPort: 4443
selector:
k8s-app: jitsi
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: jitsi
namespace: jitsi
spec:
rules:
- host: ...
http:
paths:
- path: /
backend:
serviceName: web
servicePort: https

@ -0,0 +1,18 @@
# Basic configuration to use with the traefik reverse proxy
Note: Tested with traefik 2.2.0
- When running behind traefik, it's a better practice to remove the port-binds for the web service.
- The provided example uses an external network with the name "web". This is the network which moste likely was created while setting up traefik.
- Look for comments starting with **#traefik:** to see the changes made in docker-compose.yml.
- Traefik obtains Let's Encrypt certificates automatically.
Uncomment and set DOCKER_HOST_ADDRESS in .env. I'm pretty sure, that this is mandatory for the docker-setup and should be clearer in the original README. Could be the proxying, didn't investigate further.
## TODO
Add or rewrite the example with docker-compose extends
````env
DOCKER_HOST_ADDRESS=1.2.3.4
````

@ -0,0 +1,269 @@
version: '3'
services:
# Frontend
web:
image: jitsi/web
volumes:
- ${CONFIG}/web:/config
- ${CONFIG}/web/letsencrypt:/etc/letsencrypt
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts
environment:
- ENABLE_LETSENCRYPT
- ENABLE_HTTP_REDIRECT
- ENABLE_HSTS
- ENABLE_XMPP_WEBSOCKET
- DISABLE_HTTPS
- LETSENCRYPT_DOMAIN
- LETSENCRYPT_EMAIL
- LETSENCRYPT_USE_STAGING
- PUBLIC_URL
- TZ
- AMPLITUDE_ID
- ANALYTICS_SCRIPT_URLS
- ANALYTICS_WHITELISTED_EVENTS
- BRIDGE_CHANNEL
- CALLSTATS_CUSTOM_SCRIPT_URL
- CALLSTATS_ID
- CALLSTATS_SECRET
- CHROME_EXTENSION_BANNER_JSON
- CONFCODE_URL
- CONFIG_EXTERNAL_CONNECT
- DEPLOYMENTINFO_ENVIRONMENT
- DEPLOYMENTINFO_ENVIRONMENT_TYPE
- DEPLOYMENTINFO_USERREGION
- DIALIN_NUMBERS_URL
- DIALOUT_AUTH_URL
- DIALOUT_CODES_URL
- DROPBOX_APPKEY
- DROPBOX_REDIRECT_URI
- DYNAMIC_BRANDING_URL
- ENABLE_AUDIO_PROCESSING
- ENABLE_AUTH
- ENABLE_CALENDAR
- ENABLE_FILE_RECORDING_SERVICE
- ENABLE_FILE_RECORDING_SERVICE_SHARING
- ENABLE_GUESTS
- ENABLE_IPV6
- ENABLE_LIPSYNC
- ENABLE_NO_AUDIO_DETECTION
- ENABLE_P2P
- ENABLE_PREJOIN_PAGE
- ENABLE_WELCOME_PAGE
- ENABLE_CLOSE_PAGE
- ENABLE_RECORDING
- ENABLE_REMB
- ENABLE_REQUIRE_DISPLAY_NAME
- ENABLE_SIMULCAST
- ENABLE_STATS_ID
- ENABLE_STEREO
- ENABLE_SUBDOMAINS
- ENABLE_TALK_WHILE_MUTED
- ENABLE_TCC
- ENABLE_TRANSCRIPTIONS
- ETHERPAD_PUBLIC_URL
- ETHERPAD_URL_BASE
- GOOGLE_ANALYTICS_ID
- GOOGLE_API_APP_CLIENT_ID
- INVITE_SERVICE_URL
- JICOFO_AUTH_USER
- MATOMO_ENDPOINT
- MATOMO_SITE_ID
- MICROSOFT_API_APP_CLIENT_ID
- NGINX_RESOLVER
- NGINX_WORKER_PROCESSES
- NGINX_WORKER_CONNECTIONS
- PEOPLE_SEARCH_URL
- RESOLUTION
- RESOLUTION_MIN
- RESOLUTION_WIDTH
- RESOLUTION_WIDTH_MIN
- START_AUDIO_ONLY
- START_AUDIO_MUTED
- DISABLE_AUDIO_LEVELS
- ENABLE_NOISY_MIC_DETECTION
- START_BITRATE
- DESKTOP_SHARING_FRAMERATE_MIN
- DESKTOP_SHARING_FRAMERATE_MAX
- START_VIDEO_MUTED
- TESTING_CAP_SCREENSHARE_BITRATE
- TESTING_OCTO_PROBABILITY
- XMPP_AUTH_DOMAIN
- XMPP_BOSH_URL_BASE
- XMPP_DOMAIN
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_RECORDER_DOMAIN
- TOKEN_AUTH_URL
networks:
# traefik: change the following line to your external docker network
web:
meet.jitsi:
aliases:
- ${XMPP_DOMAIN}
labels:
traefik.http.middlewares.redirect.redirectscheme.scheme: https
traefik.http.routers.app-http.entrypoints: web
traefik.http.routers.app-http.middlewares: redirect
traefik.http.routers.app-http.rule: 'Host(`your.host.name`)'
traefik.http.routers.app.entrypoints: websecure
traefik.http.routers.app.rule: 'Host(`your.host.name`)'
traefik.http.routers.app.tls: 'true'
traefik.http.routers.app.tls.certresolver: le
traefik.http.services.app.loadbalancer.server.port: 80
# traefik: change the following line to your external docker network
traefik.docker.network: web
# XMPP server
prosody:
image: jitsi/prosody
expose:
- '5222'
- '5347'
- '5280'
volumes:
- ${CONFIG}/prosody:/config
environment:
- AUTH_TYPE
- ENABLE_AUTH
- ENABLE_GUESTS
- ENABLE_LOBBY
- ENABLE_XMPP_WEBSOCKET
- GLOBAL_MODULES
- GLOBAL_CONFIG
- LDAP_URL
- LDAP_BASE
- LDAP_BINDDN
- LDAP_BINDPW
- LDAP_FILTER
- LDAP_AUTH_METHOD
- LDAP_VERSION
- LDAP_USE_TLS
- LDAP_TLS_CIPHERS
- LDAP_TLS_CHECK_PEER
- LDAP_TLS_CACERT_FILE
- LDAP_TLS_CACERT_DIR
- LDAP_START_TLS
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_MODULES
- XMPP_MUC_MODULES
- XMPP_INTERNAL_MUC_MODULES
- XMPP_RECORDER_DOMAIN
- XMPP_CROSS_DOMAIN
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JIGASI_XMPP_USER
- JIGASI_XMPP_PASSWORD
- JIBRI_XMPP_USER
- JIBRI_XMPP_PASSWORD
- JIBRI_RECORDER_USER
- JIBRI_RECORDER_PASSWORD
- JWT_APP_ID
- JWT_APP_SECRET
- JWT_ACCEPTED_ISSUERS
- JWT_ACCEPTED_AUDIENCES
- JWT_ASAP_KEYSERVER
- JWT_ALLOW_EMPTY
- JWT_AUTH_TYPE
- JWT_TOKEN_AUTH_MODULE
- LOG_LEVEL
- PUBLIC_URL
- TZ
networks:
meet.jitsi:
aliases:
- ${XMPP_SERVER}
# Focus component
jicofo:
image: jitsi/jicofo
volumes:
- ${CONFIG}/jicofo:/config
environment:
- AUTH_TYPE
- BRIDGE_AVG_PARTICIPANT_STRESS
- BRIDGE_STRESS_THRESHOLD
- ENABLE_AUTH
- ENABLE_AUTO_OWNER
- ENABLE_CODEC_VP8
- ENABLE_CODEC_VP9
- ENABLE_CODEC_H264
- ENABLE_RECORDING
- ENABLE_SCTP
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS
- JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT
- JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT
- JICOFO_ENABLE_HEALTH_CHECKS
- JICOFO_SHORT_ID
- JICOFO_RESERVATION_ENABLED
- JICOFO_RESERVATION_REST_BASE_URL
- JIBRI_BREWERY_MUC
- JIBRI_REQUEST_RETRIES
- JIBRI_PENDING_TIMEOUT
- JIGASI_BREWERY_MUC
- JIGASI_SIP_URI
- JVB_BREWERY_MUC
- MAX_BRIDGE_PARTICIPANTS
- OCTO_BRIDGE_SELECTION_STRATEGY
- TZ
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_SERVER
depends_on:
- prosody
networks:
meet.jitsi:
# Video bridge
jvb:
image: jitsi/jvb
ports:
- '${JVB_PORT}:${JVB_PORT}/udp'
- '${JVB_TCP_MAPPED_PORT}:${JVB_TCP_PORT}'
volumes:
- ${CONFIG}/jvb:/config
environment:
- DOCKER_HOST_ADDRESS
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_SERVER
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JVB_BREWERY_MUC
- JVB_PORT
- JVB_TCP_HARVESTER_DISABLED
- JVB_TCP_PORT
- JVB_TCP_MAPPED_PORT
- JVB_STUN_SERVERS
- JVB_ENABLE_APIS
- JVB_WS_DOMAIN
- JVB_WS_SERVER_ID
- PUBLIC_URL
- TZ
depends_on:
- prosody
networks:
meet.jitsi:
labels:
traefik.udp.routers.jvb.entrypoints: video
traefik.udp.routers.jvb.service: jvb
traefik.udp.services.jvb.loadbalancer.server.port: 10000
# Custom network so all services can communicate using a FQDN
networks:
meet.jitsi:
# traefik: change the following line to your external docker network
web:
external: true

@ -0,0 +1,17 @@
# Basic configuration to use with the traefik reverse proxy
Note: Tested with traefik 1.7
- When running behind traefik, it's a better practice to remove the port-binds for the web service.
- The provided example uses an external network with the name "web". This is the network which moste likely was created while setting up traefik.
- Look for comments starting with **#traefik:** to see the changes made in docker-compose.yml.
Uncomment and set DOCKER_HOST_ADDRESS in .env. I'm pretty sure, that this is mandatory for the docker-setup and should be clearer in the original README. Could be the proxying, didn't investigate further.
## TODO
Add or rewrite the example with docker-compose extends
````env
DOCKER_HOST_ADDRESS=1.2.3.4
````

@ -0,0 +1,180 @@
version: '3'
services:
# Frontend
web:
image: jitsi/web
restart: ${RESTART_POLICY}
volumes:
- ${CONFIG}/web:/config:Z
- ${CONFIG}/web/letsencrypt:/etc/letsencrypt:Z
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z
environment:
- ENABLE_AUTH
- ENABLE_GUESTS
- ENABLE_LETSENCRYPT
- ENABLE_HTTP_REDIRECT
- ENABLE_TRANSCRIPTIONS
- DISABLE_HTTPS
- JICOFO_AUTH_USER
- LETSENCRYPT_DOMAIN
- LETSENCRYPT_EMAIL
- PUBLIC_URL
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_BOSH_URL_BASE
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_RECORDER_DOMAIN
- ETHERPAD_URL_BASE
- ETHERPAD_PUBLIC_URL
- TZ
- JIBRI_BREWERY_MUC
- JIBRI_PENDING_TIMEOUT
- JIBRI_XMPP_USER
- JIBRI_XMPP_PASSWORD
- JIBRI_RECORDER_USER
- JIBRI_RECORDER_PASSWORD
- ENABLE_RECORDING
networks:
# traefik: change the following line to your external docker network
web:
meet.jitsi:
aliases:
- ${XMPP_DOMAIN}
labels:
# traefik: change that to your external network
- "traefik.docker.network=web"
- "traefik.enable=true"
- "traefik.backend=jc_backend"
# traefik: change that to your actual fqdn
- "traefik.basic.frontend.rule=Host:your.host.name"
- "traefik.basic.port=8080"
# XMPP server
prosody:
image: jitsi/prosody
restart: ${RESTART_POLICY}
expose:
- '5222'
- '5347'
- '5280'
volumes:
- ${CONFIG}/prosody/config:/config:Z
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
environment:
- AUTH_TYPE
- ENABLE_AUTH
- ENABLE_GUESTS
- GLOBAL_MODULES
- GLOBAL_CONFIG
- LDAP_URL
- LDAP_BASE
- LDAP_BINDDN
- LDAP_BINDPW
- LDAP_FILTER
- LDAP_AUTH_METHOD
- LDAP_VERSION
- LDAP_USE_TLS
- LDAP_TLS_CIPHERS
- LDAP_TLS_CHECK_PEER
- LDAP_TLS_CACERT_FILE
- LDAP_TLS_CACERT_DIR
- LDAP_START_TLS
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_GUEST_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_MODULES
- XMPP_MUC_MODULES
- XMPP_INTERNAL_MUC_MODULES
- XMPP_RECORDER_DOMAIN
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JIGASI_XMPP_USER
- JIGASI_XMPP_PASSWORD
- JIBRI_XMPP_USER
- JIBRI_XMPP_PASSWORD
- JIBRI_RECORDER_USER
- JIBRI_RECORDER_PASSWORD
- JWT_APP_ID
- JWT_APP_SECRET
- JWT_ACCEPTED_ISSUERS
- JWT_ACCEPTED_AUDIENCES
- JWT_ASAP_KEYSERVER
- JWT_ALLOW_EMPTY
- JWT_AUTH_TYPE
- JWT_TOKEN_AUTH_MODULE
- LOG_LEVEL
- TZ
networks:
meet.jitsi:
aliases:
- ${XMPP_SERVER}
# Focus component
jicofo:
image: jitsi/jicofo
restart: ${RESTART_POLICY}
volumes:
- ${CONFIG}/jicofo:/config:Z
environment:
- AUTH_TYPE
- ENABLE_AUTH
- XMPP_DOMAIN
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_SERVER
- JICOFO_COMPONENT_SECRET
- JICOFO_AUTH_USER
- JICOFO_AUTH_PASSWORD
- JICOFO_RESERVATION_REST_BASE_URL
- JVB_BREWERY_MUC
- JIGASI_BREWERY_MUC
- JIBRI_BREWERY_MUC
- JIGASI_SIP_URI
- JIBRI_PENDING_TIMEOUT
- TZ
depends_on:
- prosody
networks:
meet.jitsi:
# Video bridge
jvb:
image: jitsi/jvb
restart: ${RESTART_POLICY}
ports:
- '${JVB_PORT}:${JVB_PORT}/udp'
- '${JVB_TCP_MAPPED_PORT}:${JVB_TCP_PORT}'
volumes:
- ${CONFIG}/jvb:/config:Z
environment:
- DOCKER_HOST_ADDRESS
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_SERVER
- JVB_AUTH_USER
- JVB_AUTH_PASSWORD
- JVB_BREWERY_MUC
- JVB_PORT
- JVB_TCP_HARVESTER_DISABLED
- JVB_TCP_PORT
- JVB_STUN_SERVERS
- JVB_ENABLE_APIS
- TZ
depends_on:
- prosody
networks:
meet.jitsi:
# Custom network so all services can communicate using a FQDN
networks:
meet.jitsi:
# traefik: change the following line to your external docker network
web:
external: true

@ -0,0 +1,21 @@
#!/bin/bash
function generatePassword() {
openssl rand -hex 16
}
JICOFO_COMPONENT_SECRET=$(generatePassword)
JICOFO_AUTH_PASSWORD=$(generatePassword)
JVB_AUTH_PASSWORD=$(generatePassword)
JIGASI_XMPP_PASSWORD=$(generatePassword)
JIBRI_RECORDER_PASSWORD=$(generatePassword)
JIBRI_XMPP_PASSWORD=$(generatePassword)
sed -i.bak \
-e "s#JICOFO_COMPONENT_SECRET=.*#JICOFO_COMPONENT_SECRET=${JICOFO_COMPONENT_SECRET}#g" \
-e "s#JICOFO_AUTH_PASSWORD=.*#JICOFO_AUTH_PASSWORD=${JICOFO_AUTH_PASSWORD}#g" \
-e "s#JVB_AUTH_PASSWORD=.*#JVB_AUTH_PASSWORD=${JVB_AUTH_PASSWORD}#g" \
-e "s#JIGASI_XMPP_PASSWORD=.*#JIGASI_XMPP_PASSWORD=${JIGASI_XMPP_PASSWORD}#g" \
-e "s#JIBRI_RECORDER_PASSWORD=.*#JIBRI_RECORDER_PASSWORD=${JIBRI_RECORDER_PASSWORD}#g" \
-e "s#JIBRI_XMPP_PASSWORD=.*#JIBRI_XMPP_PASSWORD=${JIBRI_XMPP_PASSWORD}#g" \
"$(dirname "$0")/.env"

@ -0,0 +1,36 @@
version: '3'
services:
jibri:
image: jitsi/jibri:latest
restart: ${RESTART_POLICY}
volumes:
- ${CONFIG}/jibri:/config:Z
- /dev/shm:/dev/shm
cap_add:
- SYS_ADMIN
- NET_BIND_SERVICE
devices:
- /dev/snd:/dev/snd
environment:
- XMPP_AUTH_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_RECORDER_DOMAIN
- XMPP_SERVER
- XMPP_DOMAIN
- JIBRI_XMPP_USER
- JIBRI_XMPP_PASSWORD
- JIBRI_BREWERY_MUC
- JIBRI_RECORDER_USER
- JIBRI_RECORDER_PASSWORD
- JIBRI_RECORDING_DIR
- JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
- JIBRI_STRIP_DOMAIN_JID
- JIBRI_LOGS_DIR
- DISPLAY=:0
- TZ
depends_on:
- jicofo
networks:
meet.jitsi:

@ -0,0 +1,53 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base-java
#ARG CHROME_RELEASE=latest
#ARG CHROMEDRIVER_MAJOR_RELEASE=latest
ARG CHROME_RELEASE=78.0.3904.97
ARG CHROMEDRIVER_MAJOR_RELEASE=78
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN \
apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y jibri libgl1-mesa-dri procps \
&& apt-cleanup
RUN \
[ "${CHROME_RELEASE}" = "latest" ] \
&& wget -q https://dl-ssl.google.com/linux/linux_signing_key.pub -O /etc/apt/trusted.gpg.d/google.asc \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
&& apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y google-chrome-stable \
&& apt-cleanup \
|| true
RUN \
[ "${CHROME_RELEASE}" != "latest" ] \
&& curl -4so "/tmp/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb" "http://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb" \
&& apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y "/tmp/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb" \
&& apt-cleanup \
|| true
RUN \
[ "${CHROMEDRIVER_MAJOR_RELEASE}" = "latest" ] \
&& CHROMEDRIVER_RELEASE="$(curl -4Ls https://chromedriver.storage.googleapis.com/LATEST_RELEASE)" \
|| CHROMEDRIVER_RELEASE="$(curl -4Ls https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROMEDRIVER_MAJOR_RELEASE})" \
&& curl -4Ls "https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_RELEASE}/chromedriver_linux64.zip" \
| zcat >> /usr/bin/chromedriver \
&& chmod +x /usr/bin/chromedriver \
&& chromedriver --version
RUN \
apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y jitsi-upload-integrations jq \
&& apt-cleanup
COPY rootfs/ /
RUN /fix-permissions.sh
VOLUME /config
USER 1001

@ -0,0 +1,60 @@
{
"recording_directory":"{{ .Env.JIBRI_RECORDING_DIR }}",
// The path to the script which will be run on completed recordings
{{ if .Env.JIBRI_FINALIZE_RECORDING_SCRIPT_PATH -}}
"finalize_recording_script_path": "{{ .Env.JIBRI_FINALIZE_RECORDING_SCRIPT_PATH }}",
{{ end -}}
"xmpp_environments": [
{
// A friendly name for this environment which can be used
// for logging, stats, etc.
"name": "prod environment",
// The hosts of the XMPP servers to connect to as part of
// this environment
"xmpp_server_hosts": [
"{{ .Env.XMPP_SERVER }}"
],
"xmpp_domain": "{{ .Env.XMPP_DOMAIN }}",
// Jibri will login to the xmpp server as a privileged user
"control_login": {
"domain": "{{ .Env.XMPP_AUTH_DOMAIN }}",
// The credentials for logging in
"username": "{{ .Env.JIBRI_XMPP_USER }}",
"password": "{{ .Env.JIBRI_XMPP_PASSWORD }}"
},
// Using the control_login information above, Jibri will join
// a control muc as a means of announcing its availability
// to provide services for a given environment
"control_muc": {
"domain": "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}",
"room_name": "{{ .Env.JIBRI_BREWERY_MUC }}",
// MUST be unic for every instanse
"nickname": "jibri-instanse-{{ .Env.JIBRI_INSTANCE_ID }}"
},
// All participants in a call join a muc so they can exchange
// information. Jibri can be instructed to join a special muc
// with credentials to give it special abilities (e.g. not being
// displayed to other users like a normal participant)
"call_login": {
"domain": "{{ .Env.XMPP_RECORDER_DOMAIN }}",
"username": "{{ .Env.JIBRI_RECORDER_USER }}",
"password": "{{ .Env.JIBRI_RECORDER_PASSWORD }}"
},
// When jibri gets a request to start a service for a room, the room
// jid will look like:
// roomName@optional.prefixes.subdomain.xmpp_domain
// We'll build the url for the call by transforming that into:
// https://xmpp_domain/subdomain/roomName
// So if there are any prefixes in the jid (like jitsi meet, which
// has its participants join a muc at conference.xmpp_domain) then
// list that prefix here so it can be stripped out to generate
// the call url correctly
"room_jid_domain_string_to_strip_from_start": "{{ .Env.JIBRI_STRIP_DOMAIN_JID }}.",
// The amount of time, in minutes, a service is allowed to continue.
// Once a service has been running for this long, it will be
// stopped (cleanly). A value of 0 means an indefinite amount
// of time is allowed
"usage_timeout": "0"
}
]
}

@ -0,0 +1,33 @@
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
java.util.logging.FileHandler.level = FINE
java.util.logging.FileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/log.%g.txt
java.util.logging.FileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
java.util.logging.FileHandler.count = 10
java.util.logging.FileHandler.limit = 10000000
org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.level = FINE
org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/ffmpeg.%g.txt
org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.count = 10
org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.limit = 10000000
org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.level = FINE
org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/pjsua.%g.txt
org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.count = 10
org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.limit = 10000000
org.jitsi.jibri.selenium.util.BrowserFileHandler.level = FINE
org.jitsi.jibri.selenium.util.BrowserFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/browser.%g.txt
org.jitsi.jibri.selenium.util.BrowserFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
org.jitsi.jibri.selenium.util.BrowserFileHandler.count = 10
org.jitsi.jibri.selenium.util.BrowserFileHandler.limit = 10000000
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
org.jitsi.level = FINE
org.glassfish.level = INFO
org.osgi.level = INFO

@ -0,0 +1,60 @@
#!/usr/bin/with-contenv bash
if [[ -z $JIBRI_RECORDER_PASSWORD || -z $JIBRI_XMPP_PASSWORD ]]; then
echo 'FATAL ERROR: Jibri recorder password and auth password must be set'
exit 1
fi
OLD_JIBRI_RECORDER_PASSWORD=passw0rd
if [[ "$JIBRI_RECORDER_PASSWORD" == "$OLD_JIBRI_RECORDER_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri recorder password must be changed, check the README'
exit 1
fi
OLD_JIBRI_XMPP_PASSWORD=passw0rd
if [[ "$JIBRI_XMPP_PASSWORD" == "$OLD_JIBRI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri auth password must be changed, check the README'
exit 1
fi
# DISPLAY is necessary for start
[ -z "${DISPLAY}" ] \
&& ( echo -e "\e[31mERROR: Please set DISPLAY variable.\e[39m"; kill 1; exit 1 )
# check loaded snd_aloop module and exit if is not loaded on the host
[ -z "$(lsmod | grep -om1 snd_aloop)" ] \
&& ( echo -e "\e[31mERROR: Please load snd-aloop module on the docker host.\e[39m"; kill 1; exit 1 )
# TODO Fix this for OpenShift
# get host's audio group id
host_audio_group="$(stat -c %g /dev/snd/pcmC0D0p 2>/dev/null)"
# audio group is not found. Has it been run without jibri.yml?
[ -z "${host_audio_group}" ] \
&& ( echo -e "\e[31mERROR: Binding /dev/snd is not found. Please check that you run docker-compose with -f jibri.yml.\e[39m"; kill 1; exit 1 )
# try to create group with this id. If group with the id already exists, just skip
groupadd -g ${host_audio_group} jibri-audio >/dev/null 2>&1
# include user to the group by id
usermod -aG ${host_audio_group} jibri
# script for finalizing must have executing bit.
[ ! -z "${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}" ] \
&& [ -f "${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}" ] \
&& [ ! -x "${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}" ] \
&& chmod +x ${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}
# set random jibri nickname for the instance if is not set
[ -z "${JIBRI_INSTANCE_ID}" ] && export JIBRI_INSTANCE_ID=$(date +%N)
# always recreate configs
tpl /defaults/config.json > /etc/jitsi/jibri/config.json
tpl /defaults/logging.properties > /etc/jitsi/jibri/logging.properties
# make recording dir
[ -z "${JIBRI_RECORDING_DIR}" ] && export JIBRI_RECORDING_DIR=/config/recordings
mkdir -pm 770 ${JIBRI_RECORDING_DIR}
# make logs dir
[ -z "${JIBRI_LOGS_DIR}" ] && export JIBRI_LOGS_DIR=/config/logs
mkdir -pm 770 ${JIBRI_LOGS_DIR}

@ -0,0 +1,4 @@
{
"CommandLineFlagSecurityWarningsEnabled": false
}

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
DAEMON="/usr/bin/Xorg -nocursor -noreset +extension RANDR +extension RENDER -logfile /tmp/xorg.log -config /etc/jitsi/jibri/xorg-video-dummy.conf ${DISPLAY}"
exec /bin/bash -c "exec $DAEMON"

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
DAEMON="/usr/bin/icewm-session"
exec /bin/bash -c "exec $DAEMON"

@ -0,0 +1,9 @@
#!/usr/bin/with-contenv bash
# TODO Fix this for OpenShift
# we have to set it, otherwise chrome won't find ~/.asoundrc file
HOME=/home/jibri
DAEMON=/opt/jitsi/jibri/launch.sh
exec /bin/bash -c "exec $DAEMON"

@ -0,0 +1,15 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base-java
RUN \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y jicofo && \
apt-cleanup
COPY rootfs/ /
RUN /fix-permissions.sh
VOLUME /config
USER 1001

@ -0,0 +1,143 @@
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool }}
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" }}
{{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "0" | toBool }}
jicofo {
{{ if $ENABLE_AUTH }}
authentication {
enabled = true
// The type of authentication. Supported values are XMPP, JWT or SHIBBOLETH (default).
{{ if eq $AUTH_TYPE "jwt" }}
type = JWT
{{ else if eq $AUTH_TYPE "shibboleth" }}
type = SHIBBOLETH
{{ else }}
type = XMPP
{{ end }}
{{ if eq $AUTH_TYPE "shibboleth" }}
login-url = "shibboleth:default"
logout-url = "shibboleth:default"
{{ else }}
login-url = "{{ .Env.XMPP_DOMAIN }}"
{{ end }}
}
{{ end }}
// Configuration related to jitsi-videobridge
bridge {
{{ if .Env.MAX_BRIDGE_PARTICIPANTS }}
max-bridge-participants = "{{ .Env.MAX_BRIDGE_PARTICIPANTS }}"
{{ end }}
{{ if .Env.BRIDGE_AVG_PARTICIPANT_STRESS }}
// The assumed average stress per participant. default is 0.01
average-participant-stress = "{{ .Env.BRIDGE_AVG_PARTICIPANT_STRESS }}"
{{ end }}
{{ if .Env.BRIDGE_STRESS_THRESHOLD }}
// The stress level above which a bridge is considered overstressed. 0.8 is the default value
stress-threshold = "{{ .Env.BRIDGE_STRESS_THRESHOLD }}"
{{ end }}
{{ if .Env.OCTO_BRIDGE_SELECTION_STRATEGY }}
selection-strategy = "{{ .Env.OCTO_BRIDGE_SELECTION_STRATEGY }}"
{{ end }}
{{ if .Env.JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS }}
health-checks {
enabled = "{{ .Env.JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS }}"
}
{{ end }}
brewery-jid = "{{ .Env.JVB_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}"
}
// Configure the codecs and RTP extensions to be used in the offer sent to clients.
codec {
video {
{{ if .Env.ENABLE_CODEC_VP8 }}
vp8 {
enabled = "{{ .Env.ENABLE_CODEC_VP8 }}"
}
{{ end }}
{{ if .Env.ENABLE_CODEC_VP9 }}
vp9 {
enabled = "{{ .Env.ENABLE_CODEC_VP9 }}"
}
{{ end }}
{{ if .Env.ENABLE_CODEC_H264 }}
h264 {
enabled = "{{ .Env.ENABLE_CODEC_H264 }}"
}
{{ end }}
}
}
conference {
{{ if .Env.ENABLE_AUTO_OWNER }}
enable-auto-owner = "{{ .Env.ENABLE_AUTO_OWNER }}"
{{ end }}
{{ if .Env.JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT }}
initial-timeout = "{{ .Env.JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT }}"
{{ end }}
{{ if .Env.JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT }}
single-participant-timeout = "{{ .Env.JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT }}"
{{ end }}
}
{{ if .Env.JICOFO_ENABLE_HEALTH_CHECKS }}
// Configuration for the internal health checks performed by jicofo.
health {
// Whether to perform health checks.
enabled = "{{ .Env.JICOFO_ENABLE_HEALTH_CHECKS }}"
}
{{ end }}
{{ if $ENABLE_RECORDING }}
jibri {
brewery-jid = "{{ .Env.JIBRI_BREWERY_MUC}}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}"
{{ if .Env.JIBRI_REQUEST_RETRIES }}
num-retries = "{{ .Env.JIBRI_REQUEST_RETRIES }}"
{{ end }}
{{ if .Env.JIBRI_PENDING_TIMEOUT }}
pending-timeout = "{{ .Env.JIBRI_PENDING_TIMEOUT }}"
{{ end }}
}
{{ end }}
{{ if and .Env.JIGASI_SIP_URI .Env.JIGASI_BREWERY_MUC }}
jigasi {
brewery-jid = "{{ .Env.JIGASI_BREWERY_MUC}}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}"
}
{{ end }}
octo {
id = "{{ .Env.JICOFO_SHORT_ID | default "1" }}"
}
{{ if .Env.ENABLE_SCTP }}
sctp {
enabled = "{{ .Env.ENABLE_SCTP }}"
}
{{ end }}
xmpp {
client {
enabled = true
hostname = "{{ .Env.XMPP_SERVER }}"
domain = "{{ .Env.XMPP_AUTH_DOMAIN }}"
username = "{{ .Env.JICOFO_AUTH_USER }}"
password = "{{ .Env.JICOFO_AUTH_PASSWORD }}"
conference-muc-jid = "{{ .Env.XMPP_MUC_DOMAIN }}"
disable-certificate-verification = true
}
}
{{ if .Env.JICOFO_RESERVATION_ENABLED | default "false" | toBool }}
reservation {
enabled = "{{ .Env.JICOFO_RESERVATION_ENABLED }}"
base-url = "{{ .Env.JICOFO_RESERVATION_REST_BASE_URL }}"
}
{{ end }}
}

@ -0,0 +1,21 @@
handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
net.java.sip.communicator.util.ScLogFormatter.programname=Jicofo
.level=INFO
net.sf.level=SEVERE
net.java.sip.communicator.plugin.reconnectplugin.level=FINE
org.ice4j.level=SEVERE
org.jitsi.impl.neomedia.level=SEVERE
# Do not worry about missing strings
net.java.sip.communicator.service.resources.AbstractResourcesService.level=SEVERE
#net.java.sip.communicator.service.protocol.level=ALL
# Enable debug packets logging
#org.jitsi.impl.protocol.xmpp.level=FINE

@ -0,0 +1,24 @@
#!/usr/bin/with-contenv bash
if [[ -z $JICOFO_COMPONENT_SECRET || -z $JICOFO_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: Jicofo component secret and auth password must be set'
exit 1
fi
OLD_JICOFO_COMPONENT_SECRET=s3cr37
if [[ "$JICOFO_COMPONENT_SECRET" == "$OLD_JICOFO_COMPONENT_SECRET" ]]; then
echo 'FATAL ERROR: Jicofo component secret must be changed, check the README'
exit 1
fi
OLD_JICOFO_AUTH_PASSWORD=passw0rd
if [[ "$JICOFO_AUTH_PASSWORD" == "$OLD_JICOFO_AUTH_PASSWORD" ]]; then
echo 'FATAL ERROR: Jicofo auth password must be changed, check the README'
exit 1
fi
tpl /defaults/jicofo.conf > /config/jicofo.conf
if [[ ! -f /config/logging.properties ]]; then
cp /defaults/logging.properties /config
fi

@ -0,0 +1,8 @@
#!/usr/bin/with-contenv bash
JAVA_SYS_PROPS="$JAVA_SYS_PROPS -Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/ -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=config -Djava.util.logging.config.file=/config/logging.properties -Dconfig.file=/config/jicofo.conf"
DAEMON=/usr/share/jicofo/jicofo.sh
DAEMON_DIR=/usr/share/jicofo/
DAEMON_OPTS="--domain=$XMPP_DOMAIN --host=$XMPP_SERVER --secret=$JICOFO_COMPONENT_SECRET --user_name=$JICOFO_AUTH_USER --user_domain=$XMPP_AUTH_DOMAIN --user_password=$JICOFO_AUTH_PASSWORD"
exec /bin/bash -c "cd $DAEMON_DIR; JAVA_SYS_PROPS=\"$JAVA_SYS_PROPS\" exec $DAEMON $DAEMON_OPTS"

@ -0,0 +1,50 @@
version: '3'
services:
# SIP gateway (audio)
jigasi:
image: jitsi/jigasi:latest
restart: ${RESTART_POLICY}
ports:
- '${JIGASI_PORT_MIN}-${JIGASI_PORT_MAX}:${JIGASI_PORT_MIN}-${JIGASI_PORT_MAX}/udp'
volumes:
- ${CONFIG}/jigasi:/config:Z
- ${CONFIG}/transcripts:/tmp/transcripts:Z
environment:
- ENABLE_AUTH
- XMPP_AUTH_DOMAIN
- XMPP_MUC_DOMAIN
- XMPP_INTERNAL_MUC_DOMAIN
- XMPP_SERVER
- XMPP_DOMAIN
- PUBLIC_URL
- JIGASI_SIP_URI
- JIGASI_SIP_PASSWORD
- JIGASI_SIP_SERVER
- JIGASI_SIP_PORT
- JIGASI_SIP_TRANSPORT
- JIGASI_SIP_DEFAULT_ROOM
- JIGASI_XMPP_USER
- JIGASI_XMPP_PASSWORD
- JIGASI_BREWERY_MUC
- JIGASI_PORT_MIN
- JIGASI_PORT_MAX
- JIGASI_HEALTH_CHECK_SIP_URI
- JIGASI_HEALTH_CHECK_INTERVAL
- JIGASI_SIP_KEEP_ALIVE_METHOD
- JIGASI_ENABLE_SDES_SRTP
- ENABLE_TRANSCRIPTIONS
- JIGASI_TRANSCRIBER_ADVERTISE_URL
- JIGASI_TRANSCRIBER_RECORD_AUDIO
- JIGASI_TRANSCRIBER_SEND_TXT
- GC_PROJECT_ID
- GC_PRIVATE_KEY_ID
- GC_PRIVATE_KEY
- GC_CLIENT_EMAIL
- GC_CLIENT_ID
- GC_CLIENT_CERT_URL
- TZ
depends_on:
- prosody
networks:
meet.jitsi:

@ -0,0 +1,17 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base-java
ENV GOOGLE_APPLICATION_CREDENTIALS /config/key.json
RUN \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y jigasi jq && \
apt-cleanup
COPY rootfs/ /
RUN /fix-permissions.sh
VOLUME ["/config", "/tmp/transcripts"]
USER 1001

@ -0,0 +1,18 @@
handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
net.java.sip.communicator.util.ScLogFormatter.programname=Jigasi
.level=INFO
net.sf.level=SEVERE
net.java.sip.communicator.plugin.reconnectplugin.level=FINE
org.ice4j.level=SEVERE
org.jitsi.impl.neomedia.level=SEVERE
# Do not worry about missing strings
net.java.sip.communicator.service.resources.AbstractResourcesService.level=SEVERE
#net.java.sip.communicator.service.protocol.level=ALL

@ -0,0 +1,150 @@
net.java.sip.communicator.impl.protocol.SingleCallInProgressPolicy.enabled=false
# Adjust opus encoder complexity
net.java.sip.communicator.impl.neomedia.codec.audio.opus.encoder.COMPLEXITY=10
# Disables packet logging
net.java.sip.communicator.packetlogging.PACKET_LOGGING_ENABLED=false
# SIP account
net.java.sip.communicator.impl.protocol.sip.acc1=acc1
{{ if and .Env.JIGASI_SIP_PORT .Env.JIGASI_SIP_TRANSPORT }}
net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_ADDRESS={{ .Env.JIGASI_SIP_SERVER }}
net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_AUTO_CONFIG=false
net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_PORT={{ .Env.JIGASI_SIP_PORT | default "5060" }}
net.java.sip.communicator.impl.protocol.sip.acc1.PREFERRED_TRANSPORT={{ .Env.JIGASI_SIP_TRANSPORT | default "UDP" }}
{{ end }}
{{ if .Env.JIGASI_ENABLE_SDES_SRTP | default "0" | toBool }}
net.java.sip.communicator.impl.protocol.sip.acc1.SAVP_OPTION=1
net.java.sip.communicator.impl.protocol.sip.acc1.DEFAULT_ENCRYPTION=true
net.java.sip.communicator.impl.protocol.sip.acc1.DEFAULT_SIPZRTP_ATTRIBUTE=false
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.ZRTP=0
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.SDES=1
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.DTLS-SRTP=0
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.ZRTP=false
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.SDES=true
net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.DTLS-SRTP=false
net.java.sip.communicator.impl.protocol.sip.acc1.SDES_CIPHER_SUITES=AES_CM_128_HMAC_SHA1_80,AES_CM_128_HMAC_SHA1_32
{{ end }}
net.java.sip.communicator.impl.protocol.sip.acc1.ACCOUNT_UID=SIP\:{{ .Env.JIGASI_SIP_URI }}
net.java.sip.communicator.impl.protocol.sip.acc1.PASSWORD={{ .Env.JIGASI_SIP_PASSWORD | b64enc }}
net.java.sip.communicator.impl.protocol.sip.acc1.PROTOCOL_NAME=SIP
net.java.sip.communicator.impl.protocol.sip.acc1.SERVER_ADDRESS={{ .Env.JIGASI_SIP_SERVER }}
net.java.sip.communicator.impl.protocol.sip.acc1.USER_ID={{ .Env.JIGASI_SIP_URI }}
net.java.sip.communicator.impl.protocol.sip.acc1.KEEP_ALIVE_INTERVAL=25
net.java.sip.communicator.impl.protocol.sip.acc1.KEEP_ALIVE_METHOD={{ .Env.JIGASI_SIP_KEEP_ALIVE_METHOD | default "OPTIONS" }}
net.java.sip.communicator.impl.protocol.sip.acc1.VOICEMAIL_ENABLED=false
net.java.sip.communicator.impl.protocol.sip.acc1.JITSI_MEET_ROOM_HEADER_NAME=X-Room-Name
net.java.sip.communicator.impl.protocol.sip.acc1.JITSI_MEET_DOMAIN_BASE_HEADER_NAME=X-Domain-Base
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.AMR-WB/16000=750
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.G722/8000=700
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.GSM/8000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.H263-1998/90000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.H264/90000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.PCMA/8000=600
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.PCMU/8000=650
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/12000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/16000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/24000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/8000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.VP8/90000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.iLBC/8000=10
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.opus/48000=1000
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.red/90000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/16000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/32000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/8000=0
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.telephone-event/8000=1
net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.ulpfec/90000=0
net.java.sip.communicator.impl.protocol.sip.acc1.OVERRIDE_ENCODINGS=true
net.java.sip.communicator.impl.protocol.sip.acc1.DOMAIN_BASE={{ .Env.XMPP_DOMAIN }}
# XMPP account used for control
net.java.sip.communicator.impl.protocol.jabber.acc1=acc1
net.java.sip.communicator.impl.protocol.jabber.acc1.ACCOUNT_UID=Jabber:{{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}
net.java.sip.communicator.impl.protocol.jabber.acc1.USER_ID={{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_SERVER_OVERRIDDEN=true
net.java.sip.communicator.impl.protocol.jabber.acc1.SERVER_ADDRESS={{ .Env.XMPP_SERVER }}
net.java.sip.communicator.impl.protocol.jabber.acc1.PASSWORD={{ .Env.JIGASI_XMPP_PASSWORD | b64enc }}
net.java.sip.communicator.impl.protocol.jabber.acc1.AUTO_GENERATE_RESOURCE=true
net.java.sip.communicator.impl.protocol.jabber.acc1.RESOURCE_PRIORITY=30
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_CARBON_DISABLED=true
net.java.sip.communicator.impl.protocol.jabber.acc1.DEFAULT_ENCRYPTION=true
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_USE_ICE=true
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_ACCOUNT_DISABLED=false
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_PREFERRED_PROTOCOL=false
net.java.sip.communicator.impl.protocol.jabber.acc1.AUTO_DISCOVER_JINGLE_NODES=false
net.java.sip.communicator.impl.protocol.jabber.acc1.PROTOCOL=Jabber
net.java.sip.communicator.impl.protocol.jabber.acc1.IS_USE_UPNP=false
net.java.sip.communicator.impl.protocol.jabber.acc1.USE_DEFAULT_STUN_SERVER=true
net.java.sip.communicator.impl.protocol.jabber.acc1.ENCRYPTION_PROTOCOL.DTLS-SRTP=0
net.java.sip.communicator.impl.protocol.jabber.acc1.ENCRYPTION_PROTOCOL_STATUS.DTLS-SRTP=true
net.java.sip.communicator.impl.protocol.jabber.acc1.VIDEO_CALLING_DISABLED=true
net.java.sip.communicator.impl.protocol.jabber.acc1.OVERRIDE_ENCODINGS=true
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.G722/8000=705
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.GSM/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.H263-1998/90000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.H264/90000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.PCMA/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.PCMU/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/12000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/16000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/24000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.VP8/90000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.iLBC/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.opus/48000=750
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/16000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/32000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.telephone-event/8000=0
net.java.sip.communicator.impl.protocol.jabber.acc1.BREWERY={{ .Env.JIGASI_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}
net.java.sip.communicator.impl.protocol.jabber.acc1.DOMAIN_BASE={{ .Env.XMPP_DOMAIN }}
org.jitsi.jigasi.BREWERY_ENABLED=true
org.jitsi.jigasi.HEALTH_CHECK_SIP_URI={{ .Env.JIGASI_HEALTH_CHECK_SIP_URI | default "" }}
org.jitsi.jigasi.HEALTH_CHECK_INTERVAL={{ .Env.JIGASI_HEALTH_CHECK_INTERVAL | default "300000" }}
org.jitsi.jigasi.HEALTH_CHECK_TIMEOUT=600000
org.jitsi.jigasi.xmpp.acc.IS_SERVER_OVERRIDDEN=true
org.jitsi.jigasi.xmpp.acc.SERVER_ADDRESS={{ .Env.XMPP_SERVER }}
org.jitsi.jigasi.xmpp.acc.VIDEO_CALLING_DISABLED=true
org.jitsi.jigasi.xmpp.acc.JINGLE_NODES_ENABLED=false
org.jitsi.jigasi.xmpp.acc.AUTO_DISCOVER_STUN=false
org.jitsi.jigasi.xmpp.acc.IM_DISABLED=true
org.jitsi.jigasi.xmpp.acc.SERVER_STORED_INFO_DISABLED=true
org.jitsi.jigasi.xmpp.acc.IS_FILE_TRANSFER_DISABLED=true
{{ if .Env.ENABLE_AUTH | default "0" | toBool }}
org.jitsi.jigasi.xmpp.acc.USER_ID={{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}
org.jitsi.jigasi.xmpp.acc.PASS={{ .Env.JIGASI_XMPP_PASSWORD }}
org.jitsi.jigasi.xmpp.acc.ANONYMOUS_AUTH=false
org.jitsi.jigasi.xmpp.acc.ALLOW_NON_SECURE=true
{{ end }}
# Activate this property if you are using self-signed certificates or other
# type of non-trusted certicates. In this mode your service trust in the
# remote certificates always.
net.java.sip.communicator.service.gui.ALWAYS_TRUST_MODE_ENABLED=true
{{ if .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool }}
# Transcription config
org.jitsi.jigasi.ENABLE_TRANSCRIPTION=true
org.jitsi.jigasi.transcription.ENABLE_TRANSLATION=true
org.jitsi.jigasi.transcription.DIRECTORY=/tmp/transcripts
org.jitsi.jigasi.transcription.BASE_URL={{ .Env.PUBLIC_URL }}/transcripts
org.jitsi.jigasi.transcription.jetty.port=-1
org.jitsi.jigasi.transcription.ADVERTISE_URL={{ .Env.JIGASI_TRANSCRIBER_ADVERTISE_URL | default "false"}}
org.jitsi.jigasi.transcription.SAVE_JSON=false
org.jitsi.jigasi.transcription.SEND_JSON=true
org.jitsi.jigasi.transcription.SAVE_TXT=true
org.jitsi.jigasi.transcription.SEND_TXT={{ .Env.JIGASI_TRANSCRIBER_SEND_TXT | default "false"}}
org.jitsi.jigasi.transcription.RECORD_AUDIO={{ .Env.JIGASI_TRANSCRIBER_RECORD_AUDIO | default "false"}}
org.jitsi.jigasi.transcription.RECORD_AUDIO_FORMAT=wav
{{end}}
{{ if .Env.JIGASI_SIP_DEFAULT_ROOM }}
org.jitsi.jigasi.DEFAULT_JVB_ROOM_NAME={{ .Env.JIGASI_SIP_DEFAULT_ROOM }}
{{ end }}
org.jitsi.jigasi.MUC_SERVICE_ADDRESS={{ .Env.XMPP_MUC_DOMAIN }}

@ -0,0 +1,50 @@
#!/usr/bin/with-contenv bash
if [[ -z $JIGASI_XMPP_PASSWORD ]]; then
echo 'FATAL ERROR: Jigasi auth password must be set'
exit 1
fi
OLD_JIGASI_XMPP_PASSWORD=passw0rd
if [[ "$JIGASI_XMPP_PASSWORD" == "$OLD_JIGASI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jigasi auth password must be changed, check the README'
exit 1
fi
tpl /defaults/sip-communicator.properties > /config/sip-communicator.properties
if [[ -f /config/custom-sip-communicator.properties ]]; then
cat /config/custom-sip-communicator.properties >> /config/sip-communicator.properties
fi
if [[ ! -f /config/logging.properties ]]; then
cp /defaults/logging.properties /config
fi
# Create Google Cloud Credentials
if [[ $ENABLE_TRANSCRIPTIONS -eq 1 || $ENABLE_TRANSCRIPTIONS == "true" ]]; then
if [[ -z $GC_PROJECT_ID || -z $GC_PRIVATE_KEY_ID || -z $GC_PRIVATE_KEY || -z $GC_CLIENT_EMAIL || -z $GC_CLIENT_ID || -z $GC_CLIENT_CERT_URL ]]; then
echo 'Transcriptions: One or more environment variables are undefined'
exit 1
fi
jq -n \
--arg GC_PROJECT_ID "$GC_PROJECT_ID" \
--arg GC_PRIVATE_KEY_ID "$GC_PRIVATE_KEY_ID" \
--arg GC_PRIVATE_KEY "$GC_PRIVATE_KEY" \
--arg GC_CLIENT_EMAIL "$GC_CLIENT_EMAIL" \
--arg GC_CLIENT_ID "$GC_CLIENT_ID" \
--arg GC_CLIENT_CERT_URL "$GC_CLIENT_CERT_URL" \
'{
type: "service_account",
project_id: $GC_PROJECT_ID,
private_key_id: $GC_PRIVATE_KEY_ID,
private_key: $GC_PRIVATE_KEY,
client_email: $GC_CLIENT_EMAIL,
client_id: $GC_CLIENT_ID,
auth_uri: "https://accounts.google.com/o/oauth2/auth",
token_uri: "https://oauth2.googleapis.com/token",
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
client_x509_cert_url: $GC_CLIENT_CERT_URL
}' \
> /config/key.json
fi

@ -0,0 +1,9 @@
#!/usr/bin/with-contenv bash
JAVA_SYS_PROPS="-Djava.util.logging.config.file=/config/logging.properties"
DAEMON=/usr/share/jigasi/jigasi.sh
DAEMON_OPTS="--nocomponent=true --configdir=/ --configdirname=config --min-port=$JIGASI_PORT_MIN --max-port=$JIGASI_PORT_MAX"
exec /bin/bash -c "JAVA_SYS_PROPS=\"$JAVA_SYS_PROPS\" exec $DAEMON $DAEMON_OPTS"

@ -0,0 +1,15 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base-java
RUN \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y jitsi-videobridge2 jq curl iproute2 && \
apt-cleanup
COPY rootfs/ /
RUN /fix-permissions.sh
VOLUME /config
USER 1001

@ -0,0 +1,65 @@
{{ $JVB_TCP_PORT := .Env.JVB_TCP_PORT | default "4443" }}
{{ $JVB_TCP_MAPPED_PORT := .Env.JVB_TCP_MAPPED_PORT | default $JVB_TCP_PORT }}
{{ $PUBLIC_URL_DOMAIN := .Env.PUBLIC_URL | default "https://localhost:8443" | trimPrefix "https://" | trimSuffix "/" -}}
{{ $WS_DOMAIN := .Env.JVB_WS_DOMAIN | default $PUBLIC_URL_DOMAIN -}}
{{ $WS_SERVER_ID := .Env.JVB_WS_SERVER_ID | default .Env.LOCAL_ADDRESS -}}
videobridge {
ice {
udp {
port = {{ .Env.JVB_PORT }}
}
tcp {
enabled = {{ not (.Env.JVB_TCP_HARVESTER_DISABLED | default "true" | toBool) }}
port = {{ .Env.JVB_TCP_PORT }}
{{ if not (eq $JVB_TCP_PORT $JVB_TCP_MAPPED_PORT) }}
mapped-port = {{ $JVB_TCP_MAPPED_PORT }}
{{ end }}
}
}
apis {
xmpp-client {
configs {
shard {
HOSTNAME = "{{ .Env.XMPP_SERVER }}"
DOMAIN = "{{ .Env.XMPP_AUTH_DOMAIN }}"
USERNAME = "{{ .Env.JVB_AUTH_USER }}"
PASSWORD = "{{ .Env.JVB_AUTH_PASSWORD }}"
MUC_JIDS = "{{ .Env.JVB_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}"
MUC_NICKNAME = "{{ .Env.HOSTNAME }}"
DISABLE_CERTIFICATE_VERIFICATION = true
}
}
}
}
stats {
enabled = true
}
websockets {
enabled = true
domain = "{{ $WS_DOMAIN }}"
tls = true
server-id = "{{ $WS_SERVER_ID }}"
}
http-servers {
private {
host = 0.0.0.0
}
public {
host = 0.0.0.0
port = 9090
}
}
}
ice4j {
harvest {
mapping {
stun {
{{ if .Env.JVB_STUN_SERVERS }}
addresses = [ "{{ join "\",\"" (splitList "," .Env.JVB_STUN_SERVERS) }}" ]
{{ end }}
}
}
}
}

@ -0,0 +1,14 @@
handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
net.java.sip.communicator.util.ScLogFormatter.programname=JVB
.level=INFO
org.jitsi.videobridge.xmpp.ComponentImpl.level=FINE
# All of the INFO level logs from MediaStreamImpl are unnecessary in the context of jitsi-videobridge.
org.jitsi.impl.neomedia.MediaStreamImpl.level=WARNING

@ -0,0 +1,5 @@
{{ if .Env.DOCKER_HOST_ADDRESS }}
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS={{ .Env.LOCAL_ADDRESS }}
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS={{ .Env.DOCKER_HOST_ADDRESS }}
{{ end }}

@ -0,0 +1,25 @@
#!/usr/bin/with-contenv bash
export LOCAL_ADDRESS=$(ip addr show dev "$(ip route|awk '/^default/ { print $5 }')" | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
if [[ -z $JVB_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: JVB auth password must be set'
exit 1
fi
OLD_JVB_AUTH_PASSWORD=passw0rd
if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then
echo 'FATAL ERROR: JVB auth password must be changed, check the README'
exit 1
fi
tpl /defaults/sip-communicator.properties > /config/sip-communicator.properties
if [[ -f /config/custom-sip-communicator.properties ]]; then
cat /config/custom-sip-communicator.properties >> /config/sip-communicator.properties
fi
tpl /defaults/jvb.conf > /config/jvb.conf
if [[ ! -f /config/logging.properties ]]; then
cp /defaults/logging.properties /config
fi

@ -0,0 +1,7 @@
#!/usr/bin/with-contenv bash
export JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/ -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=config -Djava.util.logging.config.file=/config/logging.properties -Dconfig.file=/config/jvb.conf"
DAEMON=/usr/share/jitsi-videobridge/jvb.sh
exec /bin/bash -c "exec $DAEMON --apis=${JVB_ENABLE_APIS:="none"}"

@ -0,0 +1,70 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base as builder
RUN \
apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y \
lua5.2 \
liblua5.2-dev \
libsasl2-dev \
libssl-dev \
luarocks \
git \
gcc \
&& luarocks install cyrussasl 1.1.0-1 \
&& luarocks install net-url 0.9-1 \
&& luarocks install luajwtjitsi 2.0-0
FROM ${JITSI_REPO}/base
ENV XMPP_CROSS_DOMAIN="false"
RUN \
wget -q https://prosody.im/files/prosody-debian-packages.key -O - | gpg --enarmor > /etc/apt/trusted.gpg.d/prosody.asc \
&& echo "deb http://packages.prosody.im/debian buster main" > /etc/apt/sources.list.d/prosody.list \
&& apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get install -y \
prosody \
libssl1.1 \
sasl2-bin \
libsasl2-modules-ldap \
lua-basexx \
lua-ldap \
lua-sec \
patch \
&& apt-cleanup \
&& rm -rf /etc/prosody
RUN \
apt-dpkg-wrap apt-get update \
&& apt-dpkg-wrap apt-get -d install -y jitsi-meet-prosody \
&& dpkg -x /var/cache/apt/archives/jitsi-meet-prosody*.deb /tmp/pkg \
&& mv /tmp/pkg/usr/share/jitsi-meet/prosody-plugins /prosody-plugins \
&& apt-cleanup \
&& rm -rf /tmp/pkg /var/cache/apt
COPY rootfs/ /
COPY --from=builder /usr/local/lib/lua /usr/local/lib/lua
COPY --from=builder /usr/local/share/lua /usr/local/share/lua
RUN \
patch -d /usr/lib/prosody/modules/muc -p0 < /prosody-plugins/muc_owner_allow_kick.patch && \
patch -d /usr/bin -p1 < /prosodyctl-certdir-permission-fix.patch
# Apply config
RUN echo "TLS_REQCERT allow" >> /etc/ldap/ldap.conf
# Fix permissions
RUN \
/fix-permissions.sh && \
touch /etc/saslauthd.conf && \
chmod g=u -R /prosody-plugins /etc/saslauthd.conf && \
chgrp -R root /etc/sasldb2 /run/saslauthd
EXPOSE 5222 5347 5280
VOLUME ["/config", "/prosody-plugins-custom"]
USER 1001

@ -0,0 +1,184 @@
admins = {
"{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}",
"{{ .Env.JVB_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}"
}
plugin_paths = { "/prosody-plugins", "/prosody-plugins-custom" }
http_default_host = "{{ .Env.XMPP_DOMAIN }}"
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool }}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool)}}
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" }}
{{ $JWT_ASAP_KEYSERVER := .Env.JWT_ASAP_KEYSERVER | default "" }}
{{ $JWT_ALLOW_EMPTY := .Env.JWT_ALLOW_EMPTY | default "0" | toBool }}
{{ $JWT_AUTH_TYPE := .Env.JWT_AUTH_TYPE | default "token" }}
{{ $JWT_TOKEN_AUTH_MODULE := .Env.JWT_TOKEN_AUTH_MODULE | default "token_verification" }}
{{ $ENABLE_LOBBY := .Env.ENABLE_LOBBY | default "0" | toBool }}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool }}
{{ $PUBLIC_URL := .Env.PUBLIC_URL | default "https://localhost:8443" -}}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_ISSUERS }}
asap_accepted_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ISSUERS) }}" }
{{ end }}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_AUDIENCES }}
asap_accepted_audiences = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_AUDIENCES) }}" }
{{ end }}
consider_bosh_secure = true;
-- Deprecated in 0.12
-- https://github.com/bjc/prosody/commit/26542811eafd9c708a130272d7b7de77b92712de
{{ $XMPP_CROSS_DOMAINS := $PUBLIC_URL }}
{{ $XMPP_CROSS_DOMAIN := .Env.XMPP_CROSS_DOMAIN | default "" }}
{{ if eq $XMPP_CROSS_DOMAIN "true"}}
cross_domain_websocket = true
cross_domain_bosh = true
{{ else }}
{{ if not (eq $XMPP_CROSS_DOMAIN "false") }}
{{ $XMPP_CROSS_DOMAINS = list $PUBLIC_URL (print "https://" .Env.XMPP_DOMAIN) .Env.XMPP_CROSS_DOMAIN | join "," }}
{{ end }}
cross_domain_websocket = { "{{ join "\",\"" (splitList "," $XMPP_CROSS_DOMAINS) }}" }
cross_domain_bosh = { "{{ join "\",\"" (splitList "," $XMPP_CROSS_DOMAINS) }}" }
{{ end }}
VirtualHost "{{ .Env.XMPP_DOMAIN }}"
{{ if $ENABLE_AUTH }}
{{ if eq $AUTH_TYPE "jwt" }}
authentication = "{{ $JWT_AUTH_TYPE }}"
app_id = "{{ .Env.JWT_APP_ID }}"
app_secret = "{{ .Env.JWT_APP_SECRET }}"
allow_empty_token = {{ if $JWT_ALLOW_EMPTY }}true{{ else }}false{{ end }}
{{ if $JWT_ASAP_KEYSERVER }}
asap_key_server = "{{ .Env.JWT_ASAP_KEYSERVER }}"
{{ end }}
{{ else if eq $AUTH_TYPE "ldap" }}
authentication = "cyrus"
cyrus_application_name = "xmpp"
allow_unencrypted_plain_auth = true
{{ else if eq $AUTH_TYPE "internal" }}
authentication = "internal_hashed"
{{ end }}
{{ else }}
-- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
{{ if $ENABLE_XMPP_WEBSOCKET }}
authentication = "token"
{{ else }}
authentication = "anonymous"
{{ end }}
app_id = ""
app_secret = ""
allow_empty_token = true
{{ end }}
ssl = {
key = "/config/certs/{{ .Env.XMPP_DOMAIN }}.key";
certificate = "/config/certs/{{ .Env.XMPP_DOMAIN }}.crt";
}
modules_enabled = {
"bosh";
{{ if $ENABLE_XMPP_WEBSOCKET }}
"websocket";
"smacks"; -- XEP-0198: Stream Management
{{ end }}
"pubsub";
"ping";
"speakerstats";
"conference_duration";
{{ if $ENABLE_LOBBY }}
"muc_lobby_rooms";
{{ end }}
{{ if .Env.XMPP_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES) }}";
{{ end }}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "ldap") }}
"auth_cyrus";
{{end}}
}
{{ if $ENABLE_LOBBY }}
main_muc = "{{ .Env.XMPP_MUC_DOMAIN }}"
lobby_muc = "lobby.{{ .Env.XMPP_DOMAIN }}"
{{ if .Env.XMPP_RECORDER_DOMAIN }}
muc_lobby_whitelist = { "{{ .Env.XMPP_RECORDER_DOMAIN }}" }
{{ end }}
{{ end }}
speakerstats_component = "speakerstats.{{ .Env.XMPP_DOMAIN }}"
conference_duration_component = "conferenceduration.{{ .Env.XMPP_DOMAIN }}"
c2s_require_encryption = false
{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}"
-- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
{{ if $ENABLE_XMPP_WEBSOCKET }}
authentication = "token"
{{ else }}
authentication = "anonymous"
{{ end }}
app_id = ""
app_secret = ""
allow_empty_token = true
c2s_require_encryption = false
{{ end }}
VirtualHost "{{ .Env.XMPP_AUTH_DOMAIN }}"
ssl = {
key = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.key";
certificate = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.crt";
}
authentication = "internal_hashed"
{{ if .Env.XMPP_RECORDER_DOMAIN }}
VirtualHost "{{ .Env.XMPP_RECORDER_DOMAIN }}"
modules_enabled = {
"ping";
}
authentication = "internal_hashed"
{{ end }}
Component "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}" "muc"
storage = "memory"
modules_enabled = {
"ping";
{{ if .Env.XMPP_INTERNAL_MUC_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_INTERNAL_MUC_MODULES) }}";
{{ end }}
}
muc_room_locking = false
muc_room_default_public_jids = true
Component "{{ .Env.XMPP_MUC_DOMAIN }}" "muc"
storage = "memory"
modules_enabled = {
"muc_meeting_id";
{{ if .Env.XMPP_MUC_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES) }}";
{{ end }}
{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") }}
"{{ $JWT_TOKEN_AUTH_MODULE }}";
{{ end }}
}
muc_room_cache_size = 1000
muc_room_locking = false
muc_room_default_public_jids = true
Component "focus.{{ .Env.XMPP_DOMAIN }}"
component_secret = "{{ .Env.JICOFO_COMPONENT_SECRET }}"
Component "speakerstats.{{ .Env.XMPP_DOMAIN }}" "speakerstats_component"
muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"
Component "conferenceduration.{{ .Env.XMPP_DOMAIN }}" "conference_duration_component"
muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"
{{ if $ENABLE_LOBBY }}
Component "lobby.{{ .Env.XMPP_DOMAIN }}" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true
{{ end }}

@ -0,0 +1,172 @@
{{ $LOG_LEVEL := .Env.LOG_LEVEL | default "info" }}
-- Prosody Example Configuration File
--
-- Information on configuring Prosody can be found on our
-- website at http://prosody.im/doc/configure
--
-- Tip: You can check that the syntax of this file is correct
-- when you have finished by running: luac -p prosody.cfg.lua
-- If there are any errors, it will let you know what and where
-- they are, otherwise it will keep quiet.
--
-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!
---------- Server-wide settings ----------
-- Settings in this section apply to the whole server and are the default settings
-- for any virtual hosts
-- This is a (by default, empty) list of accounts that are admins
-- for the server. Note that you must create the accounts separately
-- (see http://prosody.im/doc/creating_accounts for info)
-- Example: admins = { "user1@example.com", "user2@example.net" }
admins = { }
-- Enable use of libevent for better performance under high load
-- For more information see: http://prosody.im/doc/libevent
--use_libevent = true;
-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation on modules can be found at: http://prosody.im/doc/modules
modules_enabled = {
-- Generally required
"roster"; -- Allow users to have a roster. Recommended ;)
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
"tls"; -- Add support for secure TLS on c2s/s2s connections
"dialback"; -- s2s dialback support
"disco"; -- Service discovery
-- Not essential, but recommended
"private"; -- Private XML storage (for room bookmarks, etc.)
"vcard"; -- Allow users to set vCards
-- These are commented by default as they have a performance impact
--"privacy"; -- Support privacy lists
--"compression"; -- Stream compression (Debian: requires lua-zlib module to work)
-- Nice to have
"version"; -- Replies to server version requests
"uptime"; -- Report how long server has been running
"time"; -- Let others know the time here on this server
"ping"; -- Replies to XMPP pings with pongs
"pep"; -- Enables users to publish their mood, activity, playing music and more
"register"; -- Allow users to register on this server using a client and change passwords
-- Admin interfaces
"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
-- HTTP modules
--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
--"http_files"; -- Serve static files from a directory over HTTP
-- Other specific functionality
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
--"groups"; -- Shared roster support
--"announce"; -- Send announcement to all online users
--"welcome"; -- Welcome users who register accounts
--"watchregistrations"; -- Alert admins of registrations
--"motd"; -- Send a message to users when they log in
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
{{ if .Env.GLOBAL_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.GLOBAL_MODULES) }}";
{{ end }}
};
https_ports = { }
-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
-- "offline"; -- Store offline messages
-- "c2s"; -- Handle client connections
"s2s"; -- Handle server-to-server connections
};
-- Disable account creation by default, for security
-- For more information see http://prosody.im/doc/creating_accounts
allow_registration = false;
daemonize = false;
-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.
c2s_require_encryption = false
-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see http://prosody.im/doc/s2s#security
s2s_secure_auth = false
-- Many servers don't support encryption or have invalid or self-signed
-- certificates. You can list domains here that will not be required to
-- authenticate using certificates. They will be authenticated using DNS.
--s2s_insecure_domains = { "gmail.com" }
-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.
--s2s_secure_domains = { "jabber.org" }
-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.
authentication = "internal_hashed"
-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See http://prosody.im/doc/storage for more info.
--storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the
-- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work)
-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
-- Logging configuration
-- For advanced logging see http://prosody.im/doc/logging
--
-- Debian:
-- Logs info and higher to /var/log
-- Logs errors to syslog also
log = {
{ levels = {min = "{{ $LOG_LEVEL }}"}, to = "console"};
}
{{ if .Env.GLOBAL_CONFIG }}
{{ join "\n" (splitList "\\n" .Env.GLOBAL_CONFIG) }}
{{ end }}
-- Enable use of native prosody 0.11 support for epoll over select
network_backend = "epoll";
-- Set the TCP backlog to 511 since the kernel rounds it up to the next power of 2: 512.
network_settings = {
tcp_backlog = 511;
}
component_interface = { "*" }
data_path = "/config/data"
smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
smacks_max_hibernated_sessions = 1;
smacks_max_old_sessions = 1;
Include "conf.d/*.cfg.lua"

@ -0,0 +1,26 @@
{{ if eq (.Env.AUTH_TYPE | default "internal") "ldap" }}
ldap_servers: {{ .Env.LDAP_URL }}
ldap_search_base: {{ .Env.LDAP_BASE }}
{{ if .Env.LDAP_BINDDN | default "" }}
ldap_bind_dn: {{ .Env.LDAP_BINDDN }}
ldap_bind_pw: {{ .Env.LDAP_BINDPW }}
{{ end }}
ldap_filter: {{ .Env.LDAP_FILTER | default "uid=%u" }}
ldap_version: {{ .Env.LDAP_VERSION | default "3" }}
ldap_auth_method: {{ .Env.LDAP_AUTH_METHOD | default "bind" }}
{{ if .Env.LDAP_USE_TLS | default "0" | toBool }}
ldap_tls_key: /config/certs/{{ .Env.XMPP_DOMAIN }}.key
ldap_tls_cert: /config/certs/{{ .Env.XMPP_DOMAIN }}.crt
{{ if .Env.LDAP_TLS_CHECK_PEER | default "0" | toBool }}
ldap_tls_check_peer: yes
ldap_tls_cacert_file: {{ .Env.LDAP_TLS_CACERT_FILE | default "/etc/ssl/certs/ca-certificates.crt" }}
ldap_tls_cacert_dir: {{ .Env.LDAP_TLS_CACERT_DIR | default "/etc/ssl/certs" }}
{{ end }}
{{ if .Env.LDAP_TLS_CIPHERS }}
ldap_tls_ciphers: {{ .Env.LDAP_TLS_CIPHERS }}
{{ end }}
{{ end }}
{{ end }}
{{ if .Env.LDAP_START_TLS | default "0" | toBool }}
ldap_start_tls: yes
{{ end }}

@ -0,0 +1,78 @@
#!/usr/bin/with-contenv bash
if [[ ! -f /etc/saslauthd.conf ]]; then
tpl /defaults/saslauthd.conf > /etc/saslauthd.conf
fi
PROSODY_CFG="/config/prosody.cfg.lua"
if [[ ! -d /config/data ]]; then
mkdir -pm 770 /config/data
fi
cp -r /defaults/* /config
tpl /defaults/prosody.cfg.lua > $PROSODY_CFG
tpl /defaults/conf.d/jitsi-meet.cfg.lua > /config/conf.d/jitsi-meet.cfg.lua
if [[ -z $JICOFO_COMPONENT_SECRET || -z $JICOFO_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: Jicofo component secret and auth password must be set'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JICOFO_AUTH_USER $XMPP_AUTH_DOMAIN $JICOFO_AUTH_PASSWORD
if [[ -z $JVB_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: JVB auth password must be set'
exit 1
fi
OLD_JVB_AUTH_PASSWORD=passw0rd
if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then
echo 'FATAL ERROR: JVB auth password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JVB_AUTH_USER $XMPP_AUTH_DOMAIN $JVB_AUTH_PASSWORD
if [[ ! -z $JIBRI_XMPP_USER ]] && [[ ! -z $JIBRI_XMPP_PASSWORD ]]; then
OLD_JIBRI_XMPP_PASSWORD=passw0rd
if [[ "$JIBRI_XMPP_PASSWORD" == "$OLD_JIBRI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri auth password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIBRI_XMPP_USER $XMPP_AUTH_DOMAIN $JIBRI_XMPP_PASSWORD
fi
if [[ ! -z $JIBRI_RECORDER_USER ]] && [[ ! -z $JIBRI_RECORDER_PASSWORD ]]; then
OLD_JIBRI_RECORDER_PASSWORD=passw0rd
if [[ "$JIBRI_RECORDER_PASSWORD" == "$OLD_JIBRI_RECORDER_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri recorder password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIBRI_RECORDER_USER $XMPP_RECORDER_DOMAIN $JIBRI_RECORDER_PASSWORD
fi
if [[ ! -z $JIGASI_XMPP_USER ]] && [[ ! -z $JIGASI_XMPP_PASSWORD ]]; then
OLD_JIGASI_XMPP_PASSWORD=passw0rd
if [[ "$JIGASI_XMPP_PASSWORD" == "$OLD_JIGASI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jigasi auth password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIGASI_XMPP_USER $XMPP_AUTH_DOMAIN $JIGASI_XMPP_PASSWORD
fi
mkdir -p /config/certs
if [[ ! -f /config/certs/$XMPP_DOMAIN.crt ]]; then
# echo for using all default values
echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_DOMAIN
fi
if [[ ! -f /config/certs/$XMPP_AUTH_DOMAIN.crt ]]; then
# echo for using all default values
echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_AUTH_DOMAIN
fi
# certs will be created in /config/data
mv /config/data/*.{crt,key} /config/certs/ || true
rm -f /config/data/*.cnf

@ -0,0 +1,2 @@
pwcheck_method: saslauthd
mech_list: PLAIN

@ -0,0 +1,2 @@
#!/usr/bin/with-contenv bash
exec saslauthd -a ldap -O /etc/saslauthd.conf -c -m /var/run/saslauthd -n 5 -d

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
exec prosody --config /config/prosody.cfg.lua

@ -0,0 +1,27 @@
diff --git a/prosodyctl b/prosodyctl
index 964285a..0fcf2a5 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -803,15 +803,17 @@ function commands.cert(arg)
return 1; -- TODO Should we create it?
end
local uid = pposix.getuid();
- if uid ~= 0 and uid ~= cert_dir_attrs.uid then
- show_warning("The directory "..cert_basedir.." is not owned by the current user, won't be able to write files to it");
+ local gid = pposix.getgid();
+ if uid ~= 0 and not (
+ (cert_dir_attrs.permissions:match("^.w.......$") and uid == cert_dir_attrs.uid) or
+ (cert_dir_attrs.permissions:match("^....w....$") and gid == cert_dir_attrs.gid) or
+ cert_dir_attrs.permissions:match("^.......w.$")
+ ) then
+ show_warning("The directory "..cert_basedir.." is not writable by this user");
return 1;
elseif not cert_dir_attrs.permissions then -- COMPAT with LuaFilesystem < 1.6.2 (hey CentOS!)
show_message("Unable to check permissions on "..cert_basedir.." (LuaFilesystem 1.6.2+ required)");
show_message("Please confirm that Prosody (and only Prosody) can write to this directory)");
- elseif cert_dir_attrs.permissions:match("^%.w..%-..%-.$") then
- show_warning("The directory "..cert_basedir.." not only writable by its owner");
- return 1;
end
local subcmd = table.remove(arg, 1);
if type(cert_commands[subcmd]) == "function" then

@ -0,0 +1,72 @@
#!/bin/bash
set -e
# Don't start a release if the tree is dirty
#
if [[ ! -z $(git status -s) ]]; then
echo "Git tree is not clean, aborting release!"
exit 1
fi
# Get version and branch (we only do stable for now)
#
V="$1"
RELEASE="${2:-stable}"
if [[ -z $V ]]; then
echo "A version must be specified!"
exit 1
fi
VERSION="${RELEASE}-${V}"
echo "Releasing ${VERSION}"
if git rev-parse "${VERSION}" >/dev/null 2>&1; then
echo "Tag for such version already exists!"
exit 1
fi
# Prepare changelog
#
LAST_VERSION=$(git describe --tags --abbrev=0)
CHANGES=$(git log --oneline --no-decorate --no-merges ${LAST_VERSION}..HEAD --pretty=format:"%x2a%x20%h%x20%s")
echo "Changelog:"
echo "$CHANGES"
echo -e "## ${VERSION}\n\nBased on ${RELEASE} release ${V}.\n\n${CHANGES}\n" > tmp
cat CHANGELOG.md >> tmp
mv tmp CHANGELOG.md
# Set specific image tags in compose files
#
sed -i "" -e "s/latest/${VERSION}/" *.yml
# Commit all changes and tag the repo
#
git commit -a -m "release: ${VERSION}" -m "${CHANGES}"
git tag -a "${VERSION}" -m "release" -m "${CHANGES}"
# Tag Docker images and push them to DockerHub
#
JITSI_BUILD=${VERSION} make release
# Revert back to "latest" for development
#
sed -i "" -e "s/${VERSION}/latest/" *.yml
git commit -a -m "misc: working on latest"
# Push all changes and tags
#
git push
git push --tags

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

@ -0,0 +1,24 @@
ARG JITSI_REPO=jitsi
FROM ${JITSI_REPO}/base
ADD https://raw.githubusercontent.com/acmesh-official/acme.sh/2.8.8/acme.sh /opt
COPY rootfs/ /
RUN \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y cron nginx-extras jitsi-meet-web socat && \
apt-dpkg-wrap apt-get -d install -y jitsi-meet-web-config && \
dpkg -x /var/cache/apt/archives/jitsi-meet-web-config*.deb /tmp/pkg && \
mv /tmp/pkg/usr/share/jitsi-meet-web-config/config.js /defaults && \
mv /usr/share/jitsi-meet/interface_config.js /defaults && \
rm -f /etc/nginx/conf.d/default.conf && \
apt-cleanup && \
rm -rf /tmp/pkg /var/cache/apt
RUN /fix-permissions.sh
EXPOSE 8080 4443
VOLUME ["/config", "/usr/share/jitsi-meet/transcripts"]
USER 1001

@ -0,0 +1,26 @@
server {
listen 8080 default_server;
{{ if .Env.ENABLE_IPV6 | default "1" | toBool }}
listen [::]:8080 default_server;
{{ end }}
{{ if .Env.ENABLE_HTTP_REDIRECT | default "0" | toBool }}
return 301 https://$host$request_uri;
{{ else }}
include /config/nginx/meet.conf;
{{ end }}
}
{{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }}
server {
listen 4443 ssl http2;
{{ if .Env.ENABLE_IPV6 | default "1" | toBool }}
listen [::]:4443 ssl http2;
{{ end }}
include /config/nginx/ssl.conf;
include /config/nginx/meet.conf;
}
{{ end }}

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----

@ -0,0 +1,92 @@
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool }}
server_name _;
client_max_body_size 0;
root /usr/share/jitsi-meet;
# ssi on with javascript for multidomain variables in config.js
ssi on;
ssi_types application/x-javascript application/javascript;
index index.html index.htm;
error_page 404 /static/404.html;
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location = /config.js {
alias /config/config.js;
}
location = /interface_config.js {
alias /config/interface_config.js;
}
location = /external_api.js {
alias /usr/share/jitsi-meet/libs/external_api.min.js;
}
# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
{
add_header 'Access-Control-Allow-Origin' '*';
alias /usr/share/jitsi-meet/$1/$2;
}
# colibri (JVB) websockets
location ~ ^/colibri-ws/([a-zA-Z0-9-\.]+)/(.*) {
proxy_pass http://$1:9090/colibri-ws/$1/$2$is_args$args;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
}
# BOSH
location = /http-bind {
proxy_pass {{ .Env.XMPP_BOSH_URL_BASE }}/http-bind;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
}
{{ if $ENABLE_XMPP_WEBSOCKET }}
# xmpp websockets
location = /xmpp-websocket {
proxy_pass {{ .Env.XMPP_BOSH_URL_BASE }}/xmpp-websocket;
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
proxy_set_header X-Forwarded-For $remote_addr;
tcp_nodelay on;
}
{{ end }}
location ~ ^/([^/?&:'"]+)$ {
try_files $uri @root_path;
}
location @root_path {
rewrite ^/(.*)$ / break;
}
{{ if .Env.ETHERPAD_URL_BASE }}
# Etherpad-lite
location /etherpad/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_pass {{ .Env.ETHERPAD_URL_BASE }}/;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
proxy_set_header Host {{ .Env.XMPP_DOMAIN }};
}
{{ end }}

@ -0,0 +1,67 @@
worker_processes {{ .Env.NGINX_WORKER_PROCESSES | default "4" }};
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections {{ .Env.NGINX_WORKER_CONNECTIONS | default "768" }};
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
client_max_body_size 0;
resolver {{ .Env.NGINX_RESOLVER | default "127.0.0.11" }};
include /etc/nginx/mime.types;
types {
# add support for wasm MIME type, that is required by specification and it is not part of default mime.types file
application/wasm wasm;
}
default_type application/octet-stream;
##
# Logging Settings
##
access_log /dev/stdout;
error_log /dev/stderr;
##
# Gzip Settings
##
gzip on;
gzip_types text/plain text/css application/javascript application/json;
gzip_vary on;
gzip_min_length 860;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /config/nginx/site-confs/*;
}
daemon off;

@ -0,0 +1,306 @@
{{ $DEPLOYMENTINFO_USERREGION := .Env.DEPLOYMENTINFO_USERREGION | default "" -}}
{{ $BRIDGE_CHANNEL := .Env.BRIDGE_CHANNEL | default "websocket" -}}
{{ $ENABLE_AUDIO_PROCESSING := .Env.ENABLE_AUDIO_PROCESSING | default "true" | toBool -}}
{{ $ENABLE_CALENDAR := .Env.ENABLE_CALENDAR | default "false" | toBool -}}
{{ $ENABLE_FILE_RECORDING_SERVICE := .Env.ENABLE_FILE_RECORDING_SERVICE | default "false" | toBool -}}
{{ $ENABLE_FILE_RECORDING_SERVICE_SHARING := .Env.ENABLE_FILE_RECORDING_SERVICE_SHARING | default "false" | toBool -}}
{{ $ENABLE_IPV6 := .Env.ENABLE_IPV6 | default "true" | toBool -}}
{{ $ENABLE_LIPSYNC := .Env.ENABLE_LIPSYNC | default "false" | toBool -}}
{{ $ENABLE_NO_AUDIO_DETECTION := .Env.ENABLE_NO_AUDIO_DETECTION | default "false" | toBool -}}
{{ $ENABLE_P2P := .Env.ENABLE_P2P | default "true" | toBool -}}
{{ $ENABLE_PREJOIN_PAGE := .Env.ENABLE_PREJOIN_PAGE | default "false" | toBool -}}
{{ $ENABLE_WELCOME_PAGE := .Env.ENABLE_WELCOME_PAGE | default "true" | toBool -}}
{{ $ENABLE_CLOSE_PAGE := .Env.ENABLE_CLOSE_PAGE | default "false" | toBool -}}
{{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "false" | toBool -}}
{{ $ENABLE_REMB := .Env.ENABLE_REMB | default "true" | toBool -}}
{{ $ENABLE_REQUIRE_DISPLAY_NAME := .Env.ENABLE_REQUIRE_DISPLAY_NAME | default "false" | toBool -}}
{{ $ENABLE_SIMULCAST := .Env.ENABLE_SIMULCAST | default "true" | toBool -}}
{{ $ENABLE_STATS_ID := .Env.ENABLE_STATS_ID | default "false" | toBool -}}
{{ $ENABLE_STEREO := .Env.ENABLE_STEREO | default "false" | toBool -}}
{{ $ENABLE_TALK_WHILE_MUTED := .Env.ENABLE_TALK_WHILE_MUTED | default "false" | toBool -}}
{{ $ENABLE_TCC := .Env.ENABLE_TCC | default "true" | toBool -}}
{{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "false" | toBool -}}
{{ $RESOLUTION := .Env.RESOLUTION | default "720" -}}
{{ $RESOLUTION_MIN := .Env.RESOLUTION_MIN | default "180" -}}
{{ $RESOLUTION_WIDTH := .Env.RESOLUTION_WIDTH | default "1280" -}}
{{ $RESOLUTION_WIDTH_MIN := .Env.RESOLUTION_WIDTH_MIN | default "320" -}}
{{ $START_AUDIO_ONLY := .Env.START_AUDIO_ONLY | default "false" | toBool -}}
{{ $START_AUDIO_MUTED := .Env.START_AUDIO_MUTED | default 10 -}}
{{ $DISABLE_AUDIO_LEVELS := .Env.DISABLE_AUDIO_LEVELS | default "false" | toBool -}}
{{ $ENABLE_NOISY_MIC_DETECTION := .Env.ENABLE_NOISY_MIC_DETECTION | default "true" | toBool -}}
{{ $START_VIDEO_MUTED := .Env.START_VIDEO_MUTED | default 10 -}}
{{ $DESKTOP_SHARING_FRAMERATE_MIN := .Env.DESKTOP_SHARING_FRAMERATE_MIN | default 5 -}}
{{ $DESKTOP_SHARING_FRAMERATE_MAX := .Env.DESKTOP_SHARING_FRAMERATE_MAX | default 5 -}}
{{ $TESTING_OCTO_PROBABILITY := .Env.TESTING_OCTO_PROBABILITY | default "0" -}}
{{ $TESTING_CAP_SCREENSHARE_BITRATE := .Env.TESTING_CAP_SCREENSHARE_BITRATE | default "1" -}}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN -}}
{{ $XMPP_RECORDER_DOMAIN := .Env.XMPP_RECORDER_DOMAIN -}}
// Video configuration.
//
if (!config.hasOwnProperty('constraints')) config.constraints = {};
if (!config.constraints.hasOwnProperty('video')) config.constraints.video = {};
config.resolution = {{ $RESOLUTION }};
config.constraints.video.height = { ideal: {{ $RESOLUTION }}, max: {{ $RESOLUTION }}, min: {{ $RESOLUTION_MIN }} };
config.constraints.video.width = { ideal: {{ $RESOLUTION_WIDTH }}, max: {{ $RESOLUTION_WIDTH }}, min: {{ $RESOLUTION_WIDTH_MIN }}};
config.disableSimulcast = {{ not $ENABLE_SIMULCAST }};
config.startVideoMuted = {{ $START_VIDEO_MUTED }};
{{ if .Env.START_BITRATE -}}
config.startBitrate = '{{ .Env.START_BITRATE }}';
{{ end -}}
// ScreenShare Configuration.
//
config.desktopSharingFrameRate = { min: {{ $DESKTOP_SHARING_FRAMERATE_MIN }}, max: {{ $DESKTOP_SHARING_FRAMERATE_MAX }} };
// Audio configuration.
//
config.enableNoAudioDetection = {{ $ENABLE_NO_AUDIO_DETECTION }};
config.enableTalkWhileMuted = {{ $ENABLE_TALK_WHILE_MUTED }};
config.disableAP = {{ not $ENABLE_AUDIO_PROCESSING }};
config.stereo = {{ $ENABLE_STEREO }};
config.startAudioOnly = {{ $START_AUDIO_ONLY }};
config.startAudioMuted = {{ $START_AUDIO_MUTED }};
config.disableAudioLevels = {{ $DISABLE_AUDIO_LEVELS }};
config.enableNoisyMicDetection = {{ $ENABLE_NOISY_MIC_DETECTION }};
// Peer-to-Peer options.
//
if (!config.hasOwnProperty('p2p')) config.p2p = {};
config.p2p.enabled = {{ $ENABLE_P2P }};
// Etherpad
//
{{ if .Env.ETHERPAD_PUBLIC_URL -}}
config.etherpad_base = '{{ .Env.ETHERPAD_PUBLIC_URL }}';
{{ else if .Env.ETHERPAD_URL_BASE -}}
config.etherpad_base = '{{.Env.PUBLIC_URL}}/etherpad/p/';
{{ end -}}
// Recording.
//
{{ if $ENABLE_RECORDING -}}
config.hiddenDomain = '{{ $XMPP_RECORDER_DOMAIN }}';
// Whether to enable file recording or not
config.fileRecordingsEnabled = true;
// Whether to enable live streaming or not.
config.liveStreamingEnabled = true;
{{ if .Env.DROPBOX_APPKEY -}}
// Enable the dropbox integration.
if (!config.hasOwnProperty('dropbox')) config.dropbox = {};
config.dropbox.appKey = '{{ .Env.DROPBOX_APPKEY }}';
{{ if .Env.DROPBOX_REDIRECT_URI -}}
// A URL to redirect the user to, after authenticating
// by default uses:
// 'https://jitsi-meet.example.com/static/oauth.html'
config.dropbox.redirectURI = '{{ .Env.DROPBOX_REDIRECT_URI }}';
{{ end -}}
{{ end -}}
{{ if $ENABLE_FILE_RECORDING_SERVICE -}}
// When integrations like dropbox are enabled only that will be shown,
// by enabling fileRecordingsServiceEnabled, we show both the integrations
// and the generic recording service (its configuration and storage type
// depends on jibri configuration)
config.fileRecordingsServiceEnabled = true;
{{ end -}}
{{ if $ENABLE_FILE_RECORDING_SERVICE_SHARING -}}
// Whether to show the possibility to share file recording with other people
// (e.g. meeting participants), based on the actual implementation
// on the backend.
config.fileRecordingsServiceSharingEnabled = true;
{{ end -}}
{{ end -}}
// Analytics.
//
if (!config.hasOwnProperty('analytics')) config.analytics = {};
{{ if .Env.AMPLITUDE_ID -}}
// The Amplitude APP Key:
config.analytics.amplitudeAPPKey = '{{ .Env.AMPLITUDE_ID }}';
{{ end -}}
{{ if .Env.GOOGLE_ANALYTICS_ID -}}
// The Google Analytics Tracking ID:
config.analytics.googleAnalyticsTrackingId = '{{ .Env.GOOGLE_ANALYTICS_ID }}';
{{ end -}}
{{ if .Env.MATOMO_ENDPOINT -}}
// Matomo endpoint:
config.analytics.matomoEndpoint = '{{ .Env.MATOMO_ENDPOINT }}';
{{ end -}}
{{ if .Env.MATOMO_SITE_ID -}}
// Matomo site ID:
config.analytics.matomoSiteID = '{{ .Env.MATOMO_SITE_ID }}';
{{ end -}}
{{ if .Env.ANALYTICS_SCRIPT_URLS -}}
// Array of script URLs to load as lib-jitsi-meet "analytics handlers".
config.analytics.scriptURLs = [ '{{ join "','" (splitList "," .Env.ANALYTICS_SCRIPT_URLS) }}' ];
{{ end -}}
{{ if .Env.ANALYTICS_WHITELISTED_EVENTS -}}
config.analytics.whiteListedEvents = [ '{{ join "','" (splitList "," .Env.ANALYTICS_WHITELISTED_EVENTS) }}' ];
{{ end -}}
{{ if .Env.CALLSTATS_CUSTOM_SCRIPT_URL -}}
config.callStatsCustomScriptUrl = '{{ .Env.CALLSTATS_CUSTOM_SCRIPT_URL }}';
{{ end -}}
{{ if .Env.CALLSTATS_ID -}}
// To enable sending statistics to callstats.io you must provide the
// Application ID and Secret.
config.callStatsID = '{{ .Env.CALLSTATS_ID }}';
{{ end -}}
{{ if .Env.CALLSTATS_ID -}}
config.callStatsSecret = '{{ .Env.CALLSTATS_SECRET }}';
{{ end -}}
// Enables callstatsUsername to be reported as statsId and used
// by callstats as repoted remote id.
config.enableStatsID = {{ $ENABLE_STATS_ID }};
// Dial in/out services.
//
{{ if .Env.CONFCODE_URL -}}
config.dialInConfCodeUrl = '{{ .Env.CONFCODE_URL }}';
{{ end -}}
{{ if .Env.DIALIN_NUMBERS_URL -}}
config.dialInNumbersUrl = '{{ .Env.DIALIN_NUMBERS_URL }}';
{{ end -}}
{{ if .Env.DIALOUT_AUTH_URL -}}
config.dialOutAuthUrl = '{{ .Env.DIALOUT_AUTH_URL }}';
{{ end -}}
{{ if .Env.DIALOUT_CODES_URL -}}
config.dialOutCodesUrl = '{{ .Env.DIALOUT_CODES_URL }}';
{{ end -}}
// Calendar service integration.
//
config.enableCalendarIntegration = {{ $ENABLE_CALENDAR }};
{{ if .Env.GOOGLE_API_APP_CLIENT_ID -}}
config.googleApiApplicationClientID = '{{ .Env.GOOGLE_API_APP_CLIENT_ID }}';
{{ end -}}
{{ if .Env.MICROSOFT_API_APP_CLIENT_ID -}}
config.microsoftApiApplicationClientID = '{{ .Env.MICROSOFT_API_APP_CLIENT_ID }}';
{{ end -}}
// Invitation service.
//
{{ if .Env.INVITE_SERVICE_URL -}}
config.inviteServiceUrl = '{{ .Env.INVITE_SERVICE_URL }}';
{{ end -}}
{{ if .Env.PEOPLE_SEARCH_URL -}}
config.peopleSearchUrl = '{{ .Env.PEOPLE_SEARCH_URL }}';
config.peopleSearchQueryTypes = ['user','conferenceRooms'];
{{ end -}}
// Miscellaneous.
//
// Prejoin page.
config.prejoinPageEnabled = {{ $ENABLE_PREJOIN_PAGE }};
// Welcome page.
config.enableWelcomePage = {{ $ENABLE_WELCOME_PAGE }};
// Close page.
config.enableClosePage = {{ $ENABLE_CLOSE_PAGE }};
// Require users to always specify a display name.
config.requireDisplayName = {{ $ENABLE_REQUIRE_DISPLAY_NAME }};
// Chrome extension banner.
{{ if .Env.CHROME_EXTENSION_BANNER_JSON -}}
config.chromeExtensionBanner = {{ .Env.CHROME_EXTENSION_BANNER_JSON }};
{{ end -}}
// Advanced.
//
// Lipsync hack in jicofo, may not be safe.
config.enableLipSync = {{ $ENABLE_LIPSYNC }};
config.enableRemb = {{ $ENABLE_REMB }};
config.enableTcc = {{ $ENABLE_TCC }};
config.openBridgeChannel = '{{ $BRIDGE_CHANNEL }}';
// Enable IPv6 support.
config.useIPv6 = {{ $ENABLE_IPV6 }};
// Transcriptions (subtitles and buttons can be configured in interface_config)
config.transcribingEnabled = {{ $ENABLE_TRANSCRIPTIONS }};
{{ if .Env.DYNAMIC_BRANDING_URL -}}
// External API url used to receive branding specific information.
config.dynamicBrandingUrl = '{{ .Env.DYNAMIC_BRANDING_URL }}';
{{ end -}}
{{ if .Env.TOKEN_AUTH_URL -}}
// Authenticate using external service or just focus external auth window if there is one already.
config.tokenAuthUrl = '{{ .Env.TOKEN_AUTH_URL }}';
{{ end -}}
// Deployment information.
//
if (!config.hasOwnProperty('deploymentInfo')) config.deploymentInfo = {};
{{ if .Env.DEPLOYMENTINFO_ENVIRONMENT -}}
config.deploymentInfo.environment = '{{ .Env.DEPLOYMENTINFO_ENVIRONMENT }}';
{{ end -}}
{{ if .Env.DEPLOYMENTINFO_ENVIRONMENT_TYPE -}}
config.deploymentInfo.envType = '{{ .Env.DEPLOYMENTINFO_ENVIRONMENT_TYPE }}';
{{ end -}}
{{ if $DEPLOYMENTINFO_USERREGION -}}
config.deploymentInfo.userRegion = '{{ $DEPLOYMENTINFO_USERREGION }}';
{{ end -}}
// Testing
//
if (!config.hasOwnProperty('testing')) config.testing = {};
if (!config.testing.hasOwnProperty('octo')) config.testing.octo = {};
config.testing.capScreenshareBitrate = {{ $TESTING_CAP_SCREENSHARE_BITRATE }};
config.testing.octo.probability = {{ $TESTING_OCTO_PROBABILITY }};

@ -0,0 +1,28 @@
# session settings
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# ssl certs
{{ if .Env.ENABLE_LETSENCRYPT | default "0" | toBool }}
ssl_certificate /config/acme-certs/{{ .Env.LETSENCRYPT_DOMAIN }}/fullchain.pem;
ssl_certificate_key /config/acme-certs/{{ .Env.LETSENCRYPT_DOMAIN }}/key.pem;
{{ else }}
ssl_certificate /config/keys/cert.crt;
ssl_certificate_key /config/keys/cert.key;
{{ end }}
# protocols
# Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, intermediate configuration, no OCSP
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&ocsp=false&guideline=5.6
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Diffie-Hellman parameter for DHE cipher suites
ssl_dhparam /defaults/ffdhe2048.txt;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
{{ if .Env.ENABLE_HSTS | default "1" | toBool }}
add_header Strict-Transport-Security "max-age=63072000" always;
{{ end }}

@ -0,0 +1,50 @@
{{ $CONFIG_EXTERNAL_CONNECT := .Env.CONFIG_EXTERNAL_CONNECT | default "false" | toBool -}}
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "false" | toBool -}}
{{ $ENABLE_GUESTS := .Env.ENABLE_GUESTS | default "false" | toBool -}}
{{ $ENABLE_SUBDOMAINS := .Env.ENABLE_SUBDOMAINS | default "false" | toBool -}}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool -}}
{{ $JICOFO_AUTH_USER := .Env.JICOFO_AUTH_USER | default "focus" }}
{{ $PUBLIC_URL_DOMAIN := .Env.PUBLIC_URL | default "https://localhost:8443" | trimPrefix "https://" | trimSuffix "/" -}}
{{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN -}}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN -}}
{{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN -}}
{{ $XMPP_MUC_DOMAIN_PREFIX := (split "." .Env.XMPP_MUC_DOMAIN)._0 -}}
// Begin default config overrides.
if (!config.hasOwnProperty('hosts')) config.hosts = {};
config.hosts.domain = '{{ $XMPP_DOMAIN }}';
config.focusUserJid = '{{$JICOFO_AUTH_USER}}@{{$XMPP_AUTH_DOMAIN}}';
{{ if $ENABLE_SUBDOMAINS -}}
var subdomain = "<!--# echo var="subdomain" default="" -->";
if (subdomain) {
subdomain = subdomain.substr(0,subdomain.length-1).split('.').join('_').toLowerCase() + '.';
}
config.hosts.muc = '{{ $XMPP_MUC_DOMAIN_PREFIX }}.'+subdomain+'{{ $XMPP_DOMAIN }}';
{{ else -}}
config.hosts.muc = '{{ $XMPP_MUC_DOMAIN }}';
{{ end -}}
{{ if $ENABLE_AUTH -}}
{{ if $ENABLE_GUESTS -}}
// When using authentication, domain for guest users.
config.hosts.anonymousdomain = '{{ .Env.XMPP_GUEST_DOMAIN }}';
{{ end -}}
// Domain for authenticated users. Defaults to <domain>.
config.hosts.authdomain = '{{ $XMPP_DOMAIN }}';
{{ end -}}
config.bosh = '/http-bind';
{{ if $ENABLE_XMPP_WEBSOCKET -}}
config.websocket = 'wss://{{ $PUBLIC_URL_DOMAIN }}/xmpp-websocket';
{{ end -}}
{{ if $CONFIG_EXTERNAL_CONNECT -}}
{{ if $ENABLE_SUBDOMAINS -}}
config.externalConnectUrl = '/<!--# echo var="subdir" default="" -->http-pre-bind';
{{ else -}}
config.externalConnectUrl = '/http-pre-bind';
{{ end -}}
{{ end -}}

@ -0,0 +1,95 @@
#!/usr/bin/with-contenv bash
# make our folders
mkdir -p \
/config/{nginx/site-confs,keys} \
/var/lib/nginx/tmp/client_body \
/var/tmp/nginx
# generate keys (maybe)
if [[ $DISABLE_HTTPS -ne 1 ]]; then
if [[ $ENABLE_LETSENCRYPT -eq 1 ]]; then
if [[ ! -f /config/acme.sh/acme.sh ]]; then
mkdir /config/acme.sh
pushd /opt
sh ./acme.sh --install --home /config/acme.sh --accountemail $LETSENCRYPT_EMAIL
popd
fi
if [[ ! -f /config/acme-certs/$LETSENCRYPT_DOMAIN/fullchain.pem ]]; then
STAGING=""
if [[ $LETSENCRYPT_USE_STAGING -eq 1 ]]; then
STAGING="--staging"
fi
export LE_WORKING_DIR="/config/acme.sh"
# TODO: move away from standalone mode to webroot mode.
/config/acme.sh/acme.sh \
$STAGING \
--issue \
--standalone \
--pre-hook "if [[ -f /var/run/s6/services/nginx ]]; then s6-svc -d /var/run/s6/services/nginx; fi" \
--post-hook "if [[ -f /var/run/s6/services/nginx ]]; then s6-svc -u /var/run/s6/services/nginx; fi" \
-d $LETSENCRYPT_DOMAIN
rc=$?
if [[ $rc -eq 1 ]]; then
echo "Failed to obtain a certificate from the Let's Encrypt CA."
# this tries to get the user's attention and to spare the
# authority's rate limit:
sleep 15
echo "Exiting."
exit 1
fi
mkdir -p /config/acme-certs/$LETSENCRYPT_DOMAIN
if ! /config/acme.sh/acme.sh \
--install-cert -d $LETSENCRYPT_DOMAIN \
--key-file /config/acme-certs/$LETSENCRYPT_DOMAIN/key.pem \
--fullchain-file /config/acme-certs/$LETSENCRYPT_DOMAIN/fullchain.pem ; then
echo "Failed to install certificate."
# this tries to get the user's attention and to spare the
# authority's rate limit:
sleep 15
echo "Exiting."
exit 1
fi
fi
else
# use self-signed certs
if [[ -f /config/keys/cert.key && -f /config/keys/cert.crt ]]; then
echo "using keys found in /config/keys"
else
echo "generating self-signed keys in /config/keys, you can replace these with your own keys if required"
SUBJECT="/C=US/ST=TX/L=Austin/O=jitsi.org/OU=Jitsi Server/CN=*"
openssl req -new -x509 -days 3650 -nodes -out /config/keys/cert.crt -keyout /config/keys/cert.key -subj "$SUBJECT"
fi
fi
fi
# copy config files
tpl /defaults/nginx.conf > /config/nginx/nginx.conf
tpl /defaults/meet.conf > /config/nginx/meet.conf
if [[ -f /config/nginx/custom-meet.conf ]]; then
cat /config/nginx/custom-meet.conf >> /config/nginx/meet.conf
fi
tpl /defaults/ssl.conf > /config/nginx/ssl.conf
tpl /defaults/default > /config/nginx/site-confs/default
cp /defaults/config.js /config/config.js
tpl /defaults/system-config.js >> /config/config.js
tpl /defaults/settings-config.js >> /config/config.js
if [[ -f /config/custom-config.js ]]; then
cat /config/custom-config.js >> /config/config.js
fi
if [[ ! -f /config/interface_config.js ]]; then
cp /defaults/interface_config.js /config/interface_config.js
# It will remove parameter 'closedcaptions' from TOOLBAR_BUTTONS if ENABLE_TRANSCRIPTIONS is false,
# because it enabled by default, but not supported out of the box.
if [[ $ENABLE_TRANSCRIPTIONS -ne 1 && "$ENABLE_TRANSCRIPTIONS" != "true" ]]; then
sed -i \
-e "s#'closedcaptions', ##" \
/config/interface_config.js
fi
fi

@ -0,0 +1,10 @@
#!/usr/bin/with-contenv bash
if [[ $DISABLE_HTTPS -ne 1 ]] && \
[[ $ENABLE_LETSENCRYPT -eq 1 ]]; then
exec cron -f
else
# if cron should not be started,
# prevent s6 from restarting this script again and again
s6-svc -O /var/run/s6/services/cron
fi

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
exec nginx -c /config/nginx/nginx.conf
Loading…
Cancel
Save