Repository navigation
Use OpenSIPS as the SIP Server
OpenSIPS is an open-source SIP server. With Kamailio, it is one of the two most common SIP proxies in front of phones, PBXes and carriers. The other voice-stack guides add a component beside it:
- a vCon server,
- TFPS,
- rtpengine,
- Homer,
- Prometheus.
This guide does three things:
- It installs OpenSIPS.
- It sets OpenSIPS up as a proxy that routes each call and stays in its signaling path.
- It proves the setup with a test call.
This guide does not use sipnab. When you have this working, Run sipnab beside OpenSIPS adds sipnab. If you use Kamailio instead, see Use Kamailio as your voice stack's SIP server.
Every block on this page ran as written, in order, 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 machine:
- The source build ran on a machine with nothing installed.
- The 4.0 packages ran on the same machine after its uninstall removed the source build. Kamailio was already running on 5062.
- OpenSIPS and Kamailio on one machine and 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 the message it quotes, on both.
| Software | Version or commit |
|---|---|
| OpenSIPS, from packages | 4.0.2, the current stable release, from the OpenSIPS project's own package repository |
| OpenSIPS, from source |
f46ef9337b, master, 4.1.0-dev |
| 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.
Choose one of the two installs.
- The packages are the stable release, and what most people run.
- The source build is OpenSIPS's development branch. The other voice-stack guides build it when they install OpenSIPS for you.
The steps after this one work with either.
Both add the OpenSIPS project's package repository:
- the packages come from it,
- the source build takes
opensips-cli, OpenSIPS's command-line tool, from it.
# Run all of these, in order.
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://apt.opensips.org/opensips-org.gpg -o /etc/apt/keyrings/opensips-org.gpg
. /etc/os-release
echo "deb [signed-by=/etc/apt/keyrings/opensips-org.gpg] https://apt.opensips.org $VERSION_CODENAME 4.0-releases" \
| sudo tee /etc/apt/sources.list.d/opensips.list >/dev/null
sudo apt-get update
sudo apt-get install -y opensips-cli# Run all of these, in order.
sudo apt-get install -y opensips
sudo opensips -V | head -1The package installs OpenSIPS under /usr. Its configuration is in
/etc/opensips/opensips.cfg. It adds a systemd unit that runs it as the
opensips user. It enables the unit but does not start it.
OpenSIPS master builds with compiler optimizations turned off. That is right for OpenSIPS's own developers and wrong for a proxy carrying calls. Turn them back on before you build:
# Run all of these, in order.
sudo apt-get install -y --no-install-recommends git build-essential bison flex uuid-dev pkg-config libncurses-dev libssl-dev
sudo mkdir -p /usr/local/src/voice && sudo chown "$USER": /usr/local/src/voice
cd /usr/local/src/voice
git clone https://github.com/OpenSIPS/opensips.git
cd opensips
git checkout f46ef9337b
make Makefile.conf
sed -i 's/^DEFS+= -DCC_O0/#DEFS+= -DCC_O0/' Makefile.conf
make -j2 all
sudo make install
/usr/local/sbin/opensips -V | head -1Leave DBG_MALLOC as it is. With both it and CC_O0 switched off, this commit
of master does not compile:
-
net/tcp_conn_defs.hcallsget_ticks()without including the header that declares it. - Only
DBG_MALLOC's headers happen to supply it.
The build installs OpenSIPS under /usr/local. Its configuration is in
/usr/local/etc/opensips/opensips.cfg. Give it its own user and a systemd
unit, as the package would:
# Run all of these, in order.
sudo useradd --system --home-dir /run/opensips --shell /usr/sbin/nologin opensips
sudo chown root:opensips /usr/local/etc/opensips
sudo chmod 750 /usr/local/etc/opensips
sudo tee /etc/systemd/system/opensips.service >/dev/null <<'EOF'
[Unit]
Description=OpenSIPS SIP server
After=network.target
[Service]
Type=forking
User=opensips
Group=opensips
RuntimeDirectory=opensips
RuntimeDirectoryMode=775
PIDFile=/run/opensips/opensips.pid
ExecStart=/usr/local/sbin/opensips -P /run/opensips/opensips.pid -f /usr/local/etc/opensips/opensips.cfg -m 64 -M 8
Restart=always
TimeoutStopSec=30s
LimitNOFILE=262144
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable opensipsThis 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 Kamailio already runs on this machine on 5060, move it to 5062 first. OpenSIPS and Kamailio on one machine explains how. 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.
The two installs keep their configuration and their modules in different places. The first two lines find them:
-
Cis your configuration file. -
Mis the directory your install loads modules from. The script'smpathnames it.
# Run all of these, in order.
for f in /etc/opensips/opensips.cfg /usr/local/etc/opensips/opensips.cfg; do sudo test -f "$f" && C=$f && break; done
for d in /usr/lib/*/opensips/modules /usr/local/lib64/opensips/modules; do [ -f "$d/tm.so" ] && M=$d && break; done
echo "configuration: $C modules: $M"
sudo tee "$C" >/dev/null <<'EOF'
# OpenSIPS as a SIP proxy that stays in the path of every call.
log_level=3
stderror_enabled=no
syslog_enabled=yes
syslog_facility=LOG_LOCAL0
udp_workers=2
open_files_limit=4096
socket=udp:192.0.2.10:5060 # the address your phones and carriers reach
mpath="MODULES/"
loadmodule "proto_udp.so" # built into the core, but still loaded by name
loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "sipmsgops.so"
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/run/opensips/opensips_fifo")
route {
if (!mf_process_maxfwd_header(10)) {
send_reply(483, "Too Many Hops");
exit;
}
if (has_totag()) {
if (is_method("ACK") && t_check_trans()) {
t_relay();
exit;
}
if (!loose_route()) {
send_reply(404, "Not here");
exit;
}
t_relay();
exit;
}
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
}
t_check_trans();
if (!is_method("INVITE")) {
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 sed -i "s|^mpath=\"MODULES/\"|mpath=\"$M/\"|" "$C"
sudo chown root:opensips "$C"
sudo chmod 640 "$C"
sudo opensips -C -f "$C"
sudo systemctl restart opensips
systemctl is-active opensipsWhat the parts do:
-
record_route()adds aRecord-Routeheader naming OpenSIPS. 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. -
mi_fifois what letsopensips-clitalk to the running OpenSIPS.
opensips -C checks the configuration and prints config file ok before
anything starts.
SIPp plays both ends:
- a callee on this machine that echoes audio back,
- a caller that dials through OpenSIPS 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 itsBYEwould miss the proxy and draw404 Not here. - 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-RouteOpenSIPS added.
OpenSIPS 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 OpenSIPS shows both directions of it.
- rtpengine puts a media relay in its path.
See what OpenSIPS has handled. opensips-cli asks the running OpenSIPS
through its management interface. OpenSIPS 4 groups the management commands
by namespace. So statistics:get is what OpenSIPS 3 called get_statistics:
# Run all of these, in order.
sudo opensips-cli -x mi statistics:get rcv_requests
sudo opensips-cli -x mi statistics:get tm:After the test call, core:rcv_requests is 3:
- the
INVITE, - the
ACK, - the
BYE.
Check health and read the logs.
# Run all of these, in order.
systemctl is-active opensips
sudo opensips-cli -x mi core:uptime
sudo journalctl -u opensips -n 30Apply a configuration change. Check it first, then restart:
# Run all of these, in order.
for f in /etc/opensips/opensips.cfg /usr/local/etc/opensips/opensips.cfg; do sudo test -f "$f" && C=$f && break; done
sudo opensips -C -f "$C"
sudo systemctl restart opensipsUninstall.
- For the packages, purge them.
- For the source build, remove what it installed under
/usr/local:
# Run all of these, in order.
sudo systemctl disable --now opensips
if dpkg -s opensips >/dev/null 2>&1; then sudo apt-get purge -y opensips; fi
sudo rm -rf /usr/local/sbin/opensips* /usr/local/lib64/opensips /usr/local/etc/opensips /etc/systemd/system/opensips.service
sudo apt-get purge -y opensips-cli
sudo rm /etc/apt/sources.list.d/opensips.list /etc/apt/keyrings/opensips-org.gpgEach guide works with either install. Its "Before you start" section says which
of its steps to skip. With the packages, some guides need a module package
beside opensips:
| Guide | Modules it loads | With the packages, also install |
|---|---|---|
| rtpengine |
rtpengine, rtp_relay, dialog
|
nothing: they come with opensips
|
| rtpproxy |
rtpproxy, dialog
|
nothing: they come with opensips
|
| Homer |
proto_hep, tracer
|
nothing: they come with opensips
|
| Prometheus |
httpd, prometheus
|
opensips-http-modules, opensips-prometheus-module
|
| Add a vCon server |
siprec, b2b_entities, uac_auth
|
opensips-siprec-module, opensips-auth-modules
|
| TFPS | none | nothing: TFPS needs nothing from OpenSIPS |
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.
- Keep OpenSIPS on 5060.
- Move Kamailio to 5062, as the Kamailio guide's section describes.
- Give sipnab both ports with
--portrange 5060-5062.
-
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.
-
opensips -Creportscould not open module <signaling.so>.- The
mpathline is missing or names the wrong directory. - OpenSIPS does not fall back to its own module directory without it.
- The
-
opensips-clisaysFIFO file /var/run/opensips/opensips_fifo does not exist. One of these is true:- OpenSIPS is not running.
-
mi_fifois not loaded. - Its
fifo_nameis not/run/opensips/opensips_fifo, whereopensips-clilooks.
-
opensips-clisaysno command 'get_statistics' in module 'mi'. That is the OpenSIPS 3 name. OpenSIPS 4 calls itstatistics:get. -
The test call's
BYEgets404 Not here. The caller ignored the route set. Use the editeduac_rr.xml, not SIPp's built-inuac_pcap.
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