Merged Edition · codeandcore

Kamailio Field Manual

Chapter 1 — Installation, First Registration & Proof of Life

From zero to a running SIP proxy on Ubuntu 24.04. Every command is real. Every config line is explained. Victory condition: a softphone registers, you watch it happen in the logs, and you understand exactly what you saw.

Ubuntu 24.04Target Platform
Kamailio 6.xVersion
PostgreSQL 16Backend
PJSIPSIP Stack
Cloudflare Pages Ready

Two chapters, one static entrypoint.

Chapter 1 stays as the hands-on Kamailio build, and Chapter 2 is now split into its own page. Use this page as the merged hub for the series when you publish it on Cloudflare Pages.

Chapter 1

Kamailio Field Manual

Installation, first registration, PostgreSQL, NAT, security, and the proof-of-life workflow.

Chapter 2

Containers & PostgreSQL

Docker-based Kamailio packaging, Compose workflow, schema bootstrap, and repeatable deployment.

Static files only. No build step required. Cloudflare Pages can serve this folder as-is.

01

The Mental Model

You already have this. You built BGP at MTN Uganda in 2006. You multihomed Tullow Oil. You know exactly what a routing layer does — it does not carry the payload, it decides where the payload goes. Kamailio is that layer, but for SIP.

The Core Analogy

BGP is to IP packets what Kamailio is to SIP messages. Your Juniper MX does not host websites — it routes the packets that reach the servers that do. Kamailio does not process calls — it routes the SIP signalling that reaches the Asterisk nodes that do. One layer routes. The other layer processes. Never confuse them.

When a SIP phone powers on and sends a REGISTER message, that message hits Kamailio first. Kamailio authenticates it against PostgreSQL, stores the phone's location (IP address and port), and returns 200 OK. Kamailio never touches audio. Not one byte of RTP ever passes through it.

When a call comes in, Kamailio looks up where the destination phone last registered, then forwards the SIP INVITE to Asterisk. Asterisk answers it, bridges the audio, runs the IVR, records the call. Kamailio's job is already done before the first word is spoken.

SIP Registration Flow
SIP Phone ──REGISTER──▶ Kamailio ──lookup──▶ PostgreSQL // authenticate subscriber
SIP Phone ◀──200 OK── Kamailio ──WRITE──▶ location table // store IP:port of phone
Inbound Call Flow
Caller ──INVITE──▶ Kamailio ──lookup location──▶ PostgreSQL
Kamailio ──INVITE (fwd)──▶ Asterisk // Kamailio's job is done here
Asterisk ──RTP audio──▶ Phone // audio NEVER goes through Kamailio

This separation is why Kamailio scales to hundreds of thousands of registrations on modest hardware. It is stateless for most operations. It does not hold open audio streams. It is a SIP router, and it is extraordinarily good at that one thing.

02

What Your VM Needs

For this chapter — learning, testing, first registration — a single VM is fine. In production you will separate Kamailio, PostgreSQL, and Asterisk onto different hosts. For today, everything on one machine. Ubuntu 24.04 LTS (Noble Numbat).

ResourceMinimum (Lab)Recommended (Lab)
CPU1 vCPU2 vCPU
RAM1 GB2 GB
Disk10 GB20 GB
OSUbuntu 24.04 LTS (64-bit)
NetworkA static IP or one that won't change mid-session
Ports openUDP/TCP 5060 (SIP), UDP 5060 inbound
Know Your IP Address Before You Start

Kamailio binds to a specific IP address. Get it now and keep it in view. Run ip addr show and note the IP of your main interface (eth0, ens3, or whatever it is). You will put this in the config. If you use the wrong IP, nothing works and the error messages will not obviously tell you why.

confirm your IP before anything else bash
# Run this. Note the output. Write it down.
ip addr show | grep "inet " | grep -v 127.0.0.1

