Skip to content

Use Kamailio as the SIP Server

github-actions[bot] edited this page Oct 17, 2026 · 1 revision

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.

Tested on

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.

Install Kamailio

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 -1

gpg --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.d file 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.

Configure Kamailio as a proxy

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 listen line, before you run this block,
  • in the caller's 192.0.2.10:5060 in 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 kamailio

What the parts do:

  • record_route() adds a Record-Route header naming Kamailio. So the call's later requests, the ACK and the BYE, 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.so is what lets kamcmd talk to the running Kamailio.

kamailio -c checks the configuration before anything starts.

Place a test call

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-Route header. So Kamailio cannot route its ACK and BYE.
  • The two route sed lines 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 call at 1.
  • The last line prints the Record-Route Kamailio added, such as <sip:192.0.2.10;lr;ftag=52680SIPpTag091>. It holds:
    • Kamailio's address,
    • lr for loose routing,
    • the caller's From tag.

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.

Operate it

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 30

Apply 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 kamailio

Uninstall.

# 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.gpg

OpenSIPS and Kamailio on one machine

Developers 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 kamailio

A 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 90s

Each shows Successful call at 1. sipnab watches ports 5060-5061 by default. So give it both proxies' ports: --portrange 5060-5062.

Kamailio in the other voice-stack guides

The other guides use OpenSIPS. Each has a section that says what changes with Kamailio:

  • rtpengine: Kamailio's rtpengine module.
  • rtpproxy: Kamailio's rtpproxy module.
  • Homer: Kamailio's siptrace module sends HEP.
  • Prometheus: Kamailio's xhttp_prom module.
  • 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.

When something does not work

  • apt-get says Could 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 -c reports parse error in config file and unknown 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.
  • kamcmd says connect(//var/run/kamailio/kamailio_ctl): No such file or directory. Kamailio is not running, or ctl.so is not loaded.
  • The test call's BYE gets no answer.
    • The caller ignored the route set. So Kamailio dropped its ACK and BYE.
    • SIPp can still report the call as successful:
      • the callee, which never got the ACK, sends its 200 OK again,
      • SIPp takes one of those for the BYE's answer.
    • Use the edited uac_rr.xml, not SIPp's built-in uac_pcap.

Home

Getting started

Using the TUI

CLI & automation

Configuration

Integrations (API & MCP)

Your SIP server

Add to your voice stack

Development & internals

Clone this wiki locally