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. - Asterisk loads
chan_mobileand connects to your 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/linphone-tel,host/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- Host prep (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. Many systems only need this once; after reboots it often keeps working without repeating these steps.# Give control to the container (only if needed) 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 (e.g., to connect unrelated devices), stop the container and re-enable the host service:
# Stop the container that owns the adapter docker compose down # Return control to the host sudo systemctl enable bluetooth sudo systemctl start bluetooth sudo rfkill unblock bluetooth sudo hciconfig hci0 up # Or via bluetoothctl: power on
When switching back to the container, repeat the "Give control to the container" snippet above if the host has reclaimed the adapter.
- Adjust Bluetooth addresses
- Edit
chan_mobile.conf(andmobile.conffor compatibility) and set:[adapter] address=to your host’s Bluetooth adapter MAC.[redmi] 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.
- Optional: share host pairings
- If you already paired the phone on the host and want to reuse that, uncomment the bind in
docker-compose.yml:- /var/lib/bluetooth:/var/lib/bluetooth
- Build and run
docker compose builddocker compose up -d
- First-time pairing (container)
- Pair, trust, and connect your phone inside the container using
bluetoothctl:Then verify from Asterisk:docker exec -it asterisk-mobile bash 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
asterisk -rvvvvv mobile show devices # should show Connected: Yes, State: Free
- 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.[redmi] 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=redmimaps 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, and/devpassthrough enable Bluetooth access.- Uncomment
/var/lib/bluetoothbind to reuse host pairings.
Entrypoint: start.sh
- Starts a private system
dbus,bluetoothd --compat, thenasterisk -f -vvv.
Attach to the running Asterisk CLI:
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- Inside container: check
/var/log/asterisk/if enabled bylogger.conf.
If you use Linphone on the host, you can make tel: links dial via Linphone automatically.
- Create a small helper:
- Save
host/linphone-telto~/.local/bin/linphone-teland make it executable:mkdir -p ~/.local/bincp host/linphone-tel ~/.local/bin/linphone-telchmod +x ~/.local/bin/linphone-tel
- Register the desktop handler:
- Copy
host/linphone-tel.desktopto~/.local/share/applications/:mkdir -p ~/.local/share/applicationscp host/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. - Inside container, run
rfkill list,hciconfig -a,dmesg | tail -n 100.
Phone not pairing or connecting
- Use
bluetoothctltotrustandconnectthe phone. - If using host pairings, ensure
/var/lib/bluetoothis bind‑mounted and permissions preserved.
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
- Ensure your Asterisk build includes
chan_mobileon Ubuntu 18.04 package. - If needed, install
asteriskextras or build the module; review 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.
docker-compose.yml— container runtime configurationDockerfile— builds image with BlueZ + Asteriskstart.sh— supervised startup for dbus, bluetoothd, asteriskchan_mobile.conf,mobile.conf— Bluetooth adapter/phone mappingsip.conf— SIP account1001for your softphoneextensions.conf— dialplan for in/out bridgingrtp.conf— RTP port range and ICE/TURN options (many commented)logger.conf— logging setup (console/full/messages)host/linphone-tel,host/linphone-tel.desktop— tel: handler for Linphone
- 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
- Can I avoid pairing in the container?
- Yes, by sharing
/var/lib/bluetoothfrom the host. Ensure the phone is paired/trusted on the host and MACs match your config.
- Yes, by sharing
- 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.