`SmallWebRTCConnection` with Docker
pipecat version
0.0.67
Python version
3.11.5
Operating System
Debian 12 (python:3.11-slim-bookworm)
Question
Hey all, currently playing with SmallWebRTCConnection and SmallWebRTCPrebuiltUI. The examples are working like a charm already.
Can someone tell me how to get the local WebRTC connection working when the server is running inside a Docker container? Establishing a connection to the Docker container was no problem using WebSockets, but with WebRTC the connection seems to be stuck in the connecting state.
What I've tried
No response
Context
No response
@filipi87 maybe you have an idea?
Hit the same issue. Log as below if that helps with debugging:
INFO: 10.0.0.130:64796 - "POST /api/offer HTTP/1.1" 200 OK
2025-05-19 12:56:31.604 | INFO | bot:run_bot:26 - Starting Nova Sonic bot
2025-05-19 12:56:31.605 | INFO | bot:run_bot:30 - New conversation started: 2689fde3-b21a-46db-961b-ea389f1224b6
2025-05-19 12:56:31.605 | DEBUG | pipecat.audio.vad.silero:__init__:111 - Loading Silero VAD model...
2025-05-19 12:56:31.697 | DEBUG | pipecat.audio.vad.silero:__init__:133 - Loaded Silero VAD
2025-05-19 12:56:31.818 | INFO | transcript_handler:__init__:18 - DynamoDB integration enabled with table: nova_sonic_conversations
2025-05-19 12:56:31.819 | DEBUG | pipecat.pipeline.parallel_pipeline:__init__:91 - Creating ParallelPipeline#0 pipelines
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking PipelineSource#0 -> UserTranscriptProcessor#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking UserTranscriptProcessor#0 -> AssistantTranscriptProcessor#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking AssistantTranscriptProcessor#0 -> SmallWebRTCOutputTransport#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking SmallWebRTCOutputTransport#0 -> PipelineSink#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking ParallelPipelineSource#0 -> Pipeline#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking Pipeline#0 -> ParallelPipelineSink#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.pipeline.parallel_pipeline:__init__:108 - Finished creating ParallelPipeline#0 pipelines
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking PipelineSource#1 -> SmallWebRTCInputTransport#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking SmallWebRTCInputTransport#0 -> AWSNovaSonicUserContextAggregator#0
2025-05-19 12:56:31.819 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking AWSNovaSonicUserContextAggregator#0 -> AWSNovaSonicLLMService#0
2025-05-19 12:56:31.820 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking AWSNovaSonicLLMService#0 -> ParallelPipeline#0
2025-05-19 12:56:31.820 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking ParallelPipeline#0 -> AWSNovaSonicAssistantContextAggregator#0
2025-05-19 12:56:31.820 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking AWSNovaSonicAssistantContextAggregator#0 -> PipelineSink#1
2025-05-19 12:56:31.820 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking PipelineTaskSource#0 -> Pipeline#1
2025-05-19 12:56:31.820 | DEBUG | pipecat.processors.frame_processor:link:178 - Linking Pipeline#1 -> PipelineTaskSink#0
2025-05-19 12:56:31.820 | DEBUG | pipecat.pipeline.runner:run:38 - Runner PipelineRunner#0 started running PipelineTask#0
2025-05-19 12:56:31.821 | INFO | pipecat.services.aws_nova_sonic.aws:_start_connecting:302 - Connecting...
2025-05-19 12:56:31.828 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:187 - ICE connection state is checking, connection is connecting
2025-05-19 12:56:31.829 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:313 - Connection state changed to: connecting
2025-05-19 12:56:31.840 | INFO | pipecat.transports.network.small_webrtc:connect:308 - Connecting to Small WebRTC
2025-05-19 12:56:31.841 | INFO | pipecat.audio.vad.vad_analyzer:set_params:74 - Setting VAD params to: confidence=0.7 start_secs=0.2 stop_secs=0.8 min_volume=0.6
2025-05-19 12:56:31.841 | INFO | pipecat.transports.network.small_webrtc:connect:308 - Connecting to Small WebRTC
I get it working with --network=host to expose the UDP ports. Do we know which UDP ports we need to expose, such as-p 3000-3100:3000-3100/udp?
Hi, when you are using --network=host, the container uses the host’s network interfaces directly. So, any UDP or TCP ports opened inside the container are opened on the host network stack itself. And that is why it works.
By default, Docker uses bridge. In this case, you need to map ports in Docker if you want external access.
So, regarding how to limit which UDP ports it is going to use, SmallWebRTCConnection uses aiortc, which uses aioice libraries for ICE transport, and there is an open issue where we are not able to limit the ports:
- https://github.com/aiortc/aioice/issues/47
But for Docker, it looks like there is a workaround: if you define the ephemeral ports that the container is allowed to use, and then only expose those ports that you have allowed. Something like this:
docker run -d \
--sysctl net.ipv4.ip_local_port_range="40000 40100" \
-p 40000-40100:40000-40100/udp \
your-aiortc-image
I haven't tried that myself yet, so if you do, please let me know if it is working as expected.
And another possible approach it is to use your own TURN server, which handles relay of UDP traffic through fixed ports. This way, you only need to expose and open those TURN server ports, simplifying firewall and port management.
Hi, when you are using
--network=host, the container uses the host’s network interfaces directly. So, any UDP or TCP ports opened inside the container are opened on the host network stack itself. And that is why it works.By default, Docker uses
bridge. In this case, you need to map ports in Docker if you want external access.So, regarding how to limit which UDP ports it is going to use,
SmallWebRTCConnectionusesaiortc, which usesaioicelibraries for ICE transport, and there is an open issue where we are not able to limit the ports:But for Docker, it looks like there is a workaround: if you define the ephemeral ports that the container is allowed to use, and then only expose those ports that you have allowed. Something like this:
docker run -d \ --sysctl net.ipv4.ip_local_port_range="40000 40100" \ -p 40000-40100:40000-40100/udp \ your-aiortc-imageI haven't tried that myself yet, so if you do, please let me know if it is working as expected.
And another possible approach it is to use your own TURN server, which handles relay of UDP traffic through fixed ports. This way, you only need to expose and open those TURN server ports, simplifying firewall and port management.
Thanks for your help. Unfortunately neither --network host (I believe this has to do with macOS) nor your proposed port range solution get me any further than the connecting status. With --network host I'm not even able to reach the UI on localhost.
What I've tried:
docker run --rm --network=host -p 8765:8765 -it image_name --> cannot reach localhost
docker run --rm --sysctl net.ipv4.ip_local_port_range="40000 40100" -p 8765:8765 -p 40000-40100:40000-40100/udp -it image_name --> stuck in connecting state
With both commands the logs are showing that Pipecat is starting normally.
Would appreciate any other ideas how to get this working with Docker.
I tried the suggested workarounds but no luck. What is the alternative transport to get this working in a docker container, use DailyTransport?
2025-06-30 16:32:08.528 | DEBUG | pipecat.services.deepgram.stt:_connect:208 - Connecting to Deepgram
2025-06-30 16:32:08.535 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:192 - ICE connection state is checking, connection is connecting
2025-06-30 16:32:08.535 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:322 - Connection state changed to: connecting
2025-06-30 16:32:09.748 | DEBUG | pipecat.services.cartesia.tts:_connect_websocket:286 - Connecting to Cartesia
2025-06-30 16:32:09.980 | INFO | pipecat.transports.network.small_webrtc:connect:306 - Connecting to Small WebRTC
2025-06-30 16:32:09.981 | DEBUG | pipecat.audio.vad.vad_analyzer:set_params:74 - Setting VAD params to: confidence=0.7 start_secs=0.2 stop_secs=0.8 min_volume=0.6
2025-06-30 16:32:09.981 | INFO | pipecat.transports.network.small_webrtc:connect:306 - Connecting to Small WebRTC
2025-06-30 16:32:23.666 | INFO | atproxy.pc.main:offer:114 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-06-30 16:32:23.666 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:244 - Renegotiating SmallWebRTCConnection#0
2025-06-30 16:32:23.666 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:248 - Closing old peer connection
2025-06-30 16:32:23.667 | DEBUG | pipecat.transports.network.small_webrtc:on_disconnected:170 - Peer connection lost.
2025-06-30 16:32:23.667 | DEBUG | pipecat.transports.network.webrtc_connection:_initialize:136 - Initializing new peer connection
2025-06-30 16:32:23.670 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:219 - Creating answer
2025-06-30 16:32:23.671 | DEBUG | pipecat.transports.network.webrtc_connection:on_track:202 - Track audio received
2025-06-30 16:32:23.671 | DEBUG | pipecat.transports.network.webrtc_connection:on_track:202 - Track video received
2025-06-30 16:32:23.671 | DEBUG | pipecat.transports.network.webrtc_connection:on_icegatheringstatechange:198 - ICE gathering state is gathering
2025-06-30 16:32:23.685 | DEBUG | pipecat.transports.network.webrtc_connection:on_icegatheringstatechange:198 - ICE gathering state is complete
2025-06-30 16:32:23.686 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:222 - Setting the answer after the local description is created
INFO: 172.17.0.1:55720 - "POST /api/offer HTTP/1.1" 200 OK
2025-06-30 16:32:23.687 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:192 - ICE connection state is checking, connection is connecting
2025-06-30 16:32:23.687 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:322 - Connection state changed to: connecting
2025-06-30 16:32:39.008 | INFO | atproxy.pc.main:offer:114 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-06-30 16:32:39.009 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:244 - Renegotiating SmallWebRTCConnection#0
2025-06-30 16:32:39.009 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:248 - Closing old peer connection
Hi, If you try to run it outside of the container, directly on the same machine where you're trying to run the container, does it work for you ? If it still doesn't work, there might be a firewall rule blocking the connection.
I'll try to create an example inside Pipecat either this week or next, making it work inside the Docker container. 👍
Hi, If you try to run it outside of the container, directly on the same machine where you're trying to run the container, does it work for you ?
Yes, it works as expected on the host machine but does not get past initiating SmallWebRTCConnection connection when running in the docker container.
Yes, a docker example would be highly desirable. TIA.
Hi all, thank you for bringing this problem to our attention. I am experiencing the same issue which is preventing me to deploy my pipecat-ai-based app. Was there any progress with this? @filipi87, is there any way we can help you and contribute to fixing it? Thanks!
Hi all and @filipi87 , has there been any progress on this? A working Docker solution for SmallWebRTCConnection would still be appreciated.
We're going to be doing some work in the next few weeks to add SmallWebRTC to Pipecat Cloud. In doing so, we'll be running in a Docker container. We'll share our learnings once that activity is finished.
I have created an example, and explained what you need to do to make it work on Linux and on Mac.
All the details are inside the README.
Let me know in case you have any questions.
Thanks so much for your help @filipi87 . On a certain machine I have been able to get the service running using --network host.
Has anyone been able to establish a connection exposing individual ports and not using --network host?
For example with the solution @filipi87 has proposed a la:
# Or, expose individual ports explicitly
docker run --rm \
--sysctl net.ipv4.ip_local_port_range="40000 40100" \
-p 7860:7860 \
-p 40000-40100:40000-40100/udp \
--name small-webrtc-bot \
small-webrtc-bot:latest
This is not working for me and exposing the whole host network stack via --network host is not really an option.. On the machine, where I can establish a connection via --network host, the proposed solution with exposing individual ports is not working:
2025-08-07 09:40:26.663 | INFO | pipecat.transports.network.small_webrtc:connect:connect:405 - Connecting to Small WebRTC
2025-08-07 09:40:26.673 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:on_iceconnectionstatechange:289 - ICE connection state is checking, connection is connecting
2025-08-07 09:40:26.674 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:_handle_new_connection_state:454 - Connection state changed to: connecting
2025-08-07 09:40:37.976 | DEBUG | voice_agent.api.v2.auth:verify_token:61 - Token validation disabled
2025-08-07 09:40:37.978 | INFO | voice_agent.api.v2.webrtc:offer:116 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-08-07 09:40:37.978 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:renegotiate:356 - Renegotiating SmallWebRTCConnection#0
2025-08-07 09:40:37.983 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:317 - Creating answer
2025-08-07 09:40:37.989 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:320 - Setting the answer after the local description is created
2025-08-07 09:40:37.991 | INFO | uvicorn.access:send:476 - 10.0.2.100:40014 - "POST /api/offer HTTP/1.1" 200
2025-08-07 09:40:49.146 | DEBUG | voice_agent.api.v2.auth:verify_token:61 - Token validation disabled
2025-08-07 09:40:49.147 | INFO | voice_agent.api.v2.webrtc:offer:108 - Received offer for pc_id: SmallWebRTCConnection#0
2025-08-07 09:40:49.147 | INFO | voice_agent.api.v2.webrtc:offer:116 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-08-07 09:40:49.148 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:renegotiate:356 - Renegotiating SmallWebRTCConnection#0
2025-08-07 09:40:49.150 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:317 - Creating answer
2025-08-07 09:40:49.152 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:320 - Setting the answer after the local description is created
2025-08-07 09:40:49.153 | INFO | uvicorn.access:send:476 - 10.0.2.100:40068 - "POST /api/offer HTTP/1.1" 200
2025-08-07 09:41:00.388 | INFO | voice_agent.api.v2.webrtc:offer:108 - Received offer for pc_id: SmallWebRTCConnection#0
2025-08-07 09:41:00.390 | INFO | voice_agent.api.v2.webrtc:offer:116 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-08-07 09:41:00.391 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:renegotiate:356 - Renegotiating SmallWebRTCConnection#0
2025-08-07 09:41:00.397 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:317 - Creating answer
2025-08-07 09:41:00.405 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:320 - Setting the answer after the local description is created
2025-08-07 09:41:00.407 | INFO | uvicorn.access:send:476 - 10.0.2.100:40092 - "POST /api/offer HTTP/1.1" 200
2025-08-07 09:41:11.567 | INFO | voice_agent.api.v2.webrtc:offer:108 - Received offer for pc_id: SmallWebRTCConnection#0
2025-08-07 09:41:11.568 | INFO | voice_agent.api.v2.webrtc:offer:116 - Reusing existing connection for pc_id: SmallWebRTCConnection#0
2025-08-07 09:41:11.568 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:renegotiate:356 - Renegotiating SmallWebRTCConnection#0
2025-08-07 09:41:11.571 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:317 - Creating answer
2025-08-07 09:41:11.574 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:_create_answer:320 - Setting the answer after the local description is created
2025-08-07 09:41:11.575 | INFO | uvicorn.access:send:476 - 10.0.2.100:40036 - "POST /api/offer HTTP/1.1" 200
hi all, thanks for all support.
On my macbook I still face some issues despite following the instructions in here.
I am using a remotely hosted coturn server, and it seems to receive the messages with no errors:
(base) ubuntu@ip-172-31-15-190:~$ sudo systemctl status coturn
coturn.service - coTURN STUN/TURN Server
Loaded: loaded (/usr/lib/systemd/system/coturn.service; enabled; preset: enabled)
Active: active (running) since Thu 2025-08-07 10:20:28 EDT; 3min 25s ago
Docs: man:coturn(1)
man:turnadmin(1)
man:turnserver(1)
Main PID: 2836 (turnserver)
Tasks: 9 (limit: 18857)
Memory: 6.4M (peak: 7.2M)
CPU: 186ms
CGroup: /system.slice/coturn.service
└─2836 /usr/bin/turnserver -c /etc/turnserver.conf --pidfile=
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 178: : session 000000000000000004: peer usage: realm=<play.kivaproject.org>, username=<>, rp=80, rb=8000, sp=0, sb=0
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 178: : session 000000000000000004: closed (2nd stage), user <> realm <play.kivaproject.org> origin <>, local 172.31.15.190:3478, remote 73>
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 178: : session 000000000000000004: delete: realm=<play.kivaproject.org>, username=<>
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 202: : session 003000000000000002: refreshed, realm=<play.kivaproject.org>, username=<>, lifetime=0
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 202: : session 003000000000000002: realm <play.kivaproject.org> user <>: incoming packet REFRESH processed, success
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 202: : IPv4. Local relay addr: 172.31.15.190:12215
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 202: : session 002000000000000002: new, realm=<play.kivaproject.org>, username=<>, lifetime=600
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 202: : session 002000000000000002: realm <play.kivaproject.org> user <>: incoming packet ALLOCATE processed, success
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 203: : session 003000000000000002: usage: realm=<play.kivaproject.org>, username=<>, rp=2, rb=64, sp=2, sb=144
Aug 07 10:23:52 ip-172-31-15-190 turnserver[2836]: 203: : session 003000000000000002: peer usage: realm=<play.kivaproject.org>, username=<>, rp=121, rb=12100, sp=0, sb=0
However, from the server logs, I can see the status as "connecting" and not progressing further...
INFO: 172.17.0.1:55986 - "POST /api/offer?session_id=b04b252d-8191-4877-9d09-b55b98009f18__20250807_142300_78b30614 HTTP/1.1" 200 OK
2025-08-07 14:24:54.044 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:289 - ICE connection state is checking, connection is connecting
2025-08-07 14:24:54.044 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:454 - Connection state changed to: connecting
2025-08-07 14:25:14.886 | INFO | __main__:offer:220 - Reusing existing connection for pc_id: SmallWebRTCConnection#2
2025-08-07 14:25:14.887 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:356 - Renegotiating SmallWebRTCConnection#2
2025-08-07 14:25:14.887 | DEBUG | pipecat.transports.network.webrtc_connection:renegotiate:360 - Closing old peer connection
2025-08-07 14:25:14.887 | DEBUG | pipecat.transports.network.small_webrtc:on_disconnected:241 - Peer connection lost.
2025-08-07 14:25:14.946 | DEBUG | pipecat.transports.network.webrtc_connection:_initialize:231 - Initializing new peer connection
2025-08-07 14:25:14.961 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:317 - Creating answer
2025-08-07 14:25:14.963 | DEBUG | pipecat.transports.network.webrtc_connection:on_track:299 - Track audio received
2025-08-07 14:25:14.963 | DEBUG | pipecat.transports.network.webrtc_connection:on_track:299 - Track video received
2025-08-07 14:25:14.965 | DEBUG | pipecat.transports.network.webrtc_connection:on_icegatheringstatechange:295 - ICE gathering state is gathering
2025-08-07 14:25:15.013 | DEBUG | pipecat.transports.network.webrtc_connection:on_icegatheringstatechange:295 - ICE gathering state is complete
2025-08-07 14:25:15.014 | DEBUG | pipecat.transports.network.webrtc_connection:_create_answer:320 - Setting the answer after the local description is created
INFO: 172.17.0.1:52040 - "POST /api/offer?session_id=b04b252d-8191-4877-9d09-b55b98009f18__20250807_142300_78b30614 HTTP/1.1" 200 OK
2025-08-07 14:25:15.016 | DEBUG | pipecat.transports.network.webrtc_connection:on_iceconnectionstatechange:289 - ICE connection state is checking, connection is connecting
2025-08-07 14:25:15.016 | DEBUG | pipecat.transports.network.webrtc_connection:_handle_new_connection_state:454 - Connection state changed to: connecting
@filipi87 when you mentioned some known limitations on Macbook, were you gently suggesting to give up and stop trying? :)
Hi @fabiocat93, for macOS you will need to configure a TURN server on both peers.
If you do that, and wait for ICE candidates to finish gathering like we did in the Docker example, you should be able to see it working.
Are you using JavaScript on the client side, or one of our other SDKs?
Hi @fabiocat93, for macOS you will need to configure a TURN server on both peers.
If you do that, and wait for ICE candidates to finish gathering like we did in the Docker example, you should be able to see it working.
Are you using JavaScript on the client side, or one of our other SDKs?
yup, I use the React library. It works just fine by specifying the ICE servers on both peers. Thank you for your help! @filipi87