[{"data":1,"prerenderedAt":1039},["ShallowReactive",2],{"post-\u002Fblog\u002Frtpengine-deployment-guide":3},{"id":4,"title":5,"author":6,"body":7,"category":1022,"coverImage":1023,"date":1024,"description":1025,"extension":1026,"meta":1027,"navigation":93,"path":1028,"readingTime":147,"seo":1029,"stem":1030,"tags":1031,"__hash__":1038},"posts\u002Fblog\u002Frtpengine-deployment-guide.md","rtpengine Deployment Guide: RTP Proxy at Scale","Tumarm Engineering",{"type":8,"value":9,"toc":1011},"minimark",[10,14,18,23,31,42,46,228,232,373,376,399,403,626,637,641,648,656,659,767,771,774,780,783,799,805,809,812,818,825,832,838,842,903,906,909,962,966,973,998,1004,1007],[11,12,5],"h1",{"id":13},"rtpengine-deployment-guide-rtp-proxy-at-scale",[15,16,17],"p",{},"rtpengine is the RTP proxy of choice for production SIP infrastructure. It replaces the older rtpproxy with kernel-space packet forwarding, SRTP\u002FDTLS support, codec transcoding, and a gRPC\u002Fng control protocol that Kamailio and OpenSIPS integrate natively. At scale — carrier interconnects, WebRTC gateways, SBCs — rtpengine handles tens of thousands of concurrent RTP sessions on commodity hardware. This guide covers installation, kernel module setup, Kamailio integration, and the operational details that documentation skips.",[19,20,22],"h2",{"id":21},"why-rtpengine-over-alternatives","Why rtpengine Over Alternatives",[15,24,25,26,30],{},"The core advantage is the kernel forwarding module (",[27,28,29],"code",{},"xt_RTPENGINE","). When a session is established, rtpengine installs packet forwarding rules directly into the Linux kernel's netfilter framework. Subsequent RTP packets are forwarded in kernel space without a context switch to userspace — effectively wire-speed forwarding at the cost of a single netfilter lookup.",[15,32,33,34,37,38,41],{},"Without the kernel module, rtpengine falls back to userspace forwarding: each RTP packet traverses ",[27,35,36],{},"recvmsg()"," → userspace → ",[27,39,40],{},"sendmsg()",". This is still fast (~1 µs per packet on modern hardware) but limits throughput to roughly 300,000 packets\u002Fsec per core. With the kernel module, a 4-core server forwards over 2 million packets\u002Fsec — enough for 20,000+ concurrent audio sessions.",[19,43,45],{"id":44},"installation","Installation",[47,48,53],"pre",{"className":49,"code":50,"language":51,"meta":52,"style":52},"language-bash shiki shiki-themes github-light github-dark","# Debian \u002F Ubuntu — use the official Sipwise package repo\necho \"deb http:\u002F\u002Fpackages.sipwise.com\u002Fspce bookworm main\" \\\n    > \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fsipwise.list\n\napt-key adv --keyserver keyserver.ubuntu.com --recv-keys 0x... # Sipwise key\napt-get update\napt-get install ngcp-rtpengine\n\n# Or build from source (for custom transcoding codecs)\napt-get install build-essential pkg-config libssl-dev libpcre3-dev \\\n    libjson-glib-dev libcurl4-openssl-dev libxmlrpc-c3-dev libglib2.0-dev\n\ngit clone https:\u002F\u002Fgithub.com\u002Fsipwise\u002Frtpengine.git\ncd rtpengine\nmake\nmake install\n","bash","",[27,54,55,64,78,88,95,120,129,140,145,151,172,187,192,204,213,219],{"__ignoreMap":52},[56,57,60],"span",{"class":58,"line":59},"line",1,[56,61,63],{"class":62},"sJ8bj","# Debian \u002F Ubuntu — use the official Sipwise package repo\n",[56,65,67,71,75],{"class":58,"line":66},2,[56,68,70],{"class":69},"sj4cs","echo",[56,72,74],{"class":73},"sZZnC"," \"deb http:\u002F\u002Fpackages.sipwise.com\u002Fspce bookworm main\"",[56,76,77],{"class":69}," \\\n",[56,79,81,85],{"class":58,"line":80},3,[56,82,84],{"class":83},"szBVR","    >",[56,86,87],{"class":73}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fsipwise.list\n",[56,89,91],{"class":58,"line":90},4,[56,92,94],{"emptyLinePlaceholder":93},true,"\n",[56,96,98,102,105,108,111,114,117],{"class":58,"line":97},5,[56,99,101],{"class":100},"sScJk","apt-key",[56,103,104],{"class":73}," adv",[56,106,107],{"class":69}," --keyserver",[56,109,110],{"class":73}," keyserver.ubuntu.com",[56,112,113],{"class":69}," --recv-keys",[56,115,116],{"class":73}," 0x...",[56,118,119],{"class":62}," # Sipwise key\n",[56,121,123,126],{"class":58,"line":122},6,[56,124,125],{"class":100},"apt-get",[56,127,128],{"class":73}," update\n",[56,130,132,134,137],{"class":58,"line":131},7,[56,133,125],{"class":100},[56,135,136],{"class":73}," install",[56,138,139],{"class":73}," ngcp-rtpengine\n",[56,141,143],{"class":58,"line":142},8,[56,144,94],{"emptyLinePlaceholder":93},[56,146,148],{"class":58,"line":147},9,[56,149,150],{"class":62},"# Or build from source (for custom transcoding codecs)\n",[56,152,154,156,158,161,164,167,170],{"class":58,"line":153},10,[56,155,125],{"class":100},[56,157,136],{"class":73},[56,159,160],{"class":73}," build-essential",[56,162,163],{"class":73}," pkg-config",[56,165,166],{"class":73}," libssl-dev",[56,168,169],{"class":73}," libpcre3-dev",[56,171,77],{"class":69},[56,173,175,178,181,184],{"class":58,"line":174},11,[56,176,177],{"class":73},"    libjson-glib-dev",[56,179,180],{"class":73}," libcurl4-openssl-dev",[56,182,183],{"class":73}," libxmlrpc-c3-dev",[56,185,186],{"class":73}," libglib2.0-dev\n",[56,188,190],{"class":58,"line":189},12,[56,191,94],{"emptyLinePlaceholder":93},[56,193,195,198,201],{"class":58,"line":194},13,[56,196,197],{"class":100},"git",[56,199,200],{"class":73}," clone",[56,202,203],{"class":73}," https:\u002F\u002Fgithub.com\u002Fsipwise\u002Frtpengine.git\n",[56,205,207,210],{"class":58,"line":206},14,[56,208,209],{"class":69},"cd",[56,211,212],{"class":73}," rtpengine\n",[56,214,216],{"class":58,"line":215},15,[56,217,218],{"class":100},"make\n",[56,220,222,225],{"class":58,"line":221},16,[56,223,224],{"class":100},"make",[56,226,227],{"class":73}," install\n",[19,229,231],{"id":230},"kernel-module-setup","Kernel Module Setup",[47,233,235],{"className":49,"code":234,"language":51,"meta":52,"style":52},"# Install kernel headers for your running kernel\napt-get install linux-headers-$(uname -r)\n\n# Build and load the kernel module\ncd rtpengine\u002Fkernel-module\nmake\ninsmod xt_RTPENGINE.ko\n\n# Make it persistent\ncp xt_RTPENGINE.ko \u002Flib\u002Fmodules\u002F$(uname -r)\u002Fkernel\u002Fnet\u002Fnetfilter\u002F\ndepmod -a\necho \"xt_RTPENGINE\" >> \u002Fetc\u002Fmodules\n\n# Verify it loaded\nlsmod | grep xt_RTPENGINE\n# Expected: xt_RTPENGINE    16384  0\n",[27,236,237,242,264,268,273,280,284,292,296,301,324,332,345,349,354,368],{"__ignoreMap":52},[56,238,239],{"class":58,"line":59},[56,240,241],{"class":62},"# Install kernel headers for your running kernel\n",[56,243,244,246,248,251,255,258,261],{"class":58,"line":66},[56,245,125],{"class":100},[56,247,136],{"class":73},[56,249,250],{"class":73}," linux-headers-",[56,252,254],{"class":253},"sVt8B","$(",[56,256,257],{"class":100},"uname",[56,259,260],{"class":69}," -r",[56,262,263],{"class":253},")\n",[56,265,266],{"class":58,"line":80},[56,267,94],{"emptyLinePlaceholder":93},[56,269,270],{"class":58,"line":90},[56,271,272],{"class":62},"# Build and load the kernel module\n",[56,274,275,277],{"class":58,"line":97},[56,276,209],{"class":69},[56,278,279],{"class":73}," rtpengine\u002Fkernel-module\n",[56,281,282],{"class":58,"line":122},[56,283,218],{"class":100},[56,285,286,289],{"class":58,"line":131},[56,287,288],{"class":100},"insmod",[56,290,291],{"class":73}," xt_RTPENGINE.ko\n",[56,293,294],{"class":58,"line":142},[56,295,94],{"emptyLinePlaceholder":93},[56,297,298],{"class":58,"line":147},[56,299,300],{"class":62},"# Make it persistent\n",[56,302,303,306,309,312,314,316,318,321],{"class":58,"line":153},[56,304,305],{"class":100},"cp",[56,307,308],{"class":73}," xt_RTPENGINE.ko",[56,310,311],{"class":73}," \u002Flib\u002Fmodules\u002F",[56,313,254],{"class":253},[56,315,257],{"class":100},[56,317,260],{"class":69},[56,319,320],{"class":253},")",[56,322,323],{"class":73},"\u002Fkernel\u002Fnet\u002Fnetfilter\u002F\n",[56,325,326,329],{"class":58,"line":174},[56,327,328],{"class":100},"depmod",[56,330,331],{"class":69}," -a\n",[56,333,334,336,339,342],{"class":58,"line":189},[56,335,70],{"class":69},[56,337,338],{"class":73}," \"xt_RTPENGINE\"",[56,340,341],{"class":83}," >>",[56,343,344],{"class":73}," \u002Fetc\u002Fmodules\n",[56,346,347],{"class":58,"line":194},[56,348,94],{"emptyLinePlaceholder":93},[56,350,351],{"class":58,"line":206},[56,352,353],{"class":62},"# Verify it loaded\n",[56,355,356,359,362,365],{"class":58,"line":215},[56,357,358],{"class":100},"lsmod",[56,360,361],{"class":83}," |",[56,363,364],{"class":100}," grep",[56,366,367],{"class":73}," xt_RTPENGINE\n",[56,369,370],{"class":58,"line":221},[56,371,372],{"class":62},"# Expected: xt_RTPENGINE    16384  0\n",[15,374,375],{},"Verify kernel forwarding is active after rtpengine starts:",[47,377,379],{"className":49,"code":378,"language":51,"meta":52,"style":52},"cat \u002Fproc\u002Frtpengine\u002F0\u002Flist\n# Should show active kernel-forwarded sessions\n# Empty = kernel module not loaded, falling back to userspace\n",[27,380,381,389,394],{"__ignoreMap":52},[56,382,383,386],{"class":58,"line":59},[56,384,385],{"class":100},"cat",[56,387,388],{"class":73}," \u002Fproc\u002Frtpengine\u002F0\u002Flist\n",[56,390,391],{"class":58,"line":66},[56,392,393],{"class":62},"# Should show active kernel-forwarded sessions\n",[56,395,396],{"class":58,"line":80},[56,397,398],{"class":62},"# Empty = kernel module not loaded, falling back to userspace\n",[19,400,402],{"id":401},"configuration-file","Configuration File",[47,404,408],{"className":405,"code":406,"language":407,"meta":52,"style":52},"language-ini shiki shiki-themes github-light github-dark","# \u002Fetc\u002Frtpengine\u002Frtpengine.conf\n[rtpengine]\n# Network\ninterface = eth0\u002F203.0.113.10\nlisten-ng = 127.0.0.1:2223\nlisten-tcp-ng = 127.0.0.1:2223\n\n# Port range for RTP relay\nport-min = 30000\nport-max = 40000\n\n# DTLS\u002FSRTP\ndtls-passive = yes\ntls-certificate = \u002Fetc\u002Fssl\u002Fcerts\u002Frtpengine.pem\ntls-private-key = \u002Fetc\u002Fssl\u002Fprivate\u002Frtpengine.key\n\n# Kernel forwarding (0 = use kernel module if available)\ntable = 0\n\n# Logging\nlog-level = 5\nlog-facility = daemon\nlog-facility-rtcp = local0\n\n# Performance\ntimeout = 60\nsilent-timeout = 3600\ntos = 184                    # DSCP EF (0xB8) for RTP traffic\n\n# Transcoding (requires ffmpeg libraries)\n# codec-except = PCMU        # Uncomment to disable specific codecs\n\n# Prometheus\nprometheus = yes\nprometheus-listen = 127.0.0.1:9900\n\n# Homer SIPcapture\nhomer-ng = udp:127.0.0.1:9060\nhomer-protocol = 17\nhomer-id = 2002\n","ini",[27,409,410,415,420,425,430,435,440,444,449,454,459,463,468,473,478,483,487,493,499,504,510,516,522,528,533,539,545,551,557,562,568,574,579,585,591,597,602,608,614,620],{"__ignoreMap":52},[56,411,412],{"class":58,"line":59},[56,413,414],{},"# \u002Fetc\u002Frtpengine\u002Frtpengine.conf\n",[56,416,417],{"class":58,"line":66},[56,418,419],{},"[rtpengine]\n",[56,421,422],{"class":58,"line":80},[56,423,424],{},"# Network\n",[56,426,427],{"class":58,"line":90},[56,428,429],{},"interface = eth0\u002F203.0.113.10\n",[56,431,432],{"class":58,"line":97},[56,433,434],{},"listen-ng = 127.0.0.1:2223\n",[56,436,437],{"class":58,"line":122},[56,438,439],{},"listen-tcp-ng = 127.0.0.1:2223\n",[56,441,442],{"class":58,"line":131},[56,443,94],{"emptyLinePlaceholder":93},[56,445,446],{"class":58,"line":142},[56,447,448],{},"# Port range for RTP relay\n",[56,450,451],{"class":58,"line":147},[56,452,453],{},"port-min = 30000\n",[56,455,456],{"class":58,"line":153},[56,457,458],{},"port-max = 40000\n",[56,460,461],{"class":58,"line":174},[56,462,94],{"emptyLinePlaceholder":93},[56,464,465],{"class":58,"line":189},[56,466,467],{},"# DTLS\u002FSRTP\n",[56,469,470],{"class":58,"line":194},[56,471,472],{},"dtls-passive = yes\n",[56,474,475],{"class":58,"line":206},[56,476,477],{},"tls-certificate = \u002Fetc\u002Fssl\u002Fcerts\u002Frtpengine.pem\n",[56,479,480],{"class":58,"line":215},[56,481,482],{},"tls-private-key = \u002Fetc\u002Fssl\u002Fprivate\u002Frtpengine.key\n",[56,484,485],{"class":58,"line":221},[56,486,94],{"emptyLinePlaceholder":93},[56,488,490],{"class":58,"line":489},17,[56,491,492],{},"# Kernel forwarding (0 = use kernel module if available)\n",[56,494,496],{"class":58,"line":495},18,[56,497,498],{},"table = 0\n",[56,500,502],{"class":58,"line":501},19,[56,503,94],{"emptyLinePlaceholder":93},[56,505,507],{"class":58,"line":506},20,[56,508,509],{},"# Logging\n",[56,511,513],{"class":58,"line":512},21,[56,514,515],{},"log-level = 5\n",[56,517,519],{"class":58,"line":518},22,[56,520,521],{},"log-facility = daemon\n",[56,523,525],{"class":58,"line":524},23,[56,526,527],{},"log-facility-rtcp = local0\n",[56,529,531],{"class":58,"line":530},24,[56,532,94],{"emptyLinePlaceholder":93},[56,534,536],{"class":58,"line":535},25,[56,537,538],{},"# Performance\n",[56,540,542],{"class":58,"line":541},26,[56,543,544],{},"timeout = 60\n",[56,546,548],{"class":58,"line":547},27,[56,549,550],{},"silent-timeout = 3600\n",[56,552,554],{"class":58,"line":553},28,[56,555,556],{},"tos = 184                    # DSCP EF (0xB8) for RTP traffic\n",[56,558,560],{"class":58,"line":559},29,[56,561,94],{"emptyLinePlaceholder":93},[56,563,565],{"class":58,"line":564},30,[56,566,567],{},"# Transcoding (requires ffmpeg libraries)\n",[56,569,571],{"class":58,"line":570},31,[56,572,573],{},"# codec-except = PCMU        # Uncomment to disable specific codecs\n",[56,575,577],{"class":58,"line":576},32,[56,578,94],{"emptyLinePlaceholder":93},[56,580,582],{"class":58,"line":581},33,[56,583,584],{},"# Prometheus\n",[56,586,588],{"class":58,"line":587},34,[56,589,590],{},"prometheus = yes\n",[56,592,594],{"class":58,"line":593},35,[56,595,596],{},"prometheus-listen = 127.0.0.1:9900\n",[56,598,600],{"class":58,"line":599},36,[56,601,94],{"emptyLinePlaceholder":93},[56,603,605],{"class":58,"line":604},37,[56,606,607],{},"# Homer SIPcapture\n",[56,609,611],{"class":58,"line":610},38,[56,612,613],{},"homer-ng = udp:127.0.0.1:9060\n",[56,615,617],{"class":58,"line":616},39,[56,618,619],{},"homer-protocol = 17\n",[56,621,623],{"class":58,"line":622},40,[56,624,625],{},"homer-id = 2002\n",[15,627,628,629,632,633,636],{},"The ",[27,630,631],{},"interface"," parameter format ",[27,634,635],{},"physical-interface\u002Fpublic-ip"," is critical for NAT traversal. rtpengine binds on the physical interface IP but advertises the public IP in SDP rewriting. Get this wrong and media flows to unreachable addresses.",[19,638,640],{"id":639},"kamailio-integration","Kamailio Integration",[15,642,643,644,647],{},"Kamailio controls rtpengine via the ",[27,645,646],{},"rtpengine"," module using the ng control protocol:",[47,649,654],{"className":650,"code":652,"language":653},[651],"language-text","loadmodule \"rtpengine.so\"\n\nmodparam(\"rtpengine\", \"rtpengine_sock\", \"udp:127.0.0.1:2223\")\nmodparam(\"rtpengine\", \"rtpengine_disable_tout\", 20)\nmodparam(\"rtpengine\", \"rtpengine_retr\", 5)\nmodparam(\"rtpengine\", \"rtpengine_tout_ms\", 1000)\n\n# For multiple rtpengine instances:\n# modparam(\"rtpengine\", \"rtpengine_sock\", \"udp:10.0.1.10:2223 udp:10.0.1.11:2223\")\n\nrequest_route {\n    if (is_method(\"INVITE\")) {\n        if (has_body(\"application\u002Fsdp\")) {\n            # Offer — rewrite SDP to proxy through rtpengine\n            rtpengine_offer(\"trust-address replace-origin replace-session-connection\");\n        }\n    }\n    \n    if (is_method(\"BYE\") || is_method(\"CANCEL\")) {\n        rtpengine_delete();\n    }\n    \n    t_relay();\n}\n\nonreply_route {\n    if (t_check_status(\"18[0-9]\") || t_check_status(\"2[0-9][0-9]\")) {\n        if (has_body(\"application\u002Fsdp\")) {\n            # Answer — complete the SDP rewrite\n            rtpengine_answer(\"trust-address replace-origin replace-session-connection\");\n        }\n    }\n}\n","text",[27,655,652],{"__ignoreMap":52},[15,657,658],{},"The flags string controls rtpengine behavior:",[660,661,662,675],"table",{},[663,664,665],"thead",{},[666,667,668,672],"tr",{},[669,670,671],"th",{},"Flag",[669,673,674],{},"Effect",[676,677,678,689,703,717,727,737,747,757],"tbody",{},[666,679,680,686],{},[681,682,683],"td",{},[27,684,685],{},"trust-address",[681,687,688],{},"Trust the SDP connection address (don't override with signaling source IP)",[666,690,691,696],{},[681,692,693],{},[27,694,695],{},"replace-origin",[681,697,698,699,702],{},"Rewrite the SDP ",[27,700,701],{},"o="," line with rtpengine's address",[666,704,705,710],{},[681,706,707],{},[27,708,709],{},"replace-session-connection",[681,711,712,713,716],{},"Rewrite the session-level ",[27,714,715],{},"c="," line",[666,718,719,724],{},[681,720,721],{},[27,722,723],{},"ICE=remove",[681,725,726],{},"Strip ICE candidates (for SIP-to-SIP, not WebRTC)",[666,728,729,734],{},[681,730,731],{},[27,732,733],{},"DTLS=passive",[681,735,736],{},"Force DTLS passive mode (for WebRTC endpoints)",[666,738,739,744],{},[681,740,741],{},[27,742,743],{},"SRTP",[681,745,746],{},"Enable SRTP for this leg",[666,748,749,754],{},[681,750,751],{},[27,752,753],{},"transcode-PCMU",[681,755,756],{},"Transcode to PCMU if needed",[666,758,759,764],{},[681,760,761],{},[27,762,763],{},"record-call=yes",[681,765,766],{},"Enable call recording for this session",[19,768,770],{"id":769},"srtp-transcoding-plain-sip-to-webrtc","SRTP Transcoding: Plain SIP to WebRTC",[15,772,773],{},"The most common rtpengine use case is bridging plain SIP (with plain RTP) to WebRTC (which requires SRTP\u002FDTLS). rtpengine handles the SRTP key exchange and media encryption transparently:",[47,775,778],{"className":776,"code":777,"language":653},[651],"# For the WebRTC leg (DTLS-SRTP required)\nrtpengine_offer(\"ICE=force DTLS=passive SDES-off\");\n\n# For the SIP leg (plain RTP)\nrtpengine_answer(\"ICE=remove DTLS=off SDES-off\");\n",[27,779,777],{"__ignoreMap":52},[15,781,782],{},"With this configuration, rtpengine:",[784,785,786,790,793,796],"ol",{},[787,788,789],"li",{},"Receives DTLS from the WebRTC client and negotiates SRTP keys",[787,791,792],{},"Decrypts SRTP from the WebRTC client",[787,794,795],{},"Forwards plain RTP to the SIP endpoint",[787,797,798],{},"Encrypts in the reverse direction",[15,800,801,802,804],{},"This all happens in userspace (DTLS negotiation cannot be kernel-forwarded), but once the session is established and ",[27,803,29],{}," takes over, subsequent packets bypass userspace.",[19,806,808],{"id":807},"multi-instance-clustering","Multi-Instance Clustering",[15,810,811],{},"For high-availability and horizontal scaling, run multiple rtpengine instances and let Kamailio distribute sessions:",[47,813,816],{"className":814,"code":815,"language":653},[651],"modparam(\"rtpengine\", \"rtpengine_sock\",\n    \"udp:10.0.1.10:2223 udp:10.0.1.11:2223 udp:10.0.1.12:2223\")\n\nmodparam(\"rtpengine\", \"rtpengine_disable_tout\", 20)\n",[27,817,815],{"__ignoreMap":52},[15,819,820,821,824],{},"Kamailio's rtpengine module does round-robin across healthy instances. If an instance stops responding, Kamailio marks it disabled and routes to the remaining instances after ",[27,822,823],{},"rtpengine_disable_tout"," seconds.",[15,826,827,828,831],{},"In-dialog requests (re-INVITE, UPDATE) must reach the same rtpengine instance that handled the original INVITE. Kamailio tracks this via the ",[27,829,830],{},"rtpengine_manage()"," function which reads the stored instance from the dialog:",[47,833,836],{"className":834,"code":835,"language":653},[651],"# Use rtpengine_manage() for in-dialog requests\n# It automatically selects the correct instance\nif (has_totag()) {\n    if (is_method(\"INVITE|UPDATE|ACK\")) {\n        rtpengine_manage(\"trust-address replace-origin\");\n    }\n}\n",[27,837,835],{"__ignoreMap":52},[19,839,841],{"id":840},"capacity-planning","Capacity Planning",[660,843,844,857],{},[663,845,846],{},[666,847,848,851,854],{},[669,849,850],{},"Configuration",[669,852,853],{},"Concurrent sessions",[669,855,856],{},"Packet rate",[676,858,859,870,881,892],{},[666,860,861,864,867],{},[681,862,863],{},"Userspace only, 1 core",[681,865,866],{},"~5,000",[681,868,869],{},"~300K pps",[666,871,872,875,878],{},[681,873,874],{},"Kernel module, 1 core",[681,876,877],{},"~15,000",[681,879,880],{},"~1M pps",[666,882,883,886,889],{},[681,884,885],{},"Kernel module, 4 cores",[681,887,888],{},"~50,000",[681,890,891],{},"~3M pps",[666,893,894,897,900],{},[681,895,896],{},"Kernel module, 16 cores",[681,898,899],{},"~100,000+",[681,901,902],{},"~8M pps",[15,904,905],{},"Memory is minimal: ~1 KB per session for the kernel forwarding table, ~50 KB per session for the userspace session record. A server with 16 GB RAM handles 100,000 concurrent sessions with memory to spare.",[15,907,908],{},"Bandwidth is the real constraint. Each audio session consumes ~100 Kbps bidirectional (G.711 \u002F PCMU). 10,000 sessions = 1 Gbps throughput. Size your NIC and carrier bandwidth accordingly:",[47,910,912],{"className":49,"code":911,"language":51,"meta":52,"style":52},"# Check current throughput\ncat \u002Fproc\u002Frtpengine\u002F0\u002Fstats | grep bytes_forwarded\n# Or via Prometheus: rtpengine_total_traffic_bytes\n\n# Check kernel forwarding table size\ncat \u002Fproc\u002Frtpengine\u002F0\u002Flist | wc -l\n",[27,913,914,919,933,938,942,947],{"__ignoreMap":52},[56,915,916],{"class":58,"line":59},[56,917,918],{"class":62},"# Check current throughput\n",[56,920,921,923,926,928,930],{"class":58,"line":66},[56,922,385],{"class":100},[56,924,925],{"class":73}," \u002Fproc\u002Frtpengine\u002F0\u002Fstats",[56,927,361],{"class":83},[56,929,364],{"class":100},[56,931,932],{"class":73}," bytes_forwarded\n",[56,934,935],{"class":58,"line":80},[56,936,937],{"class":62},"# Or via Prometheus: rtpengine_total_traffic_bytes\n",[56,939,940],{"class":58,"line":90},[56,941,94],{"emptyLinePlaceholder":93},[56,943,944],{"class":58,"line":97},[56,945,946],{"class":62},"# Check kernel forwarding table size\n",[56,948,949,951,954,956,959],{"class":58,"line":122},[56,950,385],{"class":100},[56,952,953],{"class":73}," \u002Fproc\u002Frtpengine\u002F0\u002Flist",[56,955,361],{"class":83},[56,957,958],{"class":100}," wc",[56,960,961],{"class":69}," -l\n",[19,963,965],{"id":964},"call-recording-via-rtpengine","Call Recording via rtpengine",[15,967,968,969,972],{},"rtpengine supports inline call recording via the ",[27,970,971],{},"record-call"," flag. Recordings go to a local directory as PCAP files:",[47,974,976],{"className":405,"code":975,"language":407,"meta":52,"style":52},"# rtpengine.conf\nrecording-dir = \u002Fvar\u002Fspool\u002Frtpengine-recordings\nrecording-method = pcap\nrecording-format = eth\n",[27,977,978,983,988,993],{"__ignoreMap":52},[56,979,980],{"class":58,"line":59},[56,981,982],{},"# rtpengine.conf\n",[56,984,985],{"class":58,"line":66},[56,986,987],{},"recording-dir = \u002Fvar\u002Fspool\u002Frtpengine-recordings\n",[56,989,990],{"class":58,"line":80},[56,991,992],{},"recording-method = pcap\n",[56,994,995],{"class":58,"line":90},[56,996,997],{},"recording-format = eth\n",[47,999,1002],{"className":1000,"code":1001,"language":653},[651],"# Kamailio: enable recording for specific calls\nif ($avp(record_call) == \"yes\") {\n    rtpengine_offer(\"trust-address replace-origin record-call=yes\");\n} else {\n    rtpengine_offer(\"trust-address replace-origin record-call=no\");\n}\n",[27,1003,1001],{"__ignoreMap":52},[15,1005,1006],{},"PCAP recordings include all RTP\u002FRTCP packets. Import them into Wireshark with Telephony > VoIP Calls for playback and quality analysis. At scale, stream recordings directly to S3 using rtpengine's S3 output mode (available in enterprise builds) rather than accumulating PCAP files on the local filesystem.",[1008,1009,1010],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":52,"searchDepth":66,"depth":66,"links":1012},[1013,1014,1015,1016,1017,1018,1019,1020,1021],{"id":21,"depth":66,"text":22},{"id":44,"depth":66,"text":45},{"id":230,"depth":66,"text":231},{"id":401,"depth":66,"text":402},{"id":639,"depth":66,"text":640},{"id":769,"depth":66,"text":770},{"id":807,"depth":66,"text":808},{"id":840,"depth":66,"text":841},{"id":964,"depth":66,"text":965},"SBC","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1558494949-ef010cbdcc31?w=1200&q=80","2026-03-01","Deploy rtpengine as a high-performance RTP proxy: kernel forwarding module, Kamailio integration, SRTP transcoding, multi-instance clustering, and capacity planning.","md",{},"\u002Fblog\u002Frtpengine-deployment-guide",{"title":5,"description":1025},"blog\u002Frtpengine-deployment-guide",[646,1032,1033,1034,1035,1036,1037],"rtp-proxy","sbc","srtp","kamailio","media-proxy","nat-traversal","wHYzAzP3MgaoxMqqw7j2Lyp433riL0OWI-4nsrc710Q",1776964996446]