# Example output you are looking for:
#   inet 192.168.1.50/24 brd 192.168.1.255 scope global eth0
# Your IP in this example is 192.168.1.50
# This chapter uses MY_SERVER_IP as a placeholder — replace it everywhere
03

Installing Kamailio

Kamailio maintains its own official Debian/Ubuntu package repository. Ubuntu 24.04 Noble Numbat is fully supported. Do not use the version in the Ubuntu main repos — it may lag behind by a release. Use the official Kamailio repo for the latest stable.

What You Are Installing

kamailio — the core binary and base modules. kamailio-postgres-modules — the module that lets Kamailio talk to PostgreSQL for authentication and location storage. kamailio-utils — kamctl and kamdbctl, the command-line tools you use to manage everything. kamailio-tls-modules — TLS support for secure SIP. You will want this before going to production.

Update the system and install prerequisites

step 1bash
apt update && apt upgrade -y
apt install -y gnupg2 curl software-properties-common

Add the official Kamailio repository

The GPG key authenticates the packages. The sources.list entry points to the Noble (Ubuntu 24.04) branch of the Kamailio 6.x series.

step 2 — add repo key and sourcebash
# Fetch and install the Kamailio GPG signing key
curl -fsSL https://deb.kamailio.org/kamailiodebkey.gpg \
  | gpg --dearmor \
  | tee /usr/share/keyrings/kamailio-archive-keyring.gpg > /dev/null

# Add the repository — Ubuntu 24.04 Noble, Kamailio 6.x stable
echo "deb [signed-by=/usr/share/keyrings/kamailio-archive-keyring.gpg] \
  http://deb.kamailio.org/kamailio60 noble main" \
  | tee /etc/apt/sources.list.d/kamailio.list

# Refresh package lists
apt update

Install Kamailio and the modules you need

step 3 — install packagesbash
apt install -y \
  kamailio \
  kamailio-postgres-modules \
  kamailio-utils \
  kamailio-tls-modules \
  kamailio-presence-modules

This will pull in all required dependencies automatically. The install does not start Kamailio automatically — it waits for you to configure it first.

Verify the installation

step 4 — confirm binary existsbash
kamailio -V

# Expected output (version numbers will match your install):
# version: kamailio 6.0.x (x86_64/linux)
# flags: USE_TCP USE_TLS USE_SCTP DISABLE_NAGLE USE_RAW_SOCKS ...
What You Now Have

The Kamailio binary is installed at /usr/sbin/kamailio. Modules live at /usr/lib/x86_64-linux-gnu/kamailio/modules/. The main config file location is /etc/kamailio/kamailio.cfg. The helper config is /etc/kamailio/kamctlrc. Kamailio is not running yet. That is correct.

04

PostgreSQL & the Database Schema

Kamailio stores subscriber credentials, phone locations, and call records in PostgreSQL. The tool kamdbctl creates the entire schema for you — you do not write a single SQL statement by hand.

Install PostgreSQL Server

install postgresqlbash
apt install -y postgresql postgresql-contrib
systemctl enable postgresql
systemctl start postgresql

# Verify it is running
systemctl status postgresql | grep "Active:"

Create PostgreSQL users and database

create postgres roles for kamailiobash
sudo -u postgres psql

-- inside psql shell:
CREATE ROLE kamailio WITH LOGIN PASSWORD 'KamailioRW2024!';
CREATE ROLE kamailioro WITH LOGIN PASSWORD 'KamailioRO2024!';
CREATE DATABASE kamailio OWNER kamailio;
GRANT CONNECT ON DATABASE kamailio TO kamailioro;
\q
Production Note: Prefer SCRAM Password Hashing

On current PostgreSQL releases, scram-sha-256 is the recommended password verifier and authentication method. Confirm the server is using SCRAM for new passwords, then rotate role passwords if needed.

confirm scram password policybash
sudo -u postgres psql -c "SHOW password_encryption;"

