├── scripts ├── clone.sh ├── install_qt_dev.sh ├── choose_qt_version.sh ├── install_qt.sh ├── copy_one_of.sh └── build.sh ├── .github └── workflows │ ├── upstream_release.yml │ ├── ci.yml │ ├── manual_dispatch.yml │ └── build_and_publish.yml ├── LICENSE ├── Dockerfile ├── entrypoint.sh └── README.md /scripts/clone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | 6 | git clone --filter=tree:0 https://github.com/mumble-voip/mumble/ /mumble/repo 7 | 8 | cd /mumble/repo 9 | 10 | git config advice.detachedHead false 11 | 12 | if [[ -n "$MUMBLE_VERSION" && ! "$MUMBLE_VERSION" == "latest" ]]; then 13 | git checkout "$MUMBLE_VERSION" 14 | fi 15 | 16 | git submodule update --init 17 | git submodule update --depth 1 18 | -------------------------------------------------------------------------------- /scripts/install_qt_dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | 6 | if [[ "$QT_VERSION" = 6 ]]; then 7 | QT_PACKAGES=(\ 8 | qt6-base-dev \ 9 | qt6-tools-dev \ 10 | qt6-tools-dev-tools \ 11 | qt6-qpa-plugins \ 12 | ) 13 | elif [[ "$QT_VERSION" = 5 ]]; then 14 | QT_PACKAGES=(\ 15 | qtbase5-dev \ 16 | qttools5-dev \ 17 | qttools5-dev-tools 18 | ) 19 | else 20 | 1>&2 echo "Error, unknown Qt version: '$QT_VERSION'" 21 | exit 1 22 | fi 23 | 24 | apt install --no-install-recommends -y "${QT_PACKAGES[@]}" 25 | -------------------------------------------------------------------------------- /scripts/choose_qt_version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | 6 | case "${MUMBLE_VERSION}" in 7 | v1.4.* ) ;& # fallthrough 8 | 1.4.* ) ;& # fallthrough 9 | v1.5.* ) ;& # fallthrough 10 | 1.5.* ) QT_VERSION=5 11 | ;; 12 | v1.6.* ) ;& # fallthrough 13 | 1.6.* ) ;& # fallthrough 14 | latest ) ;& # fallthrough 15 | * ) QT_VERSION=6 16 | ;; 17 | esac 18 | 19 | if [[ -z "$QT_VERSION" ]]; then 20 | 1>&2 echo "Error: unable to determine Qt version from MUMBLE_VERSION=$MUMBLE_VERSION" 21 | exit 1 22 | fi 23 | 24 | echo -n "$QT_VERSION" 25 | -------------------------------------------------------------------------------- /.github/workflows/upstream_release.yml: -------------------------------------------------------------------------------- 1 | name: Upstream Release 2 | 3 | on: 4 | repository_dispatch: 5 | types: [ new_release ] 6 | 7 | jobs: 8 | publish_new_release: 9 | uses: ./.github/workflows/build_and_publish.yml 10 | with: 11 | mumble_version: ${{ github.event.client_payload.tag }} 12 | docker_version: '0' 13 | publish: true 14 | update_latest: ${{ github.event.client_payload.is_latest == 'true' }} 15 | platforms: "linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8" 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /scripts/install_qt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | 6 | if [[ "$QT_VERSION" = 6 ]]; then 7 | QT_PACKAGES=(\ 8 | libqt6core6t64 \ 9 | libqt6network6t64 \ 10 | libqt6sql6t64 \ 11 | libqt6sql6-mysql \ 12 | libqt6sql6-psql \ 13 | libqt6sql6-sqlite \ 14 | libqt6xml6t64 \ 15 | libqt6dbus6t64 \ 16 | ) 17 | elif [[ "$QT_VERSION" = 5 ]]; then 18 | QT_PACKAGES=(\ 19 | libqt5core5t64 \ 20 | libqt5network5t64 \ 21 | libqt5sql5t64 \ 22 | libqt5sql5-mysql \ 23 | libqt5sql5-psql \ 24 | libqt5sql5-sqlite \ 25 | libqt5xml5t64 \ 26 | libqt5dbus5t64 \ 27 | ) 28 | else 29 | 1>&2 echo "Error, unknown Qt version: '$QT_VERSION'" 30 | exit 1 31 | fi 32 | 33 | apt install --no-install-recommends -y "${QT_PACKAGES[@]}" 34 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | # Note: As of now the strategy property is not supported when using reusable workflows, so we can't use a build 6 | # matrix to create the different build cases (see https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) 7 | jobs: 8 | build_1_5_857: 9 | uses: ./.github/workflows/build_and_publish.yml 10 | with: 11 | mumble_version: "v1.5.857" 12 | docker_version: '0' 13 | publish: false 14 | update_latest: true 15 | platforms: "linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8" 16 | build_latest: 17 | uses: ./.github/workflows/build_and_publish.yml 18 | with: 19 | mumble_version: "latest" 20 | docker_version: '0' 21 | publish: false 22 | update_latest: true 23 | platforms: "linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8" 24 | -------------------------------------------------------------------------------- /scripts/copy_one_of.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script can be used to copy the first existing file to the 4 | # target destination. 5 | # Thus 6 | # copy_one_of.sh a b c 7 | # copies either a or b to c. The first of the target files that 8 | # exists will be copied. The rest will be ignored. 9 | 10 | set -e 11 | set -x 12 | 13 | if [[ "$#" < 2 ]]; then 14 | >&2 echo "Too few arguments - expected at least two" 15 | exit 1 16 | fi 17 | 18 | parameters=( "$@" ) 19 | target_file="${parameters[$(( $# - 1))]}" 20 | 21 | found=false 22 | 23 | # Make use of num. of arguments $# to iterate up to the i - 1st argument (last one is destination) 24 | for i in $(seq 0 $(( $# - 2 )) ); do 25 | current_file=${parameters[$i]} 26 | 27 | if [[ -f "$current_file" ]]; then 28 | cp "$current_file" "$target_file" 29 | found=true 30 | break 31 | fi 32 | done 33 | 34 | if [[ "$found" = "false" ]]; then 35 | >&2 echo "Did not find any of the source files - nothing was copied" 36 | exit 1 37 | fi 38 | -------------------------------------------------------------------------------- /.github/workflows/manual_dispatch.yml: -------------------------------------------------------------------------------- 1 | name: Manual dispatch 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | mumble_version: 7 | description: "The version (tag or commit hash) of Mumble to build" 8 | required: true 9 | default: "latest" 10 | docker_version: 11 | description: "Docker image version, independent of mumble version" 12 | required: true 13 | default: "0" 14 | publish: 15 | description: "Whether the built image(s) shall be published to Dockerhub" 16 | required: true 17 | default: "false" 18 | update_latest: 19 | description: "Whether to update the 'latest' tag on Dockerhub" 20 | required: true 21 | default: "false" 22 | 23 | jobs: 24 | manual_dispatch: 25 | uses: ./.github/workflows/build_and_publish.yml 26 | with: 27 | mumble_version: ${{ github.event.inputs.mumble_version }} 28 | docker_version: ${{ github.event.inputs.docker_version }} 29 | publish: ${{ github.event.inputs.publish == 'true' }} 30 | update_latest: ${{ github.event.inputs.update_latest == 'true' }} 31 | platforms: "linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8" 32 | secrets: inherit 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Mumble 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | 6 | BUILD_NUMBER_SCRIPT="/mumble/repo/scripts/mumble-build-number.py" 7 | VERSION_SCRIPT="/mumble/repo/scripts/mumble-version.py" 8 | 9 | mkdir build && cd build 10 | 11 | buildNumber=0 12 | if [[ ! -z "$MUMBLE_BUILD_NUMBER" ]]; then 13 | buildNumber=$MUMBLE_BUILD_NUMBER 14 | echo "Build number read from argument: $buildNumber" 15 | elif [[ "$MUMBLE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 16 | buildNumber=$(echo "$MUMBLE_VERSION" | sed -E 's/v[0-9]+\.[0-9]+\.([0-9]+)/\1/' ) 17 | echo "Build number read from version: $buildNumber" 18 | else 19 | if [[ -f "$BUILD_NUMBER_SCRIPT" && -f "$VERSION_SCRIPT" ]]; then 20 | version=$( python3 "$VERSION_SCRIPT" ) 21 | commit=$( git rev-parse HEAD ) 22 | buildNumber=$( timeout 20 python3 "$BUILD_NUMBER_SCRIPT" --commit "$commit" --version "$version" --default -1 || exitStatus=$? ) 23 | 24 | if [[ "$exitStatus" -eq 0 && "$buildNumber" -ge 0 ]]; then 25 | echo "Determined build number to be $buildNumber" 26 | else 27 | echo "Failed to fetch the build number for commit $commit, defaulting to 0" 28 | buildNumber=0 29 | fi 30 | else 31 | echo "Defaulting to build number 0" 32 | fi 33 | fi 34 | 35 | cmake \ 36 | -DCMAKE_BUILD_TYPE=Release \ 37 | -DBUILD_NUMBER=$buildNumber \ 38 | -Dclient=OFF \ 39 | -Dserver=ON \ 40 | -Dice=ON \ 41 | -Dtests=ON \ 42 | -Dwarnings-as-errors=OFF \ 43 | -Dzeroconf=OFF \ 44 | -DCMAKE_UNITY_BUILD=ON \ 45 | $MUMBLE_CMAKE_ARGS \ 46 | .. 47 | 48 | cmake --build . -j $(nproc) 49 | 50 | TEST_TIMEOUT=600 # seconds 51 | export QTEST_FUNCTION_TIMEOUT="$(( $TEST_TIMEOUT * 1000 ))" # milliseconds 52 | ctest --timeout $TIMEOUT --output-on-failure . -j $(nproc) 53 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 AS base 2 | 3 | ADD ./scripts/* /mumble/scripts/ 4 | WORKDIR /mumble/scripts 5 | 6 | ARG DEBIAN_FRONTEND=noninteractive 7 | ARG MUMBLE_VERSION=latest 8 | 9 | RUN apt-get update && apt-get install --no-install-recommends -y \ 10 | libcap2 \ 11 | libzeroc-ice3.7t64 \ 12 | '^libprotobuf[0-9]+$' \ 13 | libavahi-compat-libdnssd1 \ 14 | ca-certificates \ 15 | sqlite3 \ 16 | mysql-client \ 17 | libpq5 \ 18 | && export QT_VERSION="$( /mumble/scripts/choose_qt_version.sh )" \ 19 | && /mumble/scripts/install_qt.sh \ 20 | # Workaround for systems like CentOS 7 which won't load libQt5Core.so as expected: 21 | # see also https://stackoverflow.com/a/68897099/ 22 | binutils \ 23 | && find /lib* /usr/lib* -name 'libQt?Core.so.*' -exec strip --remove-section=.note.ABI-tag {} \; \ 24 | && apt-get -y purge binutils \ 25 | # End of workaround 26 | && apt-get clean \ 27 | && rm -rf /var/lib/apt/lists/* \ 28 | && mkdir -p /data \ 29 | && rm -Rf /scripts 30 | 31 | 32 | 33 | FROM base AS build 34 | ARG DEBIAN_FRONTEND=noninteractive 35 | 36 | ADD ./scripts/* /mumble/scripts/ 37 | WORKDIR /mumble/repo 38 | 39 | RUN apt-get update && apt-get install --no-install-recommends -y \ 40 | git cmake build-essential ca-certificates pkg-config \ 41 | libssl-dev \ 42 | libboost-dev \ 43 | libprotobuf-dev \ 44 | protobuf-compiler \ 45 | libprotoc-dev \ 46 | libcap-dev \ 47 | libxi-dev \ 48 | libavahi-compat-libdnssd-dev \ 49 | libzeroc-ice-dev \ 50 | python3 \ 51 | git \ 52 | libsqlite3-dev \ 53 | libmysqlclient-dev \ 54 | libpq-dev \ 55 | && export QT_VERSION="$( /mumble/scripts/choose_qt_version.sh )" \ 56 | && /mumble/scripts/install_qt_dev.sh \ 57 | && apt-get clean \ 58 | && rm -rf /var/lib/apt/lists/* 59 | 60 | ARG MUMBLE_VERSION=latest 61 | ARG MUMBLE_BUILD_NUMBER="" 62 | ARG MUMBLE_CMAKE_ARGS="" 63 | 64 | # Clone the repo, build it and finally copy the default server ini file. Since this file may be at different locations and Docker 65 | # doesn't support conditional copies, we have to ensure that regardless of where the file is located in the repo, it will end 66 | # up at a unique path in our build container to be copied further down. 67 | RUN /mumble/scripts/clone.sh \ 68 | && /mumble/scripts/build.sh \ 69 | && /mumble/scripts/copy_one_of.sh ./scripts/murmur.ini ./auxiliary_files/mumble-server.ini default_config.ini 70 | 71 | RUN git clone https://github.com/ncopa/su-exec.git /mumble/repo/su-exec \ 72 | && cd /mumble/repo/su-exec && make 73 | 74 | 75 | 76 | FROM base 77 | 78 | COPY --from=build /mumble/repo/build/mumble-server /usr/bin/mumble-server 79 | COPY --from=build /mumble/repo/default_config.ini /etc/mumble/bare_config.ini 80 | COPY --from=build --chmod=755 /mumble/repo/su-exec/su-exec /usr/local/bin/su-exec 81 | 82 | 83 | EXPOSE 64738/tcp 64738/udp 84 | COPY entrypoint.sh /entrypoint.sh 85 | 86 | VOLUME ["/data"] 87 | ENTRYPOINT ["/entrypoint.sh"] 88 | CMD ["/usr/bin/mumble-server", "-fg"] 89 | 90 | -------------------------------------------------------------------------------- /.github/workflows/build_and_publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | mumble_version: 7 | required: true 8 | type: string 9 | docker_version: 10 | required: true 11 | type: string 12 | platforms: 13 | required: true 14 | type: string 15 | publish: 16 | required: true 17 | type: boolean 18 | update_latest: 19 | required: true 20 | type: boolean 21 | 22 | jobs: 23 | build: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Login to DockerHub 27 | if: ${{ inputs.publish }} 28 | uses: docker/login-action@v3 29 | with: 30 | username: ${{ secrets.DOCKERHUB_USERNAME }} 31 | password: ${{ secrets.DOCKERHUB_TOKEN }} 32 | 33 | - name: Login to GitHub Container registry 34 | if: ${{ inputs.publish }} 35 | uses: docker/login-action@v3 36 | with: 37 | registry: ghcr.io 38 | username: ${{ github.repository_owner }} 39 | password: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Checkout 42 | uses: actions/checkout@v4 43 | 44 | - name: Set up QEMU 45 | uses: docker/setup-qemu-action@v3 46 | 47 | - name: Set up Docker Buildx 48 | uses: docker/setup-buildx-action@v3 49 | 50 | - name: Configure target tags (with latest) 51 | if: ${{ inputs.update_latest }} 52 | run: echo "PRE_TAGS=mumble-server:latest mumble-server:${{ inputs.mumble_version }} mumble-server:${{ inputs.mumble_version }}-${{ inputs.docker_version }}" >> $GITHUB_ENV 53 | 54 | - name: Configure target tags (without latest) 55 | if: ${{ ! inputs.update_latest }} 56 | run: echo "PRE_TAGS=mumble-server:${{ inputs.mumble_version }} mumble-server:${{ inputs.mumble_version }}-${{ inputs.docker_version }}" >> $GITHUB_ENV 57 | 58 | - name: Make tags for registries 59 | run: | 60 | TAG_ARRAY=() 61 | for current in $PRE_TAGS; do 62 | TAG_ARRAY+=("mumblevoip/$current" "ghcr.io/mumble-voip/$current") 63 | done 64 | TAGS="$( IFS=","; echo "${TAG_ARRAY[*]}" )" 65 | echo "TAGS=$TAGS" >> $GITHUB_ENV 66 | 67 | - name: Build and push 68 | uses: docker/build-push-action@v6 69 | with: 70 | context: . 71 | platforms: ${{ inputs.platforms }} 72 | push: ${{ inputs.publish }} 73 | build-args: | 74 | MUMBLE_VERSION=${{ inputs.mumble_version }} 75 | tags: ${{ env.TAGS }} 76 | env: 77 | MUMBLE_VERSION: ${{ inputs.mumble_version }} 78 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | export PUID=${PUID:-10000} 5 | export PGID=${PGID:-10000} 6 | MUMBLE_CHOWN_DATA=${MUMBLE_CHOWN_DATA:-true} 7 | 8 | readonly DATA_DIR="/data" 9 | readonly BARE_BONES_CONFIG_FILE="/etc/mumble/bare_config.ini" 10 | readonly CONFIG_REGEX="^(\;|\#)?\ *([a-zA-Z_0-9]+)=.*" 11 | CONFIG_FILE="${DATA_DIR}/mumble_server_config.ini" 12 | 13 | readonly SENSITIVE_CONFIGS=( 14 | "dbPassword" 15 | "icesecretread" 16 | "icesecretwrite" 17 | "serverpassword" 18 | "registerpassword" 19 | "sslPassPhrase" 20 | ) 21 | 22 | # Compile list of configuration options from the bare-bones config 23 | readarray -t existing_config_options < <(sed -En "s/$CONFIG_REGEX/\2/p" "$BARE_BONES_CONFIG_FILE") 24 | 25 | # Grab the original command line that is supposed to start the Mumble server 26 | declare -a server_invocation=("${@}") 27 | declare -a used_configs 28 | 29 | normalize_name() { 30 | local uppercase="${1^^}" 31 | echo "${uppercase//_/}" 32 | } 33 | 34 | # Create an associative array for faster config option lookup 35 | declare -A option_for 36 | 37 | for config in "${existing_config_options[@]}"; do 38 | option_for["$(normalize_name "$config")"]="$config" 39 | done 40 | 41 | array_contains() { 42 | local array_expansion="$1[@]" seeking="$2" 43 | for element in "${!array_expansion}"; do 44 | [[ "$element" = "$seeking" ]] && return 0 45 | done 46 | return 1 47 | } 48 | 49 | set_config() { 50 | local config_name="$1" config_value="$2" is_default="$3" 51 | local apply_value=true 52 | 53 | [[ "$is_default" = true ]] && array_contains "used_configs" "$config_name" && \ 54 | apply_value=false # Don't use default value if the user already set one! 55 | 56 | [[ "$apply_value" != true ]] && return 0 57 | 58 | if array_contains "SENSITIVE_CONFIGS" "$config_name"; then 59 | echo "Setting config \"$config_name\" to: *********" 60 | else 61 | echo "Setting config \"$config_name\" to: '$config_value'" 62 | fi 63 | used_configs+=("$config_name") 64 | 65 | # Append config to our on-the-fly-built config file 66 | echo "${config_name}=${config_value}" >> "$CONFIG_FILE" 67 | } 68 | 69 | # Drop the user into a shell, if they so wish 70 | if [[ "$1" = "bash" || "$1" = "sh" ]]; then 71 | echo "Dropping into interactive BASH session" 72 | exec "${@}" 73 | fi 74 | 75 | if [[ -f "$MUMBLE_CUSTOM_CONFIG_FILE" ]]; then 76 | echo "Using manually specified config file at $MUMBLE_CUSTOM_CONFIG_FILE" 77 | echo "All MUMBLE_CONFIG variables will be ignored" 78 | CONFIG_FILE="$MUMBLE_CUSTOM_CONFIG_FILE" 79 | else 80 | # Ensures the config file is empty, starting from a clean slate 81 | echo -e "# Config file automatically generated from the MUMBLE_CONFIG_* environment variables" > "${CONFIG_FILE}" 82 | echo -e "# or secrets in /run/secrets/MUMBLE_CONFIG_* files\n" >> "${CONFIG_FILE}" 83 | 84 | # Process settings through variables of format MUMBLE_CONFIG_* 85 | 86 | while IFS='=' read -d '' -r var value; do 87 | config_option="${option_for[$(normalize_name "$var")]}" 88 | 89 | if [[ -z "$config_option" ]]; then 90 | if [[ "$MUMBLE_ACCEPT_UNKNOWN_SETTINGS" = true ]]; then 91 | echo "[WARNING]: Unable to find config corresponding to variable \"$var\". Make sure that it is correctly spelled, using it as-is" 92 | set_config "$var" "$value" 93 | else 94 | >&2 echo "[ERROR]: Unable to find config corresponding to variable \"$var\"" 95 | exit 1 96 | fi 97 | else 98 | set_config "$config_option" "$value" 99 | fi 100 | 101 | done < <( printenv --null | sed -zn 's/^MUMBLE_CONFIG_//p' ) 102 | # ^ Feeding it in like this, prevents the creation of a subshell for the while-loop 103 | 104 | # Check any docker/podman secrets matching the pattern and set config from there 105 | while read -r var; do 106 | config_option="${option_for[$(normalize_name "$var")]}" 107 | secret_file="/run/secrets/MUMBLE_CONFIG_$var" 108 | if [[ -z "$config_option" ]]; then 109 | if [[ "$MUMBLE_ACCEPT_UNKNOWN_SETTINGS" = true ]]; then 110 | echo "[WARNING]: Unable to find config corresponding to container secret \"$secret_file\". Make sure that it is correctly spelled, using it as-is" 111 | set_config "$var" "$value" 112 | else 113 | >&2 echo "[ERROR]: Unable to find config corresponding to container secret \"$secret_file\"" 114 | exit 1 115 | fi 116 | else 117 | set_config "$config_option" "$(cat $secret_file)" 118 | fi 119 | done < <( ls /run/secrets | sed -n 's/^MUMBLE_CONFIG_//p' ) 120 | 121 | # Apply default settings if they're missing 122 | 123 | # Compatibilty with old DB filename 124 | OLD_DB_FILE="${DATA_DIR}/murmur.sqlite" 125 | if [[ -f "$OLD_DB_FILE" ]]; then 126 | set_config "database" "$OLD_DB_FILE" true 127 | else 128 | set_config "database" "${DATA_DIR}/mumble-server.sqlite" true 129 | fi 130 | 131 | set_config "ice" "\"tcp -h 127.0.0.1 -p 6502\"" true 132 | 133 | if ! array_contains "used_configs" "welcometextfile"; then 134 | set_config "welcometext" "\"
Welcome to this server, running the official Mumble Docker image.
Enjoy your stay!
\"" true 135 | fi 136 | 137 | set_config "port" 64738 true 138 | set_config "users" 100 true 139 | 140 | { # Add ICE section 141 | echo -e "\n[Ice]" 142 | echo "Ice.Warn.UnknownProperties=1" 143 | echo "Ice.MessageSizeMax=65536" 144 | } >> "$CONFIG_FILE" 145 | fi 146 | 147 | # Additional environment variables 148 | 149 | [[ "$MUMBLE_VERBOSE" = true ]] && server_invocation+=( "-v" ) 150 | 151 | # Make sure the correct configuration file is used 152 | server_invocation+=( "-ini" "${CONFIG_FILE}") 153 | 154 | if [[ -f /run/secrets/MUMBLE_SUPERUSER_PASSWORD ]]; then 155 | MUMBLE_SUPERUSER_PASSWORD="$(cat /run/secrets/MUMBLE_SUPERUSER_PASSWORD)" 156 | echo "Read superuser password from container secret" 157 | fi 158 | 159 | if [[ -n "${MUMBLE_SUPERUSER_PASSWORD}" ]]; then 160 | #Variable to change the superuser password 161 | "${server_invocation[@]}" -supw "$MUMBLE_SUPERUSER_PASSWORD" 162 | echo "Successfully configured superuser password" 163 | fi 164 | 165 | # Set privileges for /app but only if pid 1 user is root and we are dropping privileges. 166 | # If container is run as an unprivileged user, it means owner already handled ownership setup on their own. 167 | # Running chown in that case (as non-root) will cause error 168 | if [[ "$(id -u)" = "0" ]] && [[ "${PUID}" != "0" ]] && [[ "${MUMBLE_CHOWN_DATA}" = true ]]; then 169 | chown -R ${PUID}:${PGID} /data 170 | fi 171 | 172 | # Show /data permissions, in case the user needs to match the mount point access 173 | echo "Running Mumble server as uid=${PUID} gid=${PGID}" 174 | echo "\"${DATA_DIR}\" has the following permissions set:" 175 | echo " $( stat ${DATA_DIR} --printf='%A, owner: \"%U\" (UID: %u), group: \"%G\" (GID: %g)' )" 176 | 177 | echo "Command run to start the service : ${server_invocation[*]}" 178 | echo "Starting..." 179 | 180 | # Drop privileges (when asked to) if root, otherwise run as current user 181 | if [[ "$(id -u)" = "0" ]] && [[ "${PUID}" != "0" ]]; then 182 | exec su-exec ${PUID}:${PGID} "${server_invocation[@]}" 183 | else 184 | exec "${server_invocation[@]}" 185 | fi 186 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mumble Docker 2 | 3 | ![Docker Image Version](https://img.shields.io/docker/v/mumblevoip/mumble-server) 4 | ![Docker Pulls](https://img.shields.io/docker/pulls/mumblevoip/mumble-server) 5 | ![Docker Image Size](https://img.shields.io/docker/image-size/mumblevoip/mumble-server) 6 | 7 | 8 | Mumble is a free, open source, low latency, high quality voice chat application. 9 | 10 |

Mumble WebsiteMumble Source

11 | 12 | This is the official code of the Mumble Docker image for self-hosting the **Mumble server**. The image is available for download on 13 | **[Dockerhub](https://hub.docker.com/r/mumblevoip/mumble-server)** and the **[GHCR](https://github.com/mumble-voip/mumble-docker/pkgs/container/mumble-server)**. 14 | 15 | ----- 16 | 17 | ## Quick Start Guide 18 | 19 | 1. [Running the container](#running-the-container) 20 | 2. [Configuration](#configuration) 21 | 3. [Building the container](#building-the-container) 22 | 4. [More docs and usage examples in the Wiki](https://github.com/mumble-voip/mumble-docker/wiki) 23 | 24 | 25 | ## Running the container 26 | 27 | ### Requirements 28 | 29 | This documentation assumes that you already have Docker installed and configured on your target machine. You may find it more convenient to set up the 30 | Docker container using [docker-compose](https://docs.docker.com/compose/). Thus, we also provide instructions for that scenario (see below). 31 | 32 | In order for Mumble to store permanent data (most notably the database file (by default Mumble uses SQLite)), the image will use a 33 | [volume](https://docs.docker.com/storage/volumes/) which is mapped to the `/data/` path inside the image. By default the image uses a user with UID 34 | `10000` and GID of also `10000` but either can be adapted when building the image yourself (see below). You will have to make sure that all file 35 | permissions are set up accordingly. 36 | 37 | ### Running the container 38 | 39 | **Using docker**: 40 | ```bash 41 | $ docker run --detach \ 42 | --name mumble-server \ 43 | --publish 64738:64738/tcp \ 44 | --publish 64738:64738/udp \ 45 | --volume ./data/mumble:/data \ 46 | --restart on-failure \ 47 | mumblevoip/mumble-server: 48 | ``` 49 | For possible values of `` see below. 50 | 51 | **Using docker-compose**: 52 | ```yaml 53 | services: 54 | mumble-server: 55 | image: mumblevoip/mumble-server: 56 | container_name: mumble-server 57 | hostname: mumble-server 58 | restart: on-failure 59 | ports: 60 | - 64738:64738 61 | - 64738:64738/udp 62 | # expose: 63 | # - 6502 64 | ``` 65 | For possible values of `` see below. 66 | 67 | The additional port `6502` could for instance be used to expose the [ICE interface](https://wiki.mumble.info/wiki/Murmur.ini#ice). You'll obviously 68 | have to adapt the used port for whatever you configured in the server's configuration file. 69 | 70 | ### Tags 71 | 72 | For an up-to-date list of available tags, see [Dockerhub](https://hub.docker.com/r/mumblevoip/mumble-server/tags). Generally, you can either use 73 | `latest` to always fetch the latest version or tags of the form `vX.Y.Z` corresponding to the respective stable releases of Mumble, e.g. `v1.4.230`. 74 | 75 | 76 | ## Configuration 77 | 78 | The preferred way of configuring the server instance in the Docker container is by means of environment variables. All of these variables take the 79 | form `MUMBLE_CONFIG_`, where `` is the name of the configuration to set. All config options that can be set in the regular 80 | Mumble server configuration file (historically called `murmur.ini`) can be set. For an overview of available options, see 81 | [here](https://wiki.mumble.info/wiki/Murmur.ini). 82 | 83 | `` is case-insensitive and underscores may be inserted into the respective config name, to increase readability. Thus, 84 | `MUMBLE_CONFIG_dbhost`, `MUMBLE_CONFIG_DBHOST` and `MUMBLE_CONFIG_DB_HOST` all refer to the same config `dbHost`. 85 | 86 | The container entrypoint will use these environment variables and build a corresponding configuration file from it on-the-fly, which is then used the 87 | spun-up server. 88 | 89 | You can specify these environment variables when starting the container using the `-e` command-line option as documented 90 | [here](https://docs.docker.com/engine/reference/run/#env-environment-variables): 91 | ```bash 92 | $ docker run -e "MUMBLE_CONFIG_SERVER_PASSWORD=123" 93 | ``` 94 | 95 | As an alternative to environment variables, docker or podman secrets can be used to read configuration options from files which follow the `MUMBLE_CONFIG_` name pattern and are located in the `/run/secrets` directory at runtime. The same rules to naming environment variables apply to these files as well. 96 | 97 | Please consult the documentation of docker or podman on how to use secrets for further details. 98 | - [Docker (Swarm) Secrets](https://docs.docker.com/engine/swarm/secrets/) 99 | - Podman Secrets 100 | - [podman run with secrets](https://docs.podman.io/en/latest/markdown/podman-run.1.html#secret-secret-opt-opt) 101 | - [podman secret subcommand](https://docs.podman.io/en/latest/markdown/podman-secret.1.html) 102 | 103 | ### Example: Running the container with secrets using podman 104 | To set the server password and superuser password using podman secrets, the following series of commands can be used: 105 | 106 | ```bash 107 | # Create the secrets 108 | echo -n "secretserver" | podman secret create MUMBLE_CONFIG_SERVER_PASSWORD - 109 | echo -n "supassword" | podman secret create MUMBLE_SUPERUSER_PASSWORD - 110 | 111 | # Run the server with these secrets mounted 112 | podman run --detach \ 113 | --name mumble-server \ 114 | --publish 64738:64738/tcp \ 115 | --publish 64738:64738/udp \ 116 | --secret MUMBLE_CONFIG_SERVER_PASSWORD \ 117 | --secret MUMBLE_SUPERUSER_PASSWORD \ 118 | --volume ./data/mumble:/data \ 119 | --restart on-failure \ 120 | mumblevoip/mumble-server: 121 | ``` 122 | 123 | ### Additional variables 124 | 125 | The following _additional_ variables can be set for further server configuration: 126 | 127 | | Environment Variable | Description | 128 | |----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------- | 129 | | `MUMBLE_ACCEPT_UNKNOWN_SETTINGS` | Set to `true` to force the container to accept unknown settings passed as a `MUMBLE_CONFIG_` variable (see note below). | 130 | | `MUMBLE_CHOWN_DATA` | Set to `false` to skip taking ownership of `/data` and its contents. | 131 | | `MUMBLE_CUSTOM_CONFIG_FILE` | Specify a custom config file path - **all `MUMBLE_CONFIG_` variables are IGNORED**
(it's best to use a path inside the volume `/data/`) | 132 | | `MUMBLE_SUPERUSER_PASSWORD` | Specifies the SuperUser (Admin) password for this server. If this is not given, a random password will be generated upon first startup. | 133 | | `MUMBLE_VERBOSE` | Set to `true` to enable verbose logging in the server | 134 | 135 | 136 | Note: In the unlikely case where a `` setting is unknown to the container, startup will fail with the following error. 137 | 138 | 139 | ``` 140 | mumble-server | [ERROR]: Unable to find config corresponding to variable "" 141 | mumble-server exited with code 1 142 | ``` 143 | 144 | The root cause of this error is the fact that this setting is incorrectly registered in the Mumble server code. You can workaround this error by 145 | setting the `MUMBLE_ACCEPT_UNKNOWN_SETTINGS` environment variable to `true` and spelling `` exactly as written in the 146 | [Murmur.ini](https://wiki.mumble.info/wiki/Murmur.ini) documentation. 147 | 148 | 149 | ## Building the container 150 | 151 | After having cloned this repository, you can just run 152 | ```bash 153 | $ docker build . 154 | ``` 155 | in order to build a Mumble server from the latest commit in the upstream [master branch](https://github.com/mumble-voip/mumble/commits/master). 156 | 157 | If you prefer to instead build a specific version of the Mumble server, you can use the `MUMBLE_VERSION` argument like this: 158 | ```bash 159 | $ docker build --build-arg MUMBLE_VERSION=v1.4.230 . 160 | ``` 161 | `MUMBLE_VERSION` can either be one of the [published tags](https://github.com/mumble-voip/mumble/tags) of the upstream repository or a commit hash of 162 | the respective commit to build. 163 | 164 | Note that either way, only Mumble versions >= 1.4 can be built using this image. Mumble versions 1.3 and earlier are not compatible with the build 165 | process employed by this Docker image. 166 | 167 | ### Using a different UID/GID 168 | 169 | You can use Docker-standard `PUID` and `PGID` environment variables to set the UID and GID you wish mumble-server to run as and who will own the 170 | files in `/data`. The default is UID:GID 10000:10000. Unless the environment variable `MUMBLE_CHOWN_DATA` is set to `false` the container will 171 | take ownership of `/data` and any of its contents at container launch. 172 | 173 | ### Using custom build options 174 | 175 | It is also possible to pass custom cmake options to the build process by means of the `MUMBLE_CMAKE_ARGS` build variable. That way, you can customize 176 | the build to your liking. For instance, this could be used to enable the Tracy profiler (assuming you are building a version of the server that has 177 | support for it): 178 | ```bash 179 | $ docker build --build-arg MUMBLE_CMAKE_ARGS="-Dtracy=ON" 180 | ``` 181 | 182 | For an overview of all available build options, check the 183 | [build instructions](https://github.com/mumble-voip/mumble/blob/master/docs/dev/build-instructions) of the main project. 184 | 185 | 186 | ### Common build issues 187 | 188 | Should you see the error 189 | ``` 190 | Got permission denied while trying to connect to the Docker daemon socket 191 | ``` 192 | you most likely invoked `docker` as a non-root user. In order for that to be possible, you need to add yourself to the `docker` group on your system. 193 | See the [official docs](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user) on this topic for further 194 | information. 195 | 196 | --------------------------------------------------------------------------------