Turn your Linux PC into a softphone for your mobile’s GSM calls. This project runs Asterisk with the chan_mobile Bluetooth gateway inside a Docker container, so you can:
- Receive incoming GSM calls on your PC (ring a SIP client like Linphone)
- Place outgoing calls from your SIP client via your mobile phone over Bluetooth
It uses BlueZ + D-Bus for Bluetooth, and Asterisk to bridge GSM↔SIP audio.
- A privileged container starts
dbus,bluetoothd(BlueZ), andasterisk. - The container reuses the host Bluetooth pairing database from
/var/lib/bluetooth. - Asterisk loads
chan_mobileand connects to your paired phone over Bluetooth RFCOMM/HFP. - Dialplan bridges calls:
- Incoming GSM → rings SIP extension
1001. - Outgoing from SIP → dials out using the paired mobile device.
- Incoming GSM → rings SIP extension
Key files in this repo configure that flow:
docker-compose.yml— host integration and device accessDockerfile— Ubuntu 18.04 + BlueZ + Asterisk runtimechan_mobile.conf/mobile.conf— Bluetooth adapter and phone mappingsip.conf— local SIP account1001for your softphoneextensions.conf— dialplan bridging SIP↔Mobilertp.conf,logger.conf— media and loggingstart.sh— launches dbus, bluetoothd, and asterisk in-foregroundhost-config/tel_url_handler/linphone-tel,host-config/tel_url_handler/linphone-tel.desktop— optional tel: link handler for Linphone
- Linux host with working Bluetooth adapter
- Docker and Docker Compose
- A SIP softphone on the host (e.g., Linphone)
- A mobile phone with Bluetooth Hands‑Free support (HFP)
Notes
- Container runs with
privileged,network_mode: host, and/devbind. This is necessary for BlueZ/Bluetooth access and Asterisk audio bridging. - Ubuntu 18.04 base is used to match Asterisk and BlueZ versions known to work with
chan_mobile. - Not compatible with Docker Desktop installed via App Center/Snap/Flatpak. Those setups typically cannot expose host D-Bus and the physical Bluetooth adapter to containers. Use a native Docker Engine installation on the host OS.
Why Docker?
- Asterisk’s
chan_mobilehas long‑standing compatibility issues with the modern Bluetooth stack in newer Ubuntu releases (e.g., 24.04). On up‑to‑date hosts, Asterisk often fails to cooperate reliably with BlueZ/DBus for HFP/RFCOMM, causing unstable pairing, device discovery, or Audio Gateway operation. This container pins an older, known‑good userspace (Ubuntu 18.04 with matching BlueZ/Asterisk) so you don’t need to downgrade your entire OS just to make GSM↔SIP bridging work.
Avoid Docker Desktop from App Center/Snap/Flatpak — it won’t pass through host D-Bus or the Bluetooth adapter in the way this stack requires. Install Docker Engine natively from Docker’s official APT repository.
- Optional: remove conflicting packages (Docker Desktop, legacy docker.io)
- These commands are safe if those packages are absent.
sudo apt remove -y docker-desktop || true sudo apt remove -y docker.io docker-doc podman-docker containerd runc || true # Do NOT remove your data unless you intend to: # sudo rm -rf /var/lib/docker /var/lib/containerd
- Install prerequisites and add Docker’s APT repo
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release; echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update- Install Docker Engine + Compose plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker- (Optional) Run Docker as your user
sudo usermod -aG docker $USER
# Log out and back in (or reboot) so your group membership applies- Verify
docker run --rm hello-world
docker compose version- Pair and trust your phone on the host
- Do this on the host, not inside the container. Use your desktop Bluetooth UI or
bluetoothctl:bluetoothctl power on agent on default-agent scan on # wait until you see your phone (e.g., XX:XX:XX:XX:XX:XX) pair XX:XX:XX:XX:XX:XX trust XX:XX:XX:XX:XX:XX connect XX:XX:XX:XX:XX:XX quit
- Adjust Bluetooth addresses
- The repo tracks
chan_mobile.conf.exampleandmobile.conf.example. - Copy them to local
chan_mobile.confandmobile.confbefore editing MAC addresses. The local.conffiles are ignored by git. - Edit
chan_mobile.conf(andmobile.conffor compatibility) and set:[adapter] address=to your host’s Bluetooth adapter MAC.[mobile_phone] address=to your phone’s Bluetooth MAC.- Keep
port=3unless you know your HFP/RFCOMM channel differs. To discover your phone’s HFP/RFCOMM channel, run:sudo sdptool records XX:XX:XX:XX:XX:XX | grep -i -A10 "Audio Gateway\|Handsfree"Replace the MAC and use the reported RFCOMM channel forport.
- Hand Bluetooth control to the container (first-time or as needed)
-
If you see conflicts with the host's
bluetoothd, let the container own Bluetooth (dbus + bluetoothd) and claim the adapter.sudo systemctl stop bluetooth || true sudo systemctl disable bluetooth || true sudo rfkill unblock bluetooth sudo modprobe btusb bluetooth rfcomm sudo hciconfig hci0 up hciconfig -a # look for UP RUNNING
To use Bluetooth on the host again later, stop the container and re-enable the host service:
docker compose down sudo systemctl enable bluetooth sudo systemctl start bluetooth sudo rfkill unblock bluetooth sudo hciconfig hci0 up
- Build and run
docker compose builddocker compose up -d
- Verify the phone auto-connects
- Watch logs:
docker logs -f asterisk-mobile - Optional one-shot checks:
docker exec asterisk-mobile asterisk -rx "mobile show devices"docker exec asterisk-mobile asterisk -rx "mobile show connections"
- If the phone was already paired and trusted on the host, no manual pairing inside the container should be needed.
- Register your SIP client
- Configure your SIP softphone to register to:
- Server:
127.0.0.1 - User:
1001 - Password:
1234(change it!) - Transport: UDP
- Server:
- Test
- Outgoing: dial a number from your SIP client; it should go out via your phone.
- Incoming: call your mobile; your SIP client should ring as extension
1001.
Install and point Linphone (Desktop or CLI) to Asterisk on the host, and use the provided configs.
-
Install Linphone
- Ubuntu 24.x: from App Center (or via apt/flatpak). Any recent Linphone Desktop or
linphonecworks.
- Ubuntu 24.x: from App Center (or via apt/flatpak). Any recent Linphone Desktop or
-
Copy the config
- For Linphone Desktop (GUI):
mkdir -p "$HOME/.config/linphone"cp host-config/linphone/linphonerc "$HOME/.config/linphone/linphonerc"
- For Linphone CLI (
linphonec):mkdir -p "$HOME/.config/linphone"cp host-config/linphone/linphonerc-asterisk "$HOME/.config/linphone/linphonerc"
- For Linphone Desktop (GUI):
-
Adjust credentials if needed
- In
~/.config/linphone/linphonerc, under[proxy_0]set:reg_proxy=sip:127.0.0.1;transport=udp(or your Asterisk IP)reg_identity=sip:1001@127.0.0.1(or your extension@server)
- Linphone will prompt for the password on first register unless you add an
[auth_info_*]section.
- In
-
About these config files
- They are full configs (not minimal). Linphone may auto-extend/modify them on first run — that’s expected.
- Personal/Sensitive values was redacted from the versions in this repo:
[sip] contact=...replaced with a genericsip:1001@127.0.0.1to avoid exposing usernames/hosts.[misc] uuid=...replaced with<uuid>.[sound] *_dev_id=...changed toPulseAudio Defaultto avoid exposing specific hardware names.[auth_info_0] ha1=...replaced with<ha1>because it is a password hash.
- If you prefer persistent credentials delete the whole
[auth_info_*]section and enter credentials via the UI once; Linphone will recreate it.
-
Notes
- You don’t need to remove Linphone’s auto-generated sections; keeping them is fine.
Asterisk SIP account: sip.conf
[1001]is a local user for your softphone.- Change
secret, and adapt codecs (alaw/ulaw) to your needs.
Bluetooth gateway: chan_mobile.conf (and mobile.conf)
[adapter] id=usbandaddress=<adapter-mac>point to your adapter.[mobile_phone] address=<phone-mac>,port=3,context=from-mobile,adapter=usb.- On some phones the HFP/RFCOMM channel can differ; if calls fail to connect, scan channels with
sdptool browse <phone-mac>and updateportaccordingly.
Dialplan: extensions.conf
- Global
MOBILE_IFACE=mobile_phonemaps to your phone section. from-sip: anything dialed_X.from SIP is sent toMobile/${MOBILE_IFACE}/${EXTEN}.from-mobile: incoming GSM calls dialSIP/1001to ring your softphone.
RTP/media: rtp.conf
- RTP range narrowed to
10000–10100. Open these UDP ports if you firewall.
Logging: logger.conf
consoleandfulllog files enabled for diagnostics.
Container: docker-compose.yml
privileged: true,network_mode: host,/dev, and/var/lib/bluetoothpassthrough enable Bluetooth access and reuse the host pairing database.
Entrypoint: start.sh
- Starts a private system
dbus,bluetoothd --compat, thenasterisk -f -vvv.
Optional: attach to the running Asterisk CLI for debugging:
docker exec -it asterisk-mobile asterisk -rvvvvv
Useful commands:
core show channelscore set verbose 5mobile show devicesmobile show connectionsmobile statussip show peers(for chan_sip)
Logs:
docker logs -f asterisk-mobile- Container log files are also available under
/var/log/asterisk/if you need deeper debugging.
If you use Linphone on the host, you can make tel: links dial via Linphone automatically.
- Create a small helper:
- Save
host-config/tel_url_handler/linphone-telto~/.local/bin/linphone-teland make it executable:mkdir -p ~/.local/bincp host-config/tel_url_handler/linphone-tel ~/.local/bin/linphone-telchmod +x ~/.local/bin/linphone-tel
- Register the desktop handler:
- Copy
host-config/tel_url_handler/linphone-tel.desktopto~/.local/share/applications/:mkdir -p ~/.local/share/applicationscp host-config/tel_url_handler/linphone-tel.desktop ~/.local/share/applications/
- Update and set default handler:
update-desktop-database ~/.local/share/applications/xdg-mime default linphone-tel.desktop x-scheme-handler/tel- Verify:
xdg-mime query default x-scheme-handler/tel→linphone-tel.desktop
The helper normalizes numbers (strips spaces, keeps digits/+, converts + to 00) and launches Linphone with call sip-address=....
Switching Bluetooth control (host ↔ container)
- Give control to the container (if host
bluetoothdconflicts):sudo systemctl stop bluetooth || true sudo systemctl disable bluetooth || true sudo rfkill unblock bluetooth sudo hciconfig hci0 up
- Return control to the host:
docker compose down sudo systemctl enable bluetooth sudo systemctl start bluetooth sudo rfkill unblock bluetooth sudo hciconfig hci0 up # Optionally: bluetoothctl → power on
Bluetooth doesn’t start in container
- Check container privileges match
docker-compose.yml. - Inspect
docker logs -f asterisk-mobileafter start. - Run one-shot diagnostics with
docker exec asterisk-mobile rfkill list,docker exec asterisk-mobile hciconfig -a, anddocker exec asterisk-mobile dmesg | tail -n 100.
Phone not pairing or connecting
- Pair and trust the phone on the host first while the host
bluetoothdservice is running. - Ensure
/var/lib/bluetoothis bind-mounted into the container and the MAC addresses inchan_mobile.confmatch the host bond. - After host pairing, stop the host
bluetoothdservice before starting the container so the container can claim the adapter.
Outgoing calls fail immediately
- Verify
portinchan_mobile.confmatches phone’s HFP/RFCOMM channel (sdptool browse <mac>). - Confirm
mobile show devicesshows your device asConnected.
No audio / one‑way audio
- Open RTP UDP range in firewall:
10000–10100. - Check
directmedia=noand codec compatibility insip.conf.
SIP client won’t register
- Confirm SIP points to
127.0.0.1, user1001, password changed and correct. sip show peersshould list1001asOKwith latency.
Asterisk module not loading chan_mobile
- Verify the image build completed successfully and
chan_mobile.soexists in/usr/lib/asterisk/modules/. - Run
docker exec asterisk-mobile asterisk -rx "module show like chan_mobile.so"and review Asterisk logs for load errors.
- Change default SIP credentials in
sip.confbefore use. - Limit exposed services; this stack uses
network_mode: host. Prefer local network only. - Keep OS and Docker updated. Ubuntu 18.04 is EOL; for long‑term use, consider updating the base and re‑validating
chan_mobile.
- Do I need both
chan_mobile.confandmobile.conf?- Some Asterisk builds use
chan_mobile.conf. This repo includes both (same content) for compatibility; adjust both or preferchan_mobile.conf.
- Some Asterisk builds use
- Do I need to pair inside the container?
- No. Pair and trust the phone on the host first; the container reuses
/var/lib/bluetoothand auto-attempts the connection on startup.
- No. Pair and trust the phone on the host first; the container reuses
- Which SIP client should I use?
- Linphone, baresip, or any basic SIP client. Start simple: PC and container on the same host with UDP transport.
Contributions and improvements welcome.