ByteDesk FreeSWITCH Docker Image
July 24, 2026 Β· View on GitHub
FreeSWITCH 1.10.12 Docker image for ByteDesk Call Center System, based on Ubuntu 22.04 LTS.
π Table of Contents
- Features
- Comparison with "Official" Image
- Installation
- Configuration
- Environment Variables
- Ports
- Server
- Open Source Demo + SDK
Features
- β FreeSWITCH 1.10.12 stable release
- β Based on Ubuntu 22.04 LTS
- β mod_mariadb module included
- β MySQL/MariaDB database support
- β PostgreSQL database support
- β WebRTC support via SIP.js + mod_sofia
- β WebSocket audio streaming via mod_audio_stream
- β Icecast/MP3 streaming via mod_shout
- β Video call support (VP8/VP9/H264)
- β Basic audio files included (8kHz)
- β SIP TLS encryption support
- β Health check enabled
- β Environment variable configuration
- β Multi-architecture support (amd64/arm64)
- β Baidu MRCP Server integrated by default (bundled in image and auto-started)
- β MRCP client support available (mod_unimrcp, opt-in build)
- β mod_verto disabled (use SIP over WebSocket instead)
Comparison with "Official" Image
- safarov/freeswitch β supports amd64 only (see tags β https://hub.docker.com/r/safarov/freeswitch/tags)
- bytedesk/freeswitch β supports both amd64 and arm64 (see tags β https://hub.docker.com/r/bytedesk/freeswitch/tags)
Tip: Multi-arch images run natively on x86_64 servers and ARM devices like Apple Silicon (M1/M2/M3) without manual image switching.
Installation
Method 1: Docker Run
# Pull from Docker Hub
docker pull bytedesk/freeswitch:latest
# Pull from Alibaba Cloud (recommended for China)
docker pull registry.cn-hangzhou.aliyuncs.com/bytedesk/freeswitch:latest
# Run container (adjust env/ports for your scenario)
docker run -d \
--name freeswitch \
-p 5060:5060/tcp -p 5060:5060/udp \
-p 5080:5080/tcp -p 5080:5080/udp \
-p 8021:8021 \
-p 7443:7443 \
-p 16384-32768:16384-32768/udp \
-e FREESWITCH_ESL_PASSWORD='YOUR_ESL_PASSWORD' \
-e FREESWITCH_DEFAULT_PASSWORD='YOUR_SIP_PASSWORD' \
-e FREESWITCH_DOMAIN=sip.yourdomain.com \
-e FREESWITCH_EXTERNAL_IP=YOUR_PUBLIC_IP \
-e TZ=Asia/Shanghai \
-v freeswitch_data:/usr/local/freeswitch \
# Config directory - override container config with local files (actual runtime path: /usr/local/freeswitch/etc/freeswitch)
-v ../../../../deploy/freeswitch/conf:/usr/local/freeswitch/etc/freeswitch \
--restart=unless-stopped \
bytedesk/freeswitch:latest
Method 2: Docker Compose
Single Example (Optional Custom Configuration)
Create a docker-compose.yml file (uncomment the mount line if you want to use local custom configs):
version: "3.9"
services:
freeswitch:
image: bytedesk/freeswitch:latest
container_name: freeswitch-bytedesk
restart: unless-stopped
ports:
- "5060:5060/tcp"
- "5060:5060/udp"
- "5080:5080/tcp"
- "5080:5080/udp"
- "8021:8021"
- "7443:7443"
- "16384-32768:16384-32768/udp"
environment:
FREESWITCH_ESL_PASSWORD: ${ESL_PASSWORD}
FREESWITCH_DEFAULT_PASSWORD: ${SIP_PASSWORD}
FREESWITCH_DOMAIN: ${DOMAIN}
FREESWITCH_EXTERNAL_IP: ${EXTERNAL_IP}
TZ: Asia/Shanghai
# Built-in Baidu MRCP Server configuration
# BAIDU_MRCP_ENABLE: "1"
# BAIDU_APPID: your_app_id
# BAIDU_API_KEY: your_api_key
# BAIDU_SECRET_KEY: your_secret_key
# BAIDU_MRCP_SIP_PORT: "5070"
# BAIDU_MRCP_CONTROL_PORT: "1544"
# BAIDU_MRCP_SAVE_AUDIO: "1"
volumes:
# Optional: mount custom configuration directory (actual runtime path: /usr/local/freeswitch/etc/freeswitch)
# - ./freeswitch-conf:/usr/local/freeswitch/etc/freeswitch
# Or, per your project structure:
# - ../../../../deploy/freeswitch/conf:/usr/local/freeswitch/etc/freeswitch
# Data persistence
- freeswitch-log:/usr/local/freeswitch/log
- freeswitch-db:/usr/local/freeswitch/db
- freeswitch-recordings:/usr/local/freeswitch/recordings
healthcheck:
test: ["CMD", "fs_cli", "-p", "${ESL_PASSWORD}", "-x", "status"]
interval: 30s
timeout: 10s
retries: 5
volumes:
freeswitch-log:
freeswitch-db:
freeswitch-recordings:
Note: When using local custom configuration, make sure the target path is /usr/local/freeswitch/etc/freeswitch, which is the actual configuration directory read by FreeSWITCH at runtime.
Create a .env file (copy from docker/.env.example):
ESL_PASSWORD=MyStr0ng#ESL!Pass2024
SIP_PASSWORD=MyStr0ng#SIP!Pass2024
DOMAIN=sip.company.com
EXTERNAL_IP=203.0.113.10
Start the container:
docker compose up -d
Configuration
Custom Configuration Files
Baidu MRCP Server (built-in)
- The image downloads and bundles Baidu MRCP Server during build. On container start, it writes configs from env vars and starts the server in background.
- FreeSWITCH connects to the built-in server via
127.0.0.1:5070by default (mrcp_profiles/baidu.xml). - No port mapping is required for typical usage. If you want to expose the MRCP server for external clients, publish
5070/udp,tcp,1544/tcp, and1554/tcp.
Runtime environment variables:
BAIDU_MRCP_ENABLE: enable built-in MRCP server (default 1)BAIDU_APPID: Baidu AppIDBAIDU_API_KEY: Baidu API Key (maps to AUTH_APPKEY in config)BAIDU_SECRET_KEY: Baidu Secret Key (not used in current sample configs, reserved)BAIDU_MRCP_SIP_PORT: MRCP server SIP port (default 5070 to avoid FS 5060 conflict)BAIDU_MRCP_CONTROL_PORT: MRCPv2 control port (default 1544)BAIDU_MRCP_SAVE_AUDIO: whether to save audio (1/0, default 1)
Build-time argument:
BAIDU_MRCP_URL: download URL of the Baidu MRCP Server tarball (defaulthttps://www.weiyuai.cn/download/mrcp_server_baidu.tar.gz)
Compose snippet (partial):
environment:
- BAIDU_MRCP_ENABLE=1
- BAIDU_APPID=your_app_id
- BAIDU_API_KEY=your_api_key
- BAIDU_SECRET_KEY=your_secret_key
- BAIDU_MRCP_SIP_PORT=5070
- BAIDU_MRCP_CONTROL_PORT=1544
- BAIDU_MRCP_SAVE_AUDIO=1
Verify runtime:
# Check MRCP server output in container logs
docker logs -f freeswitch-bytedesk | tail -n 200
# Or inspect detailed log inside container
docker exec -it freeswitch-bytedesk bash -lc 'tail -n 200 /var/log/unimrcpserver.out'
FreeSWITCH default profile: conf/mrcp_profiles/baidu.xml
<profile name="baidu" version="2">
<param name="server-ip" value="127.0.0.1"/>
<param name="server-port" value="5070"/>
<param name="sip-transport" value="udp"/>
<recogparams>
<param name="start-input-timers" value="false"/>
</recogparams>
</profile>
MRCP (mod_unimrcp) Quick Notes (client)
- The image includes loading config for mod_unimrcp. To use it as a client inside the image, enable UniMRCP build at image build time (
--build-arg BUILD_UNIMRCP=1). - Default client profile file:
conf/mrcp_profiles/baidu.xml(editserver-ipto your MRCP server). - UniMRCP client settings file:
conf/autoload_configs/unimrcp.conf.xml(default-profile=baidu). - Verify module:
fs_cli -x "show modules | grep unimrcp"should listmod_unimrcp.
Dialplan example:
<extension name="baidu_asr_test">
<condition field="destination_number" expression="^9001$">
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="speak" data="Please speak"/>
<action application="play_and_detect_speech"
data="silence_stream://2000 mrcp:baidu {start-input-timers=false}builtin:grammar/boolean grammar.xml"/>
<action application="log" data="INFO ASR result: ${detect_speech_result}"/>
</condition>
</extension>
WebSocket Audio Streaming (mod_audio_stream)
- The image now builds and loads
mod_audio_streamby default. - This module is intended for real-time audio streaming between FreeSWITCH and external WebSocket services such as ASR, AI agents, TTS pipelines, or custom media processors.
- The Docker build uses
MOD_AUDIO_STREAM_REFto select the upstream git ref. The default value ismain.
Recommended versioning strategy:
- For development or upstream tracking, keep
MOD_AUDIO_STREAM_REF=main - For staging or production, pin to a tested tag or commit SHA for reproducible builds
Build examples:
# Pin to a release tag
docker build -f docker/Dockerfile docker \
--build-arg MOD_AUDIO_STREAM_REF=v1.0.0 \
-t bytedesk/freeswitch:mod-audio-stream
# Pin to a commit
docker build -f docker/Dockerfile docker \
--build-arg MOD_AUDIO_STREAM_REF=ec2a781 \
-t bytedesk/freeswitch:mod-audio-stream
Verify the module inside a running container:
docker exec -it freeswitch fs_cli -x "show modules like audio_stream"
If the output contains mod_audio_stream, the module was installed and loaded successfully.
Dialplan example (minimal β starts streaming on answer):
<extension name="audio_stream_demo">
<condition field="destination_number" expression="^9002$">
<action application="answer"/>
<action application="sleep" data="500"/>
<!--
mix-type: mono | mixed | stereo
sampling-rate: 8k | 16k
metadata (optional): valid UTF-8 text sent before audio
-->
<action application="set"
data="stream_result=${expand(api uuid_audio_stream ${uuid} start ws://your-server:8080/stream mixed 8k hello_from_freeswitch)}"/>
<action application="log" data="INFO audio_stream started: ${stream_result}"/>
</condition>
</extension>
fs_cli / ESL example (start, send text, stop):
# Start streaming
fs_cli -x "uuid_audio_stream <uuid> start ws://your-server:8080/stream mixed 8k"
# Send text mid-stream
fs_cli -x "uuid_audio_stream <uuid> send_text a text message"
# Stop
fs_cli -x "uuid_audio_stream <uuid> stop"
Important: Configuration Path Information
FreeSWITCH actual configuration path: /usr/local/freeswitch/etc/freeswitch
The container contains two configuration directories:
/usr/local/freeswitch/etc/freeswitch- β Actually used at runtime (correct mount path)/usr/local/freeswitch/conf- β Backup directory (not read by FreeSWITCH process)
Verification method:
# Verify the actual configuration path in the container
docker exec -it freeswitch-container fs_cli -p YOUR_ESL_PASSWORD -x 'global_getvar conf_dir'
# Output: /usr/local/freeswitch/etc/freeswitch
Steps to Configure Custom XML Files
-
Export default configuration:
mkdir -p ./freeswitch-conf docker run --rm bytedesk/freeswitch:latest \ tar -C /usr/local/freeswitch/etc/freeswitch -cf - . | tar -C ./freeswitch-conf -xf - -
Edit XML files locally:
vars.xml&sip_profiles/internal.xml- SIP domains, ports, codecsautoload_configs/switch.conf.xml- RTP port range, core databaseautoload_configs/db.conf.xml&autoload_configs/odbc.conf.xml- Database DSNautoload_configs/event_socket.conf.xml- ESL configuration
-
Mount custom configuration (use correct path):
docker run -d \ --name freeswitch \ -v $(pwd)/freeswitch-conf:/usr/local/freeswitch/etc/freeswitch \ -p 5060:5060/tcp -p 5060:5060/udp \ -p 8021:8021 \ -e FREESWITCH_ESL_PASSWORD=password \ bytedesk/freeswitch:latest
β οΈ Critical Notice:
- You MUST mount to
/usr/local/freeswitch/etc/freeswitchpath, this is the actual configuration directory FreeSWITCH reads at runtime- If you mount to
/usr/local/freeswitch/confpath, FreeSWITCH will not read the custom configuration, which may cause issues like ESL connection failure- Use
fs_cli -x 'global_getvar conf_dir'command to verify the current configuration path
Environment Variables
Core Configuration
| Variable | Description | Default | Required | Security Level |
|---|---|---|---|---|
FREESWITCH_ESL_PASSWORD | ESL management password | - | β Yes | π΄ High |
FREESWITCH_DEFAULT_PASSWORD | Default SIP user password | 1234 | β οΈ Strongly Recommended | π΄ High |
FREESWITCH_DOMAIN | SIP domain or IP address | - | No | π‘ Medium |
FREESWITCH_EXTERNAL_IP | External IP for NAT traversal | - | No | π’ Low |
TZ | Timezone | Asia/Shanghai | No | π’ Low |
RTP Media Configuration
| Variable | Description | Default | Required |
|---|---|---|---|
FREESWITCH_RTP_START | RTP start port | 16384 | No |
FREESWITCH_RTP_END | RTP end port | 32768 | No |
Database Configuration
The image enables FreeSWITCH core PostgreSQL support at build time (--enable-core-pgsql-support), so you can use PostgreSQL in addition to MySQL/MariaDB.
| Variable | Description | Default | Required |
|---|---|---|---|
FREESWITCH_DB_HOST | Database host | - | No |
FREESWITCH_DB_NAME | Database name | - | No |
FREESWITCH_DB_USER | Database user | root | No |
FREESWITCH_DB_PASSWORD | Database password | - | No |
FREESWITCH_DB_PORT | Database port | 3306 | No |
FREESWITCH_DB_CHARSET | Database charset | utf8mb4 | No |
FREESWITCH_DB_SCHEME | Core DB connection scheme | mariadb | No |
FREESWITCH_DB_ODBC_DIALECT | ODBC connection dialect | mysql | No |
Configuration Examples
Development Environment:
docker run -d \
-e FREESWITCH_ESL_PASSWORD=dev123 \
-e FREESWITCH_DEFAULT_PASSWORD=test1234 \
bytedesk/freeswitch:latest
Production with Database:
docker run -d \
-e FREESWITCH_ESL_PASSWORD='MyStr0ng#ESL!Pass2024' \
-e FREESWITCH_DEFAULT_PASSWORD='MyStr0ng#SIP!Pass2024' \
-e FREESWITCH_DOMAIN=sip.company.com \
-e FREESWITCH_EXTERNAL_IP=203.0.113.10 \
-e FREESWITCH_DB_HOST=mysql.internal \
-e FREESWITCH_DB_NAME=freeswitch \
-e FREESWITCH_DB_USER=fsuser \
-e FREESWITCH_DB_PASSWORD='db_secure_pass' \
bytedesk/freeswitch:latest
Ports
Required Ports
| Port | Protocol | Description |
|---|---|---|
| 5060 | TCP/UDP | SIP internal |
| 5080 | TCP/UDP | SIP external |
| 8021 | TCP | ESL management |
| 7443 | TCP | WebRTC WSS |
| 16384-32768 | UDP | RTP media |
Optional Ports
| Port | Protocol | Description |
|---|---|---|
| 5061 | TCP | SIP internal TLS |
| 5081 | TCP | SIP external TLS |
| 5066 | TCP | WebSocket signaling |
| 3478-3479 | UDP | STUN service |
Server
Open Source Demo + SDK
| Project | Description | Forks | Stars |
|---|---|---|---|
| iOS | iOS | ||
| Android | Android | ||
| Flutter | Flutter | ||
| UniApp | Uniapp | ||
| Web | Vue/React/Angular/Next.js/JQuery/... | ||
| Wordpress | Wordpress | ||
| Woocommerce | woocommerce |