# If this is not 'scram-sha-256', set it:
sudo -u postgres psql -c "ALTER SYSTEM SET password_encryption='scram-sha-256';"
sudo -u postgres psql -c "SELECT pg_reload_conf();"

# Then reset Kamailio role passwords so they are stored as SCRAM verifiers
sudo -u postgres psql -c "ALTER ROLE kamailio PASSWORD 'KamailioRW2024!';"
sudo -u postgres psql -c "ALTER ROLE kamailioro PASSWORD 'KamailioRO2024!';"

Lock down pg_hba.conf for Kamailio access

Restrict database access to local connections (or specific Kamailio hosts) and force SCRAM auth. Exact path can vary by PostgreSQL major version.

/etc/postgresql/*/main/pg_hba.confconf
# Keep peer auth for postgres local admin
local   all             postgres                                peer

# Kamailio DB users on localhost (IPv4/IPv6)
host    kamailio        kamailio        127.0.0.1/32           scram-sha-256
host    kamailio        kamailio        ::1/128                scram-sha-256
host    kamailio        kamailioro      127.0.0.1/32           scram-sha-256
host    kamailio        kamailioro      ::1/128                scram-sha-256

# For remote DB host deployments, replace loopback ranges above with
# your Kamailio server subnet(s) only. Never use 0.0.0.0/0.
reload postgres after pg_hba changebash
systemctl reload postgresql
systemctl status postgresql | grep "Active:"

Configure kamctlrc before running kamdbctl

kamctlrc is where you tell the Kamailio toolset how to reach PostgreSQL. Edit it now — the database creation step reads it.

/etc/kamailio/kamctlrc — database sectionconf
## Uncomment and set these lines in /etc/kamailio/kamctlrc

SIP_DOMAIN=sip.yourdomain.com       # or your server IP for lab

DBENGINE=PGSQL
DBHOST=localhost
DBPORT=5432
DBNAME=kamailio

DBRWUSER="kamailio"
DBRWPW="KamailioRW2024!"          # choose your own

DBROUSER="kamailioro"
DBROPW="KamailioRO2024!"          # choose your own

DBROOTUSER="postgres"
DBROOTPW="YourPostgresSuperuserPassword"

Create the Kamailio database and all tables

kamdbctl create — one command does everythingbash
kamdbctl create

# You will be prompted to confirm. Type 'y'.
# This creates:
#   - the 'kamailio' database
#   - kamailio and kamailioro PostgreSQL users
#   - ~30 tables including: subscriber, location, acc, missed_calls
#
# If it asks for the PostgreSQL superuser password, enter it.

Apply least-privilege grants for read-only role

After kamdbctl create, grant only what the read-only user needs. Keep write privileges on kamailio only.

grant readonly access to kamailiorosql
sudo -u postgres psql -d kamailio

REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM kamailioro;
GRANT USAGE ON SCHEMA public TO kamailioro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO kamailioro;

ALTER DEFAULT PRIVILEGES FOR ROLE kamailio IN SCHEMA public
GRANT SELECT ON TABLES TO kamailioro;

\q

Add your first subscriber (SIP account)

This creates the account 1001@yourdomain with password test1234. This is what your softphone will use to register.

kamctl add — create a SIP userbash
kamctl add 1001 test1234
kamctl add 1002 test1234

# Verify they were created:
kamctl show 1001

# Expected output:
# username | domain          | password  | ha1 ...
# 1001     | sip.yourdomain  | test1234  | ...
05

kamailio.cfg — The Routing Brain

This is the heart of Kamailio. Everything it does is defined here. The default config that ships with the package is a complete, working, production-capable configuration for basic SIP proxy operation. You do not rewrite it — you configure it via preprocessor defines at the top.

How the Config File Works

The top section uses C-style #!define and #!ifdef preprocessor directives to enable features. You define what you want, and the rest of the file uses those definitions to activate the right code paths. Think of it like feature flags at the top of the file, and the actual routing logic below.

Edit /etc/kamailio/kamailio.cfg. Find and modify these lines near the top. Most are already present but commented out or need your values substituted in.

/etc/kamailio/kamailio.cfg — top section to configure kamailio config
#!KAMAILIO
#
####### Global Parameters #########

# ── FEATURE FLAGS ────────────────────────────────────────────────────
# Uncomment WITH_POSTGRES to enable PostgreSQL auth and location storage
#!define WITH_POSTGRES
# Uncomment WITH_AUTH to require authentication on REGISTER and INVITE
#!define WITH_AUTH
# Uncomment WITH_USRLOCDB to store registrations in PostgreSQL (not memory)
#!define WITH_USRLOCDB

# ── DATABASE URL ─────────────────────────────────────────────────────
# Replace the credentials to match what you set in kamctlrc
#!define DBURL "postgres://kamailio:KamailioRW2024!@localhost/kamailio"

# ── SERVER IDENTITY ──────────────────────────────────────────────────
# This must match the domain you used when creating subscribers
domain = "sip.yourdomain.com"   # or your server IP for lab

# ── LISTEN ADDRESSES ─────────────────────────────────────────────────
# Replace MY_SERVER_IP with the actual IP of your VM (from Section 02)
listen = udp:MY_SERVER_IP:5060
listen = tcp:MY_SERVER_IP:5060

# ── LOGGING ──────────────────────────────────────────────────────────
debug=3          # 0=errors only, 3=info, 5=full debug (very noisy)
log_stderror=no  # log to syslog, not stderr
log_facility=LOG_LOCAL0

# ── PERFORMANCE ──────────────────────────────────────────────────────
# For a lab VM, these defaults are fine
children=4       # worker processes, set to number of CPU cores
The Three Lines That Must Be Right

If Kamailio refuses to start or phones cannot register, it is almost always one of three things: (1) DBURL has wrong credentials or database name, (2) listen IP does not match the actual interface IP, (3) domain does not match what you used with kamctl add. Check these three first, always.

Understanding the Routing Script (the important parts)

Below the configuration section, the file contains routing logic. You do not need to modify this for basic operation, but you need to understand what it does. Here are the key route blocks:

the main request_route — every incoming SIP message enters here kamailio routing script
request_route {

    # ── Max Forwards check ───────────────────────────────────────────
    # Prevents SIP routing loops. If a packet has been forwarded
    # more than 10 times, reject it. Same concept as IP TTL.
    if (!mf_process_maxfwd_header("10")) {
        sl_send_reply("483", "Too Many Hops");
        exit;
    }

    # ── OPTIONS keepalive (ping/pong) ─────────────────────────────────
    # SIP phones periodically send OPTIONS to check if the server is alive.
    # We reply 200 OK immediately without processing further.
    if (is_method("OPTIONS") && uri==myself) {
        sl_send_reply("200", "OK");
        exit;
    }

    # ── Route REGISTER to the registrar handler ──────────────────────
    # All REGISTER messages (phone checking in) go to route[REGISTRAR]
    if (is_method("REGISTER")) {
        route(REGISTRAR);
        exit;
    }

    # ── Everything else: look up where to send it ────────────────────
    # For calls and other messages, look up the destination in the
    # location table (where did they last register from?)
    if (!lookup("location")) {
        # Destination not found in our location table
        sl_send_reply("404", "Not Found");
        exit;
    }

    route(RELAY);   # Forward it to wherever lookup() found
}
route[REGISTRAR] — handles phone registration kamailio routing script
route[REGISTRAR] {
    # ── Authentication ───────────────────────────────────────────────
    # www_authorize checks the phone's credentials against the
    # 'subscriber' table in PostgreSQL. If wrong password → 401 Unauthorized.
    if (is_method("REGISTER")) {
        if (!www_authorize("$fd", "subscriber")) {
            www_challenge("$fd", "0");
            exit;
        }
    }

    # ── Save the registration ────────────────────────────────────────
    # save() writes the phone's current IP:port into the location table.
    # This is how Kamailio knows where to forward calls to this extension.
    if (!save("location")) {
        sl_reply_error();
    }
    exit;
}
06

Starting Kamailio & Reading Logs

Before starting, always run the config check. Kamailio's config parser will catch syntax errors and tell you exactly which line is wrong. Never start Kamailio without checking first — in production this habit will save you from outages.

validate config — always do this before starting bash
kamailio -c -f /etc/kamailio/kamailio.cfg

# Good output ends with:
#   Success: Configuration file '/etc/kamailio/kamailio.cfg' OK
#
# If there is a syntax error it will say:
#   ERROR: ... line 47: unexpected token
# Go to that line number and fix it before proceeding.
start, stop, restart, status bash
# Start Kamailio
systemctl start kamailio

# Enable it to start on boot
systemctl enable kamailio

# Check it is running
systemctl status kamailio

# Verify it is listening on port 5060
ss -ulnp | grep 5060
ss -tlnp | grep 5060

# Expected output:
# udp  UNCONN  0  0  MY_SERVER_IP:5060  0.0.0.0:*  users:(("kamailio",...))

Reading the logs in real time

Kamailio logs to syslog. On Ubuntu 24.04 this goes to the journal. Open a second terminal and keep this running while you test — this is your window into everything that is happening.

tail the logs — keep this open in a second terminal bash
# Method 1: journalctl (preferred on Ubuntu 24.04)
journalctl -u kamailio -f --output=cat

# Method 2: syslog directly
tail -f /var/log/syslog | grep kamailio

# Method 3: debug mode — maximum verbosity (for when you are stuck)
# Stop the service first, then run in foreground:
systemctl stop kamailio
kamailio -D -E -d -d -d -f /etc/kamailio/kamailio.cfg
# This prints every SIP message in full to your terminal
# Ctrl+C to stop, then systemctl start kamailio to go back to normal
07

Registering Your First Phone

Now you register a SIP softphone. Use any SIP client you have — Zoiper, Linphone, MicroSIP (Windows), or the Linphone app on your mobile. The settings are the same for all of them.

SettingValueNotes
SIP Username / Extension 1001 The user you created with kamctl add
SIP Password test1234 As set in kamctl add
SIP Domain / Server MY_SERVER_IP Your VM's IP address
SIP Port 5060 Default SIP port
Transport UDP Start with UDP; TCP later
STUN Disabled Not needed for same-LAN lab

Point the phone at your server IP and let it register. While it connects, watch your log terminal. You should see a burst of activity. Here is what you are looking for:

what successful registration looks like in the logs syslog output
# First attempt — phone sends REGISTER without credentials
REGISTER sip:MY_SERVER_IP SIP/2.0
# Kamailio challenges it — asks for credentials
SIP/2.0 401 Unauthorized
# Phone retries with credentials (digest auth)
REGISTER sip:MY_SERVER_IP SIP/2.0  # this time with Authorization header
# Kamailio verifies against PostgreSQL subscriber table
# Writes phone's IP:port into location table
SIP/2.0 200 OK                     # ← this is your victory
# Log line: "REGISTERED aor=<sip:1001@yourdomain> expires=3600"
Confirm the Registration in the Database

The definitive proof: run kamctl ul show 1001 and you will see the phone's current IP address, port, user agent string, and when the registration expires. If this shows data, Kamailio is working correctly.

verify registration from the command line bash
# Show where extension 1001 is currently registered
kamctl ul show 1001

# Show ALL currently registered phones
kamctl ul show

# Expected output for a registered phone:
# Contact: <sip:1001@192.168.1.100:5060>
# Expires: 3600
# User-Agent: Zoiper ...

# Register a second phone on extension 1002, then try calling 1001
# from 1002. Kamailio looks up 1001's location and routes the call.
08

The SIP Flow — What Just Happened

Registration looked like magic from the phone's perspective — it connected and showed a green tick. Here is exactly what happened, message by message, so that when something goes wrong you will know where in this sequence to look.

#DirectionMessageWhat it means
1 Phone → Kamailio REGISTER (no auth) Phone announces itself, asks to register. No credentials yet.
2 Kamailio → Phone 401 Unauthorized Challenge: "Prove who you are." Contains a nonce (random challenge value).
3 Phone → Kamailio REGISTER (with auth) Phone hashes username+password+nonce and sends the result. Password never travels in clear text.
4 Kamailio → PostgreSQL SELECT ha1 from subscriber Fetches the stored password hash for this user.
5 PostgreSQL → Kamailio Hash returned Kamailio computes the expected response and compares to what the phone sent.
6 Kamailio → PostgreSQL INSERT/UPDATE location Stores phone's current IP:port with expiry time. This is how calls reach this phone.
7 Kamailio → Phone 200 OK Registered. Phone shows green. Repeats before expiry (usually every 60–600 seconds).
The Password Never Travels in Plaintext

SIP digest authentication is a challenge-response system. The phone never sends your password across the network. It sends MD5(username:realm:password:nonce). Kamailio computes the same hash server-side and compares. This is why Kamailio stores both the plaintext password and the pre-computed HA1 hash in the subscriber table — it needs the hash to verify without receiving the password.

09

Useful Daily Commands

These are the commands you will use constantly. They should become muscle memory before you move to the next chapter.

CommandWhat it does
kamctl ul showShow all currently registered phones (user location table)
kamctl ul show 1001Show where extension 1001 is registered right now
kamctl add 1003 passwordCreate a new SIP subscriber
kamctl passwd 1001 newpasswordChange a subscriber's password
kamctl rm 1001Delete a subscriber
kamctl monitorLive statistics — calls/sec, registrations, memory usage
kamctl fifo get_statistics allDetailed runtime statistics dump
kamailio -cCheck config syntax (always run before reload)
systemctl reload kamailioReload config without dropping calls
kamcmd ul.dumpAlternative location table dump via RPC
kamcmd stats.get_statistics allFull stats via RPC interface
kamctl monitor — your cockpit view bash
kamctl monitor 1

# Refreshes every 1 second. Shows:
#   Now: X processes, X listening, X registered contacts
#   Last 1s: X processed, X forwarded, X dropped
#   Memory: used / available
#   SHM memory (shared): status
Troubleshooting Checklist When Phones Cannot Register

1. Check systemctl status kamailio — is it actually running?
2. Check ss -ulnp | grep 5060 — is it listening on the right IP?
3. Check firewall: ufw status — is UDP 5060 allowed?
4. Run kamailio -D -E -f /etc/kamailio/kamailio.cfg in foreground and watch raw SIP messages.
5. Check that the domain in kamailio.cfg matches the SIP domain in kamctlrc and in your softphone config.
6. Check PostgreSQL is running: systemctl status postgresql.
7. Test the DB connection manually: psql -h localhost -U kamailio -d kamailio -c "SELECT * FROM subscriber LIMIT 5;"
8. If auth fails, check PostgreSQL logs for pg_hba.conf rejects and bad password verifier errors.

10

NAT & Edge Client Reality

Your chapter is excellent for same-LAN lab success. The first gap to close for real-world clients is NAT behavior. Kamailio docs around nathelper, registrar, and usrloc make this explicit: store the received source tuple for REGISTER and use standards-conforming alias handling for in-dialog routing.

Critical NAT Rule

If you use fix_nated_register(), set received_avp to the same value in both nathelper and registrar. If these values differ, registrations can appear to work but re-INVITE/BYE and keepalive behavior becomes inconsistent.

minimal NAT-safe registration additions (top-level module params) kamailio config
# NAT detection + received tuple storage
modparam("nathelper", "received_avp", "$avp(s:rcv)")
modparam("registrar", "received_avp", "$avp(s:rcv)")

# Optional SIP keepalive pings for UDP NATed endpoints
modparam("nathelper", "natping_interval", 15)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_method", "OPTIONS")

# In REQUEST_ROUTE
if (nat_uac_test("19")) {
    # 1=private Contact, 2=Via mismatch, 16=port mismatch
    fix_nated_register();
}
RFC-Friendly Contact Handling

Kamailio documentation warns that fix_nated_contact() rewrites Contact and can break strict clients. Prefer set_contact_alias() and handle_ruri_alias() for a more standards-conforming path, especially when TCP/TLS connection reuse matters.

11

Identity, Domain, and alias

Kamailio core docs for myself, alias, and listen show a common first-production failure pattern: the proxy identifies local domains incorrectly, then routing and loose_route behavior become unpredictable. Your build should define identity intentionally.

identity hardening block kamailio config
# Core identity for myself checks
listen=udp:MY_SERVER_IP:5060
listen=tcp:MY_SERVER_IP:5060
alias=sip.yourdomain.com:5060
alias=MY_SERVER_IP:5060

# If you serve many domains/userspaces, align these:
modparam("auth_db", "use_domain", 1)
modparam("usrloc", "use_domain", 1)
Simple Consistency Rule

Keep four values aligned: softphone domain, SIP_DOMAIN in kamctlrc, auth realm in challenges, and what Kamailio treats as local (alias/myself). Alignment here removes a huge class of 401/404 confusion.

12

Security Baseline (Don’t Skip)

The official auth and permissions modules add controls missing from a pure lab setup. For internet-facing SIP, add source ACLs, stronger digest behavior, and challenge integrity checks.

ControlWhy it mattersMinimum recommendation
permissions ACLBlock unknown source networks earlyallow_source_address("1") gate for trunks/admin endpoints
auth qopAdds nonce-count semantics and better replay resistancemodparam("auth","qop","auth")
nonce_countDetects nonce reuse/replaymodparam("auth","nonce_count",1)
auth_checks_*Binds nonce to message identity/source traitsEnable conservative bits first (uri and source IP)
starter auth hardening snippet kamailio config
modparam("auth", "qop", "auth")
modparam("auth", "nonce_count", 1)
modparam("auth", "nonce_expire", 300)
modparam("auth", "auth_checks_register", 9)
modparam("auth", "auth_checks_no_dlg", 9)

# 9 = URI(1) + source IP(8)
# Avoid enabling call-id/from-tag checks until endpoint behavior is verified.
Do Not Assume Lab Defaults Are Safe

If you expose UDP 5060 publicly with weak subscriber passwords and no ACL/rate controls, credential stuffing starts quickly. Keep this chapter in lab mode unless these controls are in place.

13

usrloc DB Modes Explained

Kamailio usrloc documentation defines five practical storage modes. Picking the wrong one causes confusion around restart behavior and performance. This is a key concept worth making explicit in Chapter 1.

db_modeBehaviorWhen to use
0Memory only, no DB persistenceFast lab tests where restart loss is acceptable
1Write-through (every change to DB immediately)Higher durability, lower speed
2Write-back (memory + periodic DB flush)Common balance for single-node setups
3DB-only (no memory cache)Shared DB multi-proxy designs; slower per request
4Load at startup then memory onlySpecialized replication patterns
recommended chapter-1 baseline kamailio config
# Good baseline for your current architecture
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "timer_interval", 60)

Documentation anchors used for this extension

Core cookbook and module docs reviewed: core configuration (listen, alias, myself), auth, auth_db, registrar, usrloc, nathelper, and permissions.

Chapter 1 Complete — What You Now Have

Chapter 2 builds on this foundation: adding Asterisk behind Kamailio, the PJSIP trunk configuration, and routing inbound calls from Kamailio to your first IVR. The BGP router now has something to route calls to.