mirror of
https://github.com/casjaysdevdocker/prosody
synced 2026-06-23 20:01:02 -04:00
🦈🏠🐜❗ Initial Commit ❗🐜🦈🏠
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
# .dockerignore created on 05/19/26 at 09:30
|
||||||
|
|
||||||
|
# version control
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
|
||||||
|
# local and secret config
|
||||||
|
.env
|
||||||
|
app.env
|
||||||
|
default.env
|
||||||
|
.claude/
|
||||||
|
|
||||||
|
# build artifacts
|
||||||
|
binaries/
|
||||||
|
releases/
|
||||||
|
|
||||||
|
# runtime volume data (never in image)
|
||||||
|
volumes/
|
||||||
|
docker/volumes/
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# docs and meta (not needed in image)
|
||||||
|
*.md
|
||||||
|
LICENSE*
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Template generated on Sun May 17 10:58:44 PM EDT 2026 from https://github.com/alexkaratarakis/gitattributes"
|
||||||
|
# Common settings that generally should always be used with your language specific settings
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
# The above will handle all files NOT found below
|
||||||
|
# Documents
|
||||||
|
*.bibtex text diff=bibtex
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
||||||
|
*.md text diff=markdown
|
||||||
|
*.mdx text diff=markdown
|
||||||
|
*.tex text diff=tex
|
||||||
|
*.adoc text
|
||||||
|
*.textile text
|
||||||
|
*.mustache text
|
||||||
|
*.csv text eol=crlf
|
||||||
|
*.tab text
|
||||||
|
*.tsv text
|
||||||
|
*.txt text
|
||||||
|
*.sql text
|
||||||
|
*.epub diff=astextplain
|
||||||
|
# Graphics
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.tif binary
|
||||||
|
*.tiff binary
|
||||||
|
*.ico binary
|
||||||
|
# SVG treated as text by default.
|
||||||
|
*.svg text
|
||||||
|
# If you want to treat it as binary,
|
||||||
|
# use the following line instead.
|
||||||
|
# *.svg binary
|
||||||
|
*.eps binary
|
||||||
|
# Scripts
|
||||||
|
*.bash text eol=lf
|
||||||
|
*.fish text eol=lf
|
||||||
|
*.ksh text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.zsh text eol=lf
|
||||||
|
# These are explicitly windows files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
# Serialisation
|
||||||
|
*.json text
|
||||||
|
*.toml text
|
||||||
|
*.xml text
|
||||||
|
*.yaml text
|
||||||
|
*.yml text
|
||||||
|
# Archives
|
||||||
|
*.7z binary
|
||||||
|
*.bz binary
|
||||||
|
*.bz2 binary
|
||||||
|
*.bzip2 binary
|
||||||
|
*.gz binary
|
||||||
|
*.lz binary
|
||||||
|
*.lzma binary
|
||||||
|
*.rar binary
|
||||||
|
*.tar binary
|
||||||
|
*.taz binary
|
||||||
|
*.tbz binary
|
||||||
|
*.tbz2 binary
|
||||||
|
*.tgz binary
|
||||||
|
*.tlz binary
|
||||||
|
*.txz binary
|
||||||
|
*.xz binary
|
||||||
|
*.Z binary
|
||||||
|
*.zip binary
|
||||||
|
*.zst binary
|
||||||
|
# Text files where line endings should be preserved
|
||||||
|
*.patch -text
|
||||||
|
# Exclude files from exporting
|
||||||
|
.gitattributes export-ignore
|
||||||
|
.gitignore export-ignore
|
||||||
|
.gitkeep export-ignore
|
||||||
|
|
||||||
|
# Template generated on Sun May 17 10:58:44 PM EDT 2026
|
||||||
|
# Files for git large file system
|
||||||
|
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.rpm filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.7zip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bzip2 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Global owners — review required for everything not covered below
|
||||||
|
* @casjaysdevdocker
|
||||||
|
|
||||||
|
# Workflow changes require maintainer sign-off
|
||||||
|
.github/ @casjaysdevdocker
|
||||||
|
|
||||||
|
# Docker assets
|
||||||
|
docker/ @casjaysdevdocker
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- uses: docker/setup-buildx-action@b5730e1a0a27db01e64c4ab5f4f7c8a63c1de14a # v3.10.0
|
||||||
|
|
||||||
|
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- uses: docker/metadata-action@902fa8ec7d6ecbea8a986b37db18de1c4e72470b # v5.7.0
|
||||||
|
id: meta
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
|
||||||
|
tags: |
|
||||||
|
type=edge,branch=main
|
||||||
|
type=sha,prefix=sha-
|
||||||
|
annotations: |
|
||||||
|
maintainer=${{ github.repository_owner }} <${{ github.repository_owner }}@casjay.pro>
|
||||||
|
org.opencontainers.image.vendor=${{ github.repository_owner }}
|
||||||
|
org.opencontainers.image.authors=${{ github.repository_owner }}
|
||||||
|
org.opencontainers.image.title=${{ github.event.repository.name }}
|
||||||
|
org.opencontainers.image.description=Containerized version of ${{ github.event.repository.name }}
|
||||||
|
org.opencontainers.image.url=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.source=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.documentation=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.vcs-type=Git
|
||||||
|
com.github.containers.toolbox=false
|
||||||
|
|
||||||
|
- uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/Dockerfile
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
labels: ""
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Build and publish release image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- uses: docker/setup-buildx-action@b5730e1a0a27db01e64c4ab5f4f7c8a63c1de14a # v3.10.0
|
||||||
|
|
||||||
|
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: version
|
||||||
|
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: docker/metadata-action@902fa8ec7d6ecbea8a986b37db18de1c4e72470b # v5.7.0
|
||||||
|
id: meta
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=raw,value=latest
|
||||||
|
type=raw,value=${{ steps.version.outputs.version }}
|
||||||
|
annotations: |
|
||||||
|
maintainer=${{ github.repository_owner }} <${{ github.repository_owner }}@casjay.pro>
|
||||||
|
org.opencontainers.image.vendor=${{ github.repository_owner }}
|
||||||
|
org.opencontainers.image.authors=${{ github.repository_owner }}
|
||||||
|
org.opencontainers.image.title=${{ github.event.repository.name }}
|
||||||
|
org.opencontainers.image.description=Containerized version of ${{ github.event.repository.name }}
|
||||||
|
org.opencontainers.image.url=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.source=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.documentation=${{ github.event.repository.html_url }}
|
||||||
|
org.opencontainers.image.vcs-type=Git
|
||||||
|
com.github.containers.toolbox=false
|
||||||
|
|
||||||
|
- uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
labels: ""
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ steps.version.outputs.version }}
|
||||||
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
||||||
|
VCS_REF=${{ github.sha }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: softprops/action-gh-release@da05d552573ad5aba039edc1654bcb6e02e54e87 # v2.2.2
|
||||||
|
with:
|
||||||
|
generate_release_notes: true
|
||||||
|
tag_name: ${{ github.ref_name }}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
# gitignore created on 05/19/26 at 09:30
|
||||||
|
ignoredirmessage
|
||||||
|
|
||||||
|
# ignore commit message
|
||||||
|
**/.gitcommit
|
||||||
|
|
||||||
|
# ignore build failure markers
|
||||||
|
**/.build_failed*
|
||||||
|
|
||||||
|
# ignore backup files
|
||||||
|
**/*.bak
|
||||||
|
|
||||||
|
# ignore push/git control files
|
||||||
|
**/.no_push
|
||||||
|
**/.no_git
|
||||||
|
|
||||||
|
# ignore install markers
|
||||||
|
**/.installed
|
||||||
|
|
||||||
|
# ignore work in progress scripts
|
||||||
|
**/*.rewrite.sh
|
||||||
|
**/*.refactor.sh
|
||||||
|
|
||||||
|
# ignore dotenv files
|
||||||
|
.env
|
||||||
|
app.env
|
||||||
|
default.env
|
||||||
|
|
||||||
|
# ignore log and temp files
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
.fuse_hidden*
|
||||||
|
.directory
|
||||||
|
.Trash-*
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
.DS_Store?
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
._*
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
|
||||||
|
# runtime volume data — never committed
|
||||||
|
volumes/
|
||||||
|
docker/volumes/
|
||||||
|
|
||||||
|
# Claude Code runtime files
|
||||||
|
.claude/settings.local.json
|
||||||
|
.claude/backups/
|
||||||
|
.claude/cache/
|
||||||
|
.claude/file-history/
|
||||||
|
.claude/history.jsonl
|
||||||
|
.claude/projects/
|
||||||
|
.claude/statsFile
|
||||||
|
.claude/*.lock
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Claude loader
|
||||||
|
|
||||||
|
Project spec: [IDEA.md](IDEA.md)
|
||||||
|
|
||||||
|
This is a Docker image project. Implementation conventions come from
|
||||||
|
`~/.claude/memory/dockerfile_conventions.md`. All Docker assets live
|
||||||
|
under `docker/`.
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
## Project description
|
||||||
|
|
||||||
|
A production-ready Docker image for [Prosody XMPP](https://prosody.im/) configured specifically for Jitsi Meet deployments. Replaces the upstream `jitsi/docker-jitsi-meet` prosody image with a standards-compliant CasjaysDev image built on Alpine Linux with full BOSH and WebSocket support (mod_websocket).
|
||||||
|
|
||||||
|
## Project variables
|
||||||
|
|
||||||
|
```
|
||||||
|
project_name: prosody
|
||||||
|
project_org: casjaysdevdocker
|
||||||
|
internal_name: prosody
|
||||||
|
internal_org: casjaysdevdocker
|
||||||
|
image_registry: ghcr.io
|
||||||
|
upstream_image: prosody (Alpine package)
|
||||||
|
jitsi_repo: https://github.com/jitsi/docker-jitsi-meet
|
||||||
|
```
|
||||||
|
|
||||||
|
## Business logic
|
||||||
|
|
||||||
|
- Must be a drop-in replacement for `jitsi/docker-jitsi-meet` prosody container
|
||||||
|
- Must support all standard Jitsi Docker env vars: `XMPP_DOMAIN`, `XMPP_AUTH_DOMAIN`, `XMPP_MUC_DOMAIN`, `XMPP_INTERNAL_MUC_DOMAIN`, `XMPP_GUEST_DOMAIN`, `JICOFO_AUTH_PASSWORD`, `JVB_AUTH_PASSWORD`, `ENABLE_AUTH`, `ENABLE_GUESTS`, `ENABLE_XMPP_WEBSOCKET`, `PUBLIC_URL`, `LOG_LEVEL`
|
||||||
|
- Must have BOSH working on `/http-bind` at port 5280
|
||||||
|
- Must have WebSocket working on `/xmpp-websocket` at port 5280 (this is the primary fix over upstream)
|
||||||
|
- Must register jicofo and jvb users automatically at startup
|
||||||
|
- Must generate self-signed TLS certificates for Jitsi domains at startup if not present
|
||||||
|
- Must expose ports 5222 (c2s), 5280 (HTTP/BOSH/WS), 5347 (component)
|
||||||
|
- Must include all Jitsi prosody plugins from `jitsi/docker-jitsi-meet` prosody image
|
||||||
|
- Must run prosody as the `prosody` system user (non-root), not as root
|
||||||
|
- Must use `tini` as PID 1
|
||||||
|
- Must work with zero config — sane defaults for all env vars
|
||||||
|
- Must NOT require a separate nginx reverse proxy in the container
|
||||||
|
- Must NOT include s6 or any other process supervisor — single process per container
|
||||||
|
- `consider_websocket_secure = true` and `consider_bosh_secure = true` must always be set so trusted-proxy HTTPS termination works
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2026 casjay <git-admin@casjaysdev.pro>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
1. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
## 👋 Welcome to prosody 🚀
|
||||||
|
|
||||||
|
prosody README
|
||||||
|
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
🤖 casjay: [Github](https://github.com/casjay) 🤖
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# Jitsi Source Stage — extract plugins and pure-Lua libs from the official
|
||||||
|
# jitsi/prosody image at build time so we never fetch at runtime
|
||||||
|
# =============================================================================
|
||||||
|
FROM jitsi/prosody:stable AS jitsi-source
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Runtime Stage
|
||||||
|
# =============================================================================
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
ARG VERSION=dev
|
||||||
|
ARG BUILD_DATE
|
||||||
|
ARG VCS_REF
|
||||||
|
ARG LICENSE=MIT
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
# prosody from Alpine 13.x matches jitsi/prosody:stable (also 13.x)
|
||||||
|
# su-exec drops from root to prosody user before exec
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
openssl \
|
||||||
|
prosody \
|
||||||
|
su-exec \
|
||||||
|
tini
|
||||||
|
|
||||||
|
# Apply prosody 13.x compatibility patch:
|
||||||
|
# idna_to_ascii was removed in libicu 72+ but the Lua util still references it;
|
||||||
|
# the jitsi base image applies this same patch (sed -i '/idna_to_ascii/d')
|
||||||
|
RUN sed -i '/idna_to_ascii/d' /usr/lib/prosody/util/jid.lua 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create runtime directories
|
||||||
|
RUN mkdir -p \
|
||||||
|
/config/certs \
|
||||||
|
/config/conf.d \
|
||||||
|
/config/data \
|
||||||
|
/prosody-plugins \
|
||||||
|
/prosody-plugins-contrib \
|
||||||
|
/prosody-plugins-custom
|
||||||
|
|
||||||
|
# Copy Jitsi-specific prosody plugins (pure Lua — architecture-independent)
|
||||||
|
COPY --from=jitsi-source /prosody-plugins /prosody-plugins
|
||||||
|
COPY --from=jitsi-source /prosody-plugins-contrib /prosody-plugins-contrib
|
||||||
|
|
||||||
|
# Copy pure-Lua libraries that the Jitsi plugins depend on (basexx, net-url, etc.)
|
||||||
|
# We do NOT copy /usr/local/lib/lua (compiled .so for glibc/Debian — incompatible with musl/Alpine)
|
||||||
|
# lua5.4-cjson is provided by Alpine's prosody dependency and takes precedence
|
||||||
|
COPY --from=jitsi-source /usr/local/share/lua/5.4 /usr/local/share/lua/5.4
|
||||||
|
|
||||||
|
# Copy rootfs overlay (mirrors Linux FHS)
|
||||||
|
COPY docker/rootfs/ /
|
||||||
|
|
||||||
|
# Copy Dockerfile into image for reference
|
||||||
|
COPY docker/Dockerfile /root/Dockerfile
|
||||||
|
|
||||||
|
# Set ownership and permissions
|
||||||
|
RUN chown -R prosody:prosody /config /prosody-plugins-custom /prosody-plugins-contrib && \
|
||||||
|
chmod 755 /usr/local/bin/*
|
||||||
|
|
||||||
|
# BOSH + WebSocket (5280), c2s client connections (5222), component connections (5347)
|
||||||
|
EXPOSE 5222 5280 5347
|
||||||
|
|
||||||
|
STOPSIGNAL SIGRTMIN+3
|
||||||
|
|
||||||
|
HEALTHCHECK --start-period=2m --interval=1m --timeout=10s --retries=3 \
|
||||||
|
CMD /usr/local/bin/healthcheck.sh || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT [ "tini", "-p", "SIGTERM", "--", "/usr/local/bin/entrypoint.sh" ]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
services:
|
||||||
|
prosody:
|
||||||
|
image: ghcr.io/casjaysdevdocker/prosody:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- XMPP_DOMAIN=meet.jitsi
|
||||||
|
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
|
||||||
|
- XMPP_GUEST_DOMAIN=guest.meet.jitsi
|
||||||
|
- XMPP_MUC_DOMAIN=muc.meet.jitsi
|
||||||
|
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
|
||||||
|
- XMPP_HIDDEN_DOMAIN=hidden.meet.jitsi
|
||||||
|
- JICOFO_AUTH_PASSWORD=changeme_jicofo
|
||||||
|
- JVB_AUTH_PASSWORD=changeme_jvb
|
||||||
|
- ENABLE_AUTH=0
|
||||||
|
- ENABLE_GUESTS=0
|
||||||
|
- ENABLE_XMPP_WEBSOCKET=1
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
volumes:
|
||||||
|
- ./volumes/config:/config
|
||||||
|
ports:
|
||||||
|
- "5222:5222"
|
||||||
|
- "5280:5280"
|
||||||
|
- "5347:5347"
|
||||||
|
networks:
|
||||||
|
- prosody-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
prosody-net:
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,489 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck shell=bash
|
||||||
|
# entrypoint.sh — container startup script
|
||||||
|
# Called by: tini → entrypoint.sh → prosody
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Defaults
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
: "${XMPP_DOMAIN:=meet.jitsi}"
|
||||||
|
: "${XMPP_AUTH_DOMAIN:=auth.meet.jitsi}"
|
||||||
|
: "${XMPP_GUEST_DOMAIN:=guest.meet.jitsi}"
|
||||||
|
: "${XMPP_MUC_DOMAIN:=muc.meet.jitsi}"
|
||||||
|
: "${XMPP_INTERNAL_MUC_DOMAIN:=internal-muc.meet.jitsi}"
|
||||||
|
: "${XMPP_HIDDEN_DOMAIN:=hidden.meet.jitsi}"
|
||||||
|
: "${XMPP_PORT:=5222}"
|
||||||
|
: "${PROSODY_HTTP_PORT:=5280}"
|
||||||
|
: "${ENABLE_AUTH:=0}"
|
||||||
|
: "${ENABLE_GUESTS:=0}"
|
||||||
|
: "${ENABLE_XMPP_WEBSOCKET:=1}"
|
||||||
|
: "${ENABLE_LOBBY:=1}"
|
||||||
|
: "${ENABLE_BREAKOUT_ROOMS:=1}"
|
||||||
|
: "${ENABLE_AV_MODERATION:=1}"
|
||||||
|
: "${ENABLE_END_CONFERENCE:=1}"
|
||||||
|
: "${ENABLE_RECORDING:=0}"
|
||||||
|
: "${ENABLE_TRANSCRIPTIONS:=0}"
|
||||||
|
: "${JVB_AUTH_USER:=jvb}"
|
||||||
|
: "${JIBRI_RECORDER_USER:=recorder}"
|
||||||
|
: "${JIBRI_XMPP_USER:=jibri}"
|
||||||
|
: "${JIGASI_XMPP_USER:=jigasi}"
|
||||||
|
: "${LOG_LEVEL:=info}"
|
||||||
|
: "${PROSODY_MODE:=client}"
|
||||||
|
: "${PROSODY_C2S_REQUIRE_ENCRYPTION:=true}"
|
||||||
|
: "${PROSODY_ADMINS:=}"
|
||||||
|
: "${AUTH_TYPE:=internal}"
|
||||||
|
: "${DISABLE_POLLS:=0}"
|
||||||
|
|
||||||
|
# Derived
|
||||||
|
XMPP_MUC_DOMAIN_PREFIX="${XMPP_MUC_DOMAIN%%.*}"
|
||||||
|
PROSODY_CFG="/config/prosody.cfg.lua"
|
||||||
|
PROSODY_SITE_CFG="/config/conf.d/jitsi-meet.cfg.lua"
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Guards
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
[[ -n "${JICOFO_AUTH_PASSWORD:-}" ]] || { echo "FATAL: JICOFO_AUTH_PASSWORD must be set" >&2; exit 1; }
|
||||||
|
[[ -n "${JVB_AUTH_PASSWORD:-}" ]] || { echo "FATAL: JVB_AUTH_PASSWORD must be set" >&2; exit 1; }
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Directory setup
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
mkdir -p /config/certs /config/conf.d /config/data \
|
||||||
|
/prosody-plugins-custom /prosody-plugins-contrib
|
||||||
|
|
||||||
|
chown -R prosody:prosody /config /prosody-plugins-custom /prosody-plugins-contrib 2>/dev/null || true
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Generate main prosody.cfg.lua
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
__generate_main_cfg() {
|
||||||
|
# Build admins list
|
||||||
|
local admins_list=""
|
||||||
|
if [[ -n "${PROSODY_ADMINS}" ]]; then
|
||||||
|
while IFS=',' read -ra parts; do
|
||||||
|
for admin in "${parts[@]}"; do
|
||||||
|
admin="${admin// /}"
|
||||||
|
[[ -n "$admin" ]] && admins_list+=" \"${admin}\";\n"
|
||||||
|
done
|
||||||
|
done <<< "${PROSODY_ADMINS}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "${PROSODY_CFG}" << MAIN_CFG
|
||||||
|
-- Generated by entrypoint.sh — do not edit manually
|
||||||
|
|
||||||
|
---------- Server-wide settings ----------
|
||||||
|
|
||||||
|
admins = {
|
||||||
|
$(printf '%b' "${admins_list}")}
|
||||||
|
|
||||||
|
component_admins_as_room_owners = true
|
||||||
|
|
||||||
|
modules_enabled = {
|
||||||
|
-- Core
|
||||||
|
"roster";
|
||||||
|
"saslauth";
|
||||||
|
"tls";
|
||||||
|
"disco";
|
||||||
|
"ping";
|
||||||
|
"version";
|
||||||
|
"posix";
|
||||||
|
"limits";
|
||||||
|
"private";
|
||||||
|
|
||||||
|
-- HTTP (BOSH + WebSocket — required for Jitsi)
|
||||||
|
"bosh";
|
||||||
|
"websocket";
|
||||||
|
"http";
|
||||||
|
"http_health";
|
||||||
|
|
||||||
|
-- Status
|
||||||
|
"uptime";
|
||||||
|
};
|
||||||
|
|
||||||
|
modules_disabled = {
|
||||||
|
"offline";
|
||||||
|
"register";
|
||||||
|
"s2s";
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Never allow unauthenticated registration globally
|
||||||
|
allow_registration = false;
|
||||||
|
|
||||||
|
-- Rate limits for incoming connections
|
||||||
|
limits = {
|
||||||
|
c2s = {
|
||||||
|
rate = "10kb/s";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Garbage collector
|
||||||
|
gc = {
|
||||||
|
mode = "incremental";
|
||||||
|
threshold = 400;
|
||||||
|
speed = 250;
|
||||||
|
step_size = 13;
|
||||||
|
};
|
||||||
|
|
||||||
|
pidfile = "/config/data/prosody.pid";
|
||||||
|
|
||||||
|
c2s_require_encryption = ${PROSODY_C2S_REQUIRE_ENCRYPTION};
|
||||||
|
c2s_ports = { ${XMPP_PORT} }
|
||||||
|
c2s_interfaces = { "*" }
|
||||||
|
|
||||||
|
s2s_secure_auth = false
|
||||||
|
|
||||||
|
authentication = "internal_hashed"
|
||||||
|
|
||||||
|
-- Logging
|
||||||
|
log = {
|
||||||
|
{ levels = { min = "${LOG_LEVEL}" }, timestamps = "%Y-%m-%d %X", to = "console" };
|
||||||
|
};
|
||||||
|
|
||||||
|
-- HTTP configuration
|
||||||
|
-- consider_bosh_secure and consider_websocket_secure allow HTTPS-terminated
|
||||||
|
-- connections from a reverse proxy to be treated as secure.
|
||||||
|
consider_bosh_secure = true;
|
||||||
|
consider_websocket_secure = true;
|
||||||
|
|
||||||
|
-- Allow WebSocket + BOSH on the same port (5280) that the reverse proxy reaches
|
||||||
|
http_ports = { ${PROSODY_HTTP_PORT} }
|
||||||
|
http_interfaces = { "*" }
|
||||||
|
|
||||||
|
-- Stream management (required for smacks / WebSocket reconnect)
|
||||||
|
smacks_max_unacked_stanzas = 5;
|
||||||
|
smacks_hibernation_time = 60;
|
||||||
|
smacks_max_old_sessions = 1;
|
||||||
|
|
||||||
|
-- epoll backend for better performance
|
||||||
|
network_backend = "epoll";
|
||||||
|
network_settings = {
|
||||||
|
tcp_backlog = 511;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Data storage
|
||||||
|
data_path = "/config/data";
|
||||||
|
|
||||||
|
-- Plugin paths
|
||||||
|
plugin_paths = { "/prosody-plugins-custom", "/prosody-plugins/", "/prosody-plugins-contrib" };
|
||||||
|
|
||||||
|
Include "conf.d/*.cfg.lua"
|
||||||
|
MAIN_CFG
|
||||||
|
}
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Generate conf.d/jitsi-meet.cfg.lua
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
__generate_site_cfg() {
|
||||||
|
# Determine main VirtualHost authentication
|
||||||
|
local main_auth="jitsi-anonymous"
|
||||||
|
if [[ "${ENABLE_AUTH}" == "1" ]] || [[ "${ENABLE_AUTH}" == "true" ]]; then
|
||||||
|
main_auth="internal_hashed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine guest VirtualHost authentication
|
||||||
|
local guest_auth="jitsi-anonymous"
|
||||||
|
|
||||||
|
# Build global admins block for conf.d
|
||||||
|
cat > "${PROSODY_SITE_CFG}" << SITE_START
|
||||||
|
-- Generated by entrypoint.sh — do not edit manually
|
||||||
|
|
||||||
|
admins = {
|
||||||
|
"focus@${XMPP_AUTH_DOMAIN}",
|
||||||
|
"${JVB_AUTH_USER}@${XMPP_AUTH_DOMAIN}"
|
||||||
|
}
|
||||||
|
|
||||||
|
unlimited_jids = {
|
||||||
|
"focus@${XMPP_AUTH_DOMAIN}",
|
||||||
|
"${JVB_AUTH_USER}@${XMPP_AUTH_DOMAIN}"
|
||||||
|
}
|
||||||
|
|
||||||
|
muc_mapper_domain_base = "${XMPP_DOMAIN}";
|
||||||
|
muc_mapper_domain_prefix = "${XMPP_MUC_DOMAIN_PREFIX}";
|
||||||
|
|
||||||
|
recorder_prefixes = { "${JIBRI_RECORDER_USER}@${XMPP_HIDDEN_DOMAIN}" };
|
||||||
|
transcriber_prefixes = { "${JIGASI_TRANSCRIBER_USER:-transcriber}@${XMPP_HIDDEN_DOMAIN}" };
|
||||||
|
|
||||||
|
http_default_host = "${XMPP_DOMAIN}"
|
||||||
|
|
||||||
|
-- Main virtual host
|
||||||
|
VirtualHost "${XMPP_DOMAIN}"
|
||||||
|
authentication = "${main_auth}"
|
||||||
|
ssl = {
|
||||||
|
key = "/config/certs/${XMPP_DOMAIN}.key";
|
||||||
|
certificate = "/config/certs/${XMPP_DOMAIN}.crt";
|
||||||
|
}
|
||||||
|
modules_enabled = {
|
||||||
|
"bosh";
|
||||||
|
"websocket";
|
||||||
|
"smacks";
|
||||||
|
"conference_duration";
|
||||||
|
"muc_lobby_rooms";
|
||||||
|
"muc_breakout_rooms";
|
||||||
|
"features_identity";
|
||||||
|
SITE_START
|
||||||
|
|
||||||
|
# Optional XMPP_MODULES
|
||||||
|
if [[ -n "${XMPP_MODULES:-}" ]]; then
|
||||||
|
while IFS=',' read -ra mods; do
|
||||||
|
for mod in "${mods[@]}"; do
|
||||||
|
mod="${mod// /}"
|
||||||
|
[[ -n "$mod" ]] && printf ' "%s";\n' "${mod}" >> "${PROSODY_SITE_CFG}"
|
||||||
|
done
|
||||||
|
done <<< "${XMPP_MODULES}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_MAIN_HOST
|
||||||
|
}
|
||||||
|
main_muc = "${XMPP_MUC_DOMAIN}"
|
||||||
|
lobby_muc = "lobby.${XMPP_DOMAIN}"
|
||||||
|
breakout_rooms_muc = "breakout.${XMPP_DOMAIN}"
|
||||||
|
c2s_require_encryption = ${PROSODY_C2S_REQUIRE_ENCRYPTION}
|
||||||
|
|
||||||
|
SITE_MAIN_HOST
|
||||||
|
|
||||||
|
# Guest domain (only when auth is enabled and guests are enabled)
|
||||||
|
if { [[ "${ENABLE_AUTH}" == "1" ]] || [[ "${ENABLE_AUTH}" == "true" ]]; } && \
|
||||||
|
{ [[ "${ENABLE_GUESTS}" == "1" ]] || [[ "${ENABLE_GUESTS}" == "true" ]]; }; then
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_GUEST
|
||||||
|
VirtualHost "${XMPP_GUEST_DOMAIN}"
|
||||||
|
authentication = "${guest_auth}"
|
||||||
|
modules_enabled = {
|
||||||
|
"smacks";
|
||||||
|
}
|
||||||
|
main_muc = "${XMPP_MUC_DOMAIN}"
|
||||||
|
lobby_muc = "lobby.${XMPP_DOMAIN}"
|
||||||
|
breakout_rooms_muc = "breakout.${XMPP_DOMAIN}"
|
||||||
|
c2s_require_encryption = ${PROSODY_C2S_REQUIRE_ENCRYPTION}
|
||||||
|
|
||||||
|
SITE_GUEST
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Auth domain
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_AUTH
|
||||||
|
VirtualHost "${XMPP_AUTH_DOMAIN}"
|
||||||
|
ssl = {
|
||||||
|
key = "/config/certs/${XMPP_AUTH_DOMAIN}.key";
|
||||||
|
certificate = "/config/certs/${XMPP_AUTH_DOMAIN}.crt";
|
||||||
|
}
|
||||||
|
modules_enabled = {
|
||||||
|
"limits_exception";
|
||||||
|
"smacks";
|
||||||
|
}
|
||||||
|
authentication = "internal_hashed"
|
||||||
|
smacks_hibernation_time = 15;
|
||||||
|
|
||||||
|
SITE_AUTH
|
||||||
|
|
||||||
|
# Hidden domain for recording/transcription
|
||||||
|
if [[ "${ENABLE_RECORDING}" == "1" ]] || [[ "${ENABLE_RECORDING}" == "true" ]] || \
|
||||||
|
[[ "${ENABLE_TRANSCRIPTIONS}" == "1" ]] || [[ "${ENABLE_TRANSCRIPTIONS}" == "true" ]]; then
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_HIDDEN
|
||||||
|
VirtualHost "${XMPP_HIDDEN_DOMAIN}"
|
||||||
|
modules_enabled = {
|
||||||
|
"smacks";
|
||||||
|
}
|
||||||
|
authentication = "internal_hashed"
|
||||||
|
|
||||||
|
SITE_HIDDEN
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Components
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_COMPONENTS
|
||||||
|
-- Internal MUC (JVB/jicofo signaling — never exposed to clients)
|
||||||
|
Component "${XMPP_INTERNAL_MUC_DOMAIN}" "muc"
|
||||||
|
storage = "memory"
|
||||||
|
modules_enabled = {
|
||||||
|
"muc_hide_all";
|
||||||
|
"muc_filter_access";
|
||||||
|
}
|
||||||
|
restrict_room_creation = true
|
||||||
|
muc_filter_whitelist = "${XMPP_AUTH_DOMAIN}"
|
||||||
|
muc_room_locking = false
|
||||||
|
muc_room_default_public_jids = true
|
||||||
|
muc_room_cache_size = 1000
|
||||||
|
muc_tombstones = false
|
||||||
|
muc_room_allow_persistent = false
|
||||||
|
|
||||||
|
-- Conference MUC (participants join rooms here)
|
||||||
|
Component "${XMPP_MUC_DOMAIN}" "muc"
|
||||||
|
restrict_room_creation = true
|
||||||
|
storage = "memory"
|
||||||
|
modules_enabled = {
|
||||||
|
"muc_hide_all";
|
||||||
|
"muc_meeting_id";
|
||||||
|
"muc_domain_mapper";
|
||||||
|
"muc_password_whitelist";
|
||||||
|
}
|
||||||
|
muc_room_cache_size = 10000
|
||||||
|
muc_room_locking = false
|
||||||
|
muc_room_default_public_jids = true
|
||||||
|
muc_tombstones = false
|
||||||
|
muc_room_allow_persistent = false
|
||||||
|
muc_password_whitelist = {
|
||||||
|
"focus@${XMPP_AUTH_DOMAIN}";
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Focus component proxy
|
||||||
|
Component "focus.${XMPP_DOMAIN}" "client_proxy"
|
||||||
|
target_address = "focus@${XMPP_AUTH_DOMAIN}"
|
||||||
|
|
||||||
|
-- Speakerstats component
|
||||||
|
Component "speakerstats.${XMPP_DOMAIN}" "speakerstats_component"
|
||||||
|
muc_component = "${XMPP_MUC_DOMAIN}"
|
||||||
|
|
||||||
|
-- End conference component
|
||||||
|
Component "endconference.${XMPP_DOMAIN}" "end_conference"
|
||||||
|
muc_component = "${XMPP_MUC_DOMAIN}"
|
||||||
|
|
||||||
|
-- AV moderation component
|
||||||
|
Component "avmoderation.${XMPP_DOMAIN}" "av_moderation_component"
|
||||||
|
muc_component = "${XMPP_MUC_DOMAIN}"
|
||||||
|
|
||||||
|
-- Lobby MUC
|
||||||
|
Component "lobby.${XMPP_DOMAIN}" "muc"
|
||||||
|
storage = "memory"
|
||||||
|
restrict_room_creation = true
|
||||||
|
muc_tombstones = false
|
||||||
|
muc_room_allow_persistent = false
|
||||||
|
muc_room_cache_size = 10000
|
||||||
|
muc_room_locking = false
|
||||||
|
muc_room_default_public_jids = true
|
||||||
|
modules_enabled = {
|
||||||
|
"muc_hide_all";
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Breakout rooms MUC
|
||||||
|
Component "breakout.${XMPP_DOMAIN}" "muc"
|
||||||
|
storage = "memory"
|
||||||
|
restrict_room_creation = true
|
||||||
|
muc_room_cache_size = 10000
|
||||||
|
muc_room_locking = false
|
||||||
|
muc_room_default_public_jids = true
|
||||||
|
muc_tombstones = false
|
||||||
|
muc_room_allow_persistent = false
|
||||||
|
modules_enabled = {
|
||||||
|
"muc_hide_all";
|
||||||
|
"muc_meeting_id";
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Room metadata component
|
||||||
|
Component "metadata.${XMPP_DOMAIN}" "room_metadata_component"
|
||||||
|
muc_component = "${XMPP_MUC_DOMAIN}"
|
||||||
|
breakout_rooms_component = "breakout.${XMPP_DOMAIN}"
|
||||||
|
|
||||||
|
SITE_COMPONENTS
|
||||||
|
|
||||||
|
# Polls component (optional disable)
|
||||||
|
if [[ "${DISABLE_POLLS}" != "1" ]] && [[ "${DISABLE_POLLS}" != "true" ]]; then
|
||||||
|
cat >> "${PROSODY_SITE_CFG}" << SITE_POLLS
|
||||||
|
Component "polls.${XMPP_DOMAIN}" "polls_component"
|
||||||
|
|
||||||
|
SITE_POLLS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Certificate generation
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
__generate_cert() {
|
||||||
|
local domain="${1}"
|
||||||
|
local cert_dir="/config/certs"
|
||||||
|
local key="${cert_dir}/${domain}.key"
|
||||||
|
local crt="${cert_dir}/${domain}.crt"
|
||||||
|
|
||||||
|
[[ -f "${key}" && -f "${crt}" ]] && return 0
|
||||||
|
|
||||||
|
echo "INFO: Generating self-signed certificate for ${domain}"
|
||||||
|
openssl req -x509 -newkey rsa:4096 \
|
||||||
|
-keyout "${key}" -out "${crt}" \
|
||||||
|
-days 3650 -nodes \
|
||||||
|
-subj "/CN=${domain}" 2>/dev/null
|
||||||
|
chmod 600 "${key}"
|
||||||
|
chown prosody:prosody "${key}" "${crt}" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
__generate_certs() {
|
||||||
|
__generate_cert "${XMPP_DOMAIN}"
|
||||||
|
__generate_cert "${XMPP_AUTH_DOMAIN}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# User registration
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
__register_user() {
|
||||||
|
local user="${1}" domain="${2}" pass="${3}"
|
||||||
|
# prosodyctl register is idempotent — re-register just updates the password
|
||||||
|
su-exec prosody prosodyctl --config "${PROSODY_CFG}" \
|
||||||
|
register "${user}" "${domain}" "${pass}" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
__register_jitsi_users() {
|
||||||
|
# Start prosody temporarily in background so prosodyctl can connect
|
||||||
|
su-exec prosody prosody --config "${PROSODY_CFG}" -F &
|
||||||
|
local pid=$!
|
||||||
|
|
||||||
|
# Wait until prosody is accepting connections (up to 30s)
|
||||||
|
local i=0
|
||||||
|
while ! su-exec prosody prosodyctl --config "${PROSODY_CFG}" status >/dev/null 2>&1; do
|
||||||
|
sleep 1
|
||||||
|
i=$(( i + 1 ))
|
||||||
|
if (( i >= 30 )); then
|
||||||
|
echo "FATAL: prosody did not start within 30s" >&2
|
||||||
|
kill "${pid}" 2>/dev/null || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "INFO: Registering jicofo user"
|
||||||
|
__register_user "focus" "${XMPP_AUTH_DOMAIN}" "${JICOFO_AUTH_PASSWORD}"
|
||||||
|
|
||||||
|
echo "INFO: Registering jvb user"
|
||||||
|
__register_user "${JVB_AUTH_USER}" "${XMPP_AUTH_DOMAIN}" "${JVB_AUTH_PASSWORD}"
|
||||||
|
|
||||||
|
# Subscribe focus to the focus component so roster is correct
|
||||||
|
if [[ "${PROSODY_MODE}" == "client" ]]; then
|
||||||
|
su-exec prosody prosodyctl --config "${PROSODY_CFG}" \
|
||||||
|
mod_roster_command subscribe "focus.${XMPP_DOMAIN}" "focus@${XMPP_AUTH_DOMAIN}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: jibri user
|
||||||
|
if [[ -n "${JIBRI_XMPP_PASSWORD:-}" ]]; then
|
||||||
|
echo "INFO: Registering jibri user"
|
||||||
|
__register_user "${JIBRI_XMPP_USER}" "${XMPP_AUTH_DOMAIN}" "${JIBRI_XMPP_PASSWORD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: jigasi user
|
||||||
|
if [[ -n "${JIGASI_XMPP_PASSWORD:-}" ]]; then
|
||||||
|
echo "INFO: Registering jigasi user"
|
||||||
|
__register_user "${JIGASI_XMPP_USER}" "${XMPP_AUTH_DOMAIN}" "${JIGASI_XMPP_PASSWORD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Shut down the temporary instance
|
||||||
|
kill "${pid}" 2>/dev/null || true
|
||||||
|
wait "${pid}" 2>/dev/null || true
|
||||||
|
# Clean up pid file so the main instance can start
|
||||||
|
rm -f /config/data/prosody.pid
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
# Main
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
echo "INFO: Generating prosody configuration"
|
||||||
|
__generate_main_cfg
|
||||||
|
__generate_site_cfg
|
||||||
|
__generate_certs
|
||||||
|
__register_jitsi_users
|
||||||
|
|
||||||
|
echo "INFO: Starting prosody"
|
||||||
|
exec su-exec prosody prosody --config "${PROSODY_CFG}" -F
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# healthcheck.sh — container health probe
|
||||||
|
# Returns 0 (healthy) if prosody's HTTP health endpoint responds 200
|
||||||
|
|
||||||
|
: "${PROSODY_HTTP_PORT:=5280}"
|
||||||
|
|
||||||
|
curl -q -LSs --max-time 5 "http://127.0.0.1:${PROSODY_HTTP_PORT}/health" -o /dev/null
|
||||||
Reference in New Issue
Block a user