Repository navigation
Use Kamailio as the SIP Server
Kamailio is an open-source SIP server. With OpenSIPS, it is one of the two most common SIP proxies in front of phones, PBXes and carriers. The two share their origins. A routing script written for one reads much like one written for the other.
The other voice-stack guides use OpenSIPS. This guide sets up Kamailio in the same role:
- as a proxy that routes each call and stays in its signaling path,
- proved with a test call.
This guide does not use sipnab. When you have this working, Run sipnab beside Kamailio adds sipnab.
Every block on this page ran as written on 2026-10-01.
- The machines were clean x86_64 virtual machines with 2 cores and 3 GB of
memory:
- Debian 13 (kernel 6.12.63),
- Ubuntu 24.04 (kernel 6.8.0).
- On each, the install ran on the machine the OpenSIPS guide had used for its source build and then its uninstall. No SIP server was running.
- OpenSIPS and Kamailio on one machine ran on both, with OpenSIPS from the packages on 5060. Then the uninstall ran on both.
- Every test call carried audio both ways, counted on the wire.
- Causing each fault under When something does not work produced what it describes, on both.
| Software | Version |
|---|---|
| Kamailio | 6.1.4, from the Kamailio project's own package repository |
| SIPp (for the test call) | the distribution's sip-tester: 3.7.3 on Debian 13, 3.7.2 on Ubuntu 24.04 |
The examples use 192.0.2.10 as the machine's address. Replace it with yours
everywhere it appears.
The distributions carry older Kamailio releases. The Kamailio project publishes current ones for Debian and Ubuntu, one repository per release series. Add the 6.1 series and install:
# Run all of these, in order.
sudo apt-get update
sudo apt-get install -y ca-certificates curl gpg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://deb.kamailio.org/kamailiodebkey.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kamailio.gpg
gpg --show-keys /etc/apt/keyrings/kamailio.gpg | grep -A1 '^pub'
. /etc/os-release
echo "deb [signed-by=/etc/apt/keyrings/kamailio.gpg] https://deb.kamailio.org/kamailio61 $VERSION_CODENAME main" \
| sudo tee /etc/apt/sources.list.d/kamailio.list >/dev/null
sudo apt-get update
printf '#!/bin/sh\nexit 101\n' | sudo tee /usr/sbin/policy-rc.d >/dev/null
sudo chmod 755 /usr/sbin/policy-rc.d
sudo apt-get install -y kamailio
sudo rm /usr/sbin/policy-rc.d
/usr/sbin/kamailio -v | head -1gpg --show-keys prints the key's fingerprint. It is
E79ACECB87D8DCD23A20AD2FFB40D3E6508EA4C8, the Kamailio Package Team's.
The Kamailio package starts Kamailio the moment it installs. It uses its sample configuration, which listens on port 5060 of every address.
- The
policy-rc.dfile around the install is Debian's way to tell a package not to start its service. - The block removes it straight after.
- Kamailio stays stopped until the next step has given it your configuration.
That matters most on a machine already running a SIP server on 5060, such as OpenSIPS.
- Two SIP servers on one UDP port do not refuse each other. The one that starts last silently receives all of that port's traffic.
- A measurement with OpenSIPS running showed this. Kamailio's sample configuration answered every request sent to 5060 the moment the package started it.
This configuration is a minimal proxy:
- it routes every call to one destination,
- it stays in the path of the call's later requests.
Your own script does much more (registration, authentication, routing to carriers).
If OpenSIPS already runs on this machine, change 5060 to 5062 in two
places, as
OpenSIPS and Kamailio on one machine
explains:
- in the
listenline, before you run this block, - in the caller's
192.0.2.10:5060in the Place a test call step.
Otherwise the Place a test call step's call reaches OpenSIPS, and tests it instead.
# Run all of these, in order.
sudo tee /etc/kamailio/kamailio.cfg >/dev/null <<'EOF'
#!KAMAILIO
# Kamailio as a SIP proxy that stays in the path of every call.
debug=2
log_stderror=no
log_facility=LOG_LOCAL0
children=2
listen=udp:192.0.2.10:5060 # the address your phones and carriers reach
loadmodule "tm.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "siputils.so"
loadmodule "textops.so"
loadmodule "pv.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "ctl.so"
request_route {
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483", "Too Many Hops");
exit;
}
if (has_totag()) {
if (loose_route()) {
t_relay();
exit;
}
if (is_method("ACK") && t_check_trans()) {
t_relay();
}
exit;
}
if (is_method("CANCEL")) {
if (t_check_trans()) {
t_relay();
}
exit;
}
t_check_trans();
if (!is_method("INVITE")) {
sl_send_reply("405", "Method Not Allowed");
exit;
}
record_route();
# Where the call goes. Here, a test callee on this machine; in your
# stack, lookup("location"), dispatcher or a carrier.
$du = "sip:127.0.0.1:5070";
t_relay();
}
EOF
sudo kamailio -c -f /etc/kamailio/kamailio.cfg
sudo systemctl enable kamailio
sudo systemctl restart kamailio
systemctl is-active kamailioWhat the parts do:
-
record_route()adds aRecord-Routeheader naming Kamailio. So the call's later requests, theACKand theBYE, come back through it. -
loose_route()routes those later requests along the recorded route. -
t_relay()forwards the request and handles retransmissions and replies. -
ctl.sois what letskamcmdtalk to the running Kamailio.
kamailio -c checks the configuration before anything starts.
SIPp plays both ends:
- a callee on this machine that echoes audio back,
- a caller that dials through Kamailio and plays a recorded G.711 sample.
So the call carries real audio both ways.
- SIPp's built-in caller ignores the
Record-Routeheader. So Kamailio cannot route itsACKandBYE. - The two route
sedlines make it honor the route set, the way a real phone does. - The callee writes what it receives to
uas.msg:
# Run all of these, in order.
sudo apt-get install -y sip-tester
mkdir -p ~/sipp/pcap && cd ~/sipp
ln -sf /usr/share/sip-tester/*.pcap pcap/
sipp -sd uac_pcap > uac_rr.xml
sed -i 's|<recv response="200" rtd="true" crlf="true">|<recv response="200" rtd="true" crlf="true" rrs="true">|' uac_rr.xml
sed -i -E 's#^( *)(ACK|BYE) sip:\[service\]@\[remote_ip\]:\[remote_port\] SIP/2.0#\1\2 [next_url] SIP/2.0\n\1[routes]#' uac_rr.xml
sipp -sn uas -i 127.0.0.1 -p 5070 -rtp_echo -m 1 -trace_msg -message_file uas.msg -bg
sudo sipp -sf uac_rr.xml 192.0.2.10:5060 -i 192.0.2.10 -p 5080 -s echo -m 1 -timeout 90s
awk '/INVITE sip:/{f=1} f' uas.msg | grep -m1 -i '^Record-Route:'The caller needs sudo because it plays the audio sample through a raw socket.
- It sends about 7 seconds of audio, then a short DTMF clip, and hangs up.
- At the end, SIPp's statistics screen shows
Successful callat 1. - The last line prints the
Record-RouteKamailio added, such as<sip:192.0.2.10;lr;ftag=52680SIPpTag091>. It holds:- Kamailio's address,
-
lrfor loose routing, - the caller's
Fromtag.
Kamailio carries the signaling only. The audio goes straight between the two ends, at the addresses and ports their SDP names. So this proxy never touches it.
- Run sipnab beside Kamailio shows both directions of it.
- rtpengine puts a media relay in its path.
See what Kamailio has handled. kamcmd asks the running Kamailio. Name a
statistic, or a group with a trailing colon. The core: group holds the
counts of requests received and replies relayed:
# Run all of these, in order.
sudo kamcmd stats.get_statistics rcv_requests_invite
sudo kamcmd stats.get_statistics core: | grep -E 'rcv_(requests|replies_2xx)_invite'After the test call, rcv_requests_invite is 1. So is
rcv_replies_2xx_invite, the callee's 200 OK.
Check health and read the logs.
# Run all of these, in order.
systemctl is-active kamailio
sudo kamcmd core.uptime
sudo journalctl -u kamailio -n 30Apply a configuration change. Check it first, then restart:
# Run all of these, in order.
sudo kamailio -c -f /etc/kamailio/kamailio.cfg
sudo systemctl restart kamailioUninstall.
# Run all of these, in order.
sudo systemctl disable --now kamailio
sudo apt-get purge -y kamailio
sudo rm /etc/apt/sources.list.d/kamailio.list /etc/apt/keyrings/kamailio.gpgDevelopers often run both, to compare them or to test against each. They can share a machine as long as they do not share a port.
- A shared port does not fail loudly. Whichever server starts last silently takes all of its traffic.
- Keep OpenSIPS on 5060, as the OpenSIPS guide sets it up.
- Keep Kamailio on 5062.
- If you set Kamailio up on 5060 first, move it before OpenSIPS starts:
# Run all of these, in order.
sudo sed -i 's|^listen=udp:192.0.2.10:5060 |listen=udp:192.0.2.10:5062 |' /etc/kamailio/kamailio.cfg
grep '^listen=' /etc/kamailio/kamailio.cfg
sudo kamailio -c -f /etc/kamailio/kamailio.cfg
sudo systemctl restart kamailioA test call now reaches Kamailio on 5062 and OpenSIPS on 5060. Place one
through each, from ~/sipp, with the callee from the Place a test call step
running:
# Run all of these, in order.
cd ~/sipp
sipp -sn uas -i 127.0.0.1 -p 5070 -rtp_echo -m 2 -bg
sudo sipp -sf uac_rr.xml 192.0.2.10:5062 -i 192.0.2.10 -p 5080 -s echo -m 1 -timeout 90s
sudo sipp -sf uac_rr.xml 192.0.2.10:5060 -i 192.0.2.10 -p 5080 -s echo -m 1 -timeout 90sEach shows Successful call at 1. sipnab watches ports 5060-5061 by default.
So give it both proxies' ports: --portrange 5060-5062.
The other guides use OpenSIPS. Each has a section that says what changes with Kamailio:
-
rtpengine: Kamailio's
rtpenginemodule. -
rtpproxy: Kamailio's
rtpproxymodule. -
Homer: Kamailio's
siptracemodule sends HEP. -
Prometheus: Kamailio's
xhttp_prommodule. - TFPS: nothing changes. TFPS needs nothing from the SIP server.
- vCon server: a gap. Kamailio has no SIPREC module, so it cannot record calls for the vCon server. sipnab's own vCons are what a Kamailio stack can send it.
-
apt-getsaysCould not get lock /var/lib/dpkg/lock-frontend. It is held by process ....- Another package tool holds the lock. On a machine that has just booted, this is usually the system's own scheduled update.
- Wait for it to finish, then run the block again.
-
kamailio -creportsparse error in config fileandunknown command, missing loadmodule?.- The script calls a function whose module is not loaded.
- The error names the line and column.
- The line before it names the function, such as
failed to find command is_method. - Load the module that provides it.
-
kamcmdsaysconnect(//var/run/kamailio/kamailio_ctl): No such file or directory. Kamailio is not running, orctl.sois not loaded. -
The test call's
BYEgets no answer.- The caller ignored the route set. So Kamailio dropped its
ACKandBYE. - SIPp can still report the call as successful:
- the callee, which never got the
ACK, sends its200 OKagain, - SIPp takes one of those for the
BYE's answer.
- the callee, which never got the
- Use the edited
uac_rr.xml, not SIPp's built-inuac_pcap.
- The caller ignored the route set. So Kamailio dropped its
Website · Repository · Issues · Generated from docs/ — edit there, not here.
Getting started
- Installation
- First CLI Triage
- Glossary
- Cookbook
- Runnable Examples
- Real World Captures
- Troubleshooting
- Tuning Capture
- Encapsulations
- Rtpengine Relays
- Backers
Using the TUI
CLI & automation
- CLI Reference
- Error Messages
- Filter DSL
- Output Formats
- SIP Response Codes
- SIP Methods
- SIP Header Fields
- SIP Parameters
- SIP Lint Rules
- MOS and Codecs
Configuration
Integrations (API & MCP)
- REST API
- Prometheus Metrics
- Authentication
- MCP
- MCP Deployment
- MCP Across an Estate
- MCP Tools
- MCP Tools Core
- MCP Tools Signaling
- MCP Tools Captures
- MCP Tools Security
- MCP Tools Media
- MCP Tools Relay
- MCP Tools TFPS
- MCP Tools Server
- MCP Tools vCon
- MCP Tools TLS
- MCP Protocol
- Uprobe Walkthrough
- Capture SIP over TLS
- WASM Plugins
- vCon Export
- vCon Capture Stack
- G729 Decoding
Your SIP server
- Use OpenSIPS as the SIP Server
- Run sipnab beside OpenSIPS
- Use Kamailio as the SIP Server
- Run sipnab beside Kamailio
- Use Asterisk as the PBX
- Run sipnab beside Asterisk
- Use FreeSWITCH in the Voice Stack
- Run sipnab beside FreeSWITCH
Add to your voice stack
- Add a vCon Server
- Send vCons to a vCon Server
- Send vCons to vcon store
- Add TFPS
- Control TFPS from sipnab
- Ban SIP Scanners with fail2ban
- Feed fail2ban from sipnab
- Add rtpengine
- Name rtpengine Media with sipnab
- Add rtpproxy
- Name rtpproxy Media with sipnab
- Add Homer
- Connect sipnab to Homer
- Add Prometheus and Grafana
- Add sipnab Metrics to Prometheus
Development & internals
- Internals Index
- Internals Subsystem Guide
- Internals Invariants
- Internals Testing
- Internals Walkthroughs
- Internals Build CI Release
- Internals Profiling
- Internals Domain Primer
- Library API
- Benchmarks
- Fault Model
- Threat Model
- Assurance Case
- Architecture
- Internals Threading
- Internals TUI Testing
- Internals Zero Copy Payloads
- Internals Uprobe Capture
- Internals Rtpengine Control Plane
- Internals Relay Control Decoding
- Internals vCon Exporter
- Internals Operator Guide Notes
- Internals Postmortems
- Internals Code Map
- Internals Lint Rules
- Internals Encapsulation Decoding
- Internals MCP Design Notes
- Internals Metrics And Output Notes