ซื้อสินค้า VoIP คลิกไปที่ https://www.lazada.co.th/shop/adventek/

 

1. เมื่อไหร่ใช้ OpenSIPS? เมื่อไหร่ใช้ Asterisk/IssabelPBX/FreePBX?

มี site ที่เคยทำให้ลูกค้าประมาณ 300 extensions ก็สามารถใช้ IssabelPBX run บน server ตัวเดียวได้

อาจจะช้าบ้างในกรณีเปลี่ยน config แล้ว reload server บ่อยๆ อย่างไรก็ตาม site ที่มี extensions > 200 ก็น่าจะใช้

OpenSIPS ได้แล้ว แต่ OpenSIPS รองรับเฉพาะ SIP protocol (signaling) ต้องมี media server

(IVR, voicemail, conf. room) มาเสริม ซึ่งก็ต้องใช้ Asterisk หรือ FreeSWITCH หรือ YATE มาทำหน้าที่นี้

ในกรณีที่เป็นบริการสาธารณะ (เช่น โทรศัพท์บ้านของ TOT) ก็สามารถนำ OpenSIPS + media server มา

ทดแทนได้   ซึ่ง Asterisk/IssabelPBX/FreePBX ไม่เหมาะกับงานแบบนี้

 

2. OpenSIPS - Open SIP Server

OpenSIPS (www.opensips.org) เป็น open source SIP server ที่พัฒนาต่อเนื่องมาจาก SER project ->

OpenSER project มีความเสถียรและมี features ที่ค่อนข้างสมบูรณ์ (แต่การใช้งานไม่ได้ง่ายสำหรับ user

ทั่วไป) OpenSIPS มี features หลักๆ ดังนี้

  • SIP registrar server
  • SIP router / proxy (lcr, dynamic routing, dialplan features)
  • SIP redirect server
  • SIP presence agent
  • SIP back-to-back User Agent
  • SIP IM server (chat and end-2-end IM)
  • SIP load-balancer or dispatcher
  • SIP front end for gateways/asterisk

บทความของเราในตอนนี้จะเป็นการติดตั้ง OpenSIPS 3.4.9 บน Debian 11.11 หลังจากนั้นบทความใน

ตอนต่อๆ ไป จะกล่าวถึง OpenSIPS GUI, การใช้งานในลักษณะ SIP trunking และ VoIP Service Platform

 

3. ติดตั้ง OpenSIPS

ขั้นแแรกติดตั้ง Debian 11.11 เลือก options - web server, SSH server, standard system utilities ตามลิ้งค์

ติดตั้ง Debian

หลังจากติดตั้ง OS เสร็จ ให้ login ด้วย root แล้ว ติดตั้ง software ที่จำเป็น

#apt install curl gnupg2 m4 wget unzip

ติดตั้ง rtpproxy

#cd /usr/src

#wget http://archive.ubuntu.com/ubuntu/pool/universe/r/rtpproxy/

rtpproxy_1.2.12.2_amd64.deb

#dpkg -i rtpproxy_1.2.1-2.2_amd64.deb

edit /etc/default/rtpproxy

    EXTRA_OPTS="-l 192.168.100.200 -s udp:127.0.0.1:12221 -u rtpproxy:rtpproxy"

edit /etc/init.d/rtpproxy

    DAEMON_OPTS="-p $PIDFILE $EXTRA_OPTS"

#systemctl restart rtpproxy

#systemctl enable rtpproxy

ติดตั้ง mariadb-server

#apt install mariadb-server

#mysql_secure_installation

ติดตั้ง OpenSIPS 3.4.9 from repos

#curl https://apt.opensips.org/opensips-org.gpg -o /usr/share/keyrings/opensips-org.gpg

#echo "deb [signed-by=/usr/share/keyrings/opensips-org.gpg] https://apt.opensips.org bullseye 3.4-releases" >/etc/apt/sources.list.d/opensips.list

#echo "deb [signed-by=/usr/share/keyrings/opensips-org.gpg] https://apt.opensips.org bullseye cli-nightly" >/etc/apt/sources.list.d/opensips-cli.list

#apt update && apt

#apt install opensips-*

คอนฟิก OpenSIPS-CLI

edit file /root/.opensips-cli.cfg ดังนี้

[default]

log_level: WARNING

prompt_name: cli

prompt_intro: Welcome to my CLI!

prompt_emptyline_repeat_cmd: False

history_file: ~/.opensips-cli.history

history_file_size: 1000

output_type: pretty-print

communication_type: http

domain: 192.168.100.200

plain_text_passwords: true   

 ใช้ opensips-cli สร้าง database ตาม commands ดังนี้

    #opensips-cli -x database create opensips

    #opensips-cli -x database add presence

 

4. คอนฟิก OpenSIPS

คอนฟิก log file

#touch /var/log/opensips.log

แก้ไข file /etc/rsyslog.conf โดยการเพิ่มบรรทัดต่อไปนี้เข้าไป

    local0.*          -/var/log/opensips.log

#systemctl restart rsyslog

แก้ไข file /etc/opensips/opensips.cfg ดังนี้

(***** download file ได้ที่ OpenSIPS-3.4.5 *****)

###################################

####### Global Parameters #########

###################################

/* uncomment the following lines to enable debugging */

#debug_mode=yes

log_level=3

xlog_level=3

stderror_enabled=no

syslog_enabled=yes

syslog_facility=LOG_LOCAL0

udp_workers=4

/* uncomment the next line to enable the auto temporary blacklisting of

   not available destinations (default disabled) */

#disable_dns_blacklist=no

/* uncomment the next line to enable IPv6 lookup after IPv4 dns

   lookup failures (default disabled) */

#dns_try_ipv6=yes

socket=udp:192.168.100.200:5060

################################

####### Modules Section ########

################################

#set module path

mpath="/usr/lib/x86_64-linux-gnu/opensips/modules/"

#### SIGNALING module

loadmodule "signaling.so"

#### StateLess module

loadmodule "sl.so"

#### Transaction Module

loadmodule "tm.so"

modparam("tm", "fr_timeout", 5)

modparam("tm", "fr_inv_timeout", 30)

modparam("tm", "restart_fr_on_each_reply", 0)

modparam("tm", "onreply_avp_mode", 1)

#### Record Route Module

loadmodule "rr.so"

/* do not append from tag to the RR (no need for this script) */

modparam("rr", "append_fromtag", 0)

#### MAX ForWarD module

loadmodule "maxfwd.so"

#### SIP MSG OPerationS module

loadmodule "sipmsgops.so"

#### FIFO Management Interface

loadmodule "mi_fifo.so"

modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")

modparam("mi_fifo", "fifo_mode", 0666)

#### MYSQL module

loadmodule "db_mysql.so"

#### HTTPD module

loadmodule "httpd.so"

modparam("httpd", "port", 8888)

 

#### USeR LOCation module

loadmodule "usrloc.so"

modparam("usrloc", "nat_bflag", "NAT")

modparam("usrloc", "working_mode_preset", "single-instance-sql-write-back")

modparam("usrloc", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### REGISTRAR module

loadmodule "registrar.so"

modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")

modparam("registrar", "received_avp", "$avp(received_nh)")

/* uncomment the next line not to allow more than 10 contacts per AOR */

#modparam("registrar", "max_contacts", 10)

#### ACCounting module

loadmodule "acc.so"

/* what special events should be accounted ? */

modparam("acc", "early_media", 0)

modparam("acc", "report_cancels", 0)

/* by default we do not adjust the direct of the sequential requests.

   if you enable this parameter, be sure to enable "append_fromtag"

   in "rr" module */

modparam("acc", "detect_direction", 0)

modparam("acc", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### AUTHentication modules

loadmodule "auth.so"

loadmodule "auth_db.so"

modparam("auth_db", "calculate_ha1", yes)

modparam("auth_db", "password_column", "password")

modparam("auth_db", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

 

modparam("auth_db", "load_credentials", "")

#### ALIAS module

loadmodule "alias_db.so"

modparam("alias_db", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### DOMAIN module

loadmodule "domain.so"

modparam("domain", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

modparam("domain", "db_mode", 1)

modparam("auth_db|usrloc", "use_domain", 1)

#### PRESENCE modules

loadmodule "xcap.so"

loadmodule "presence.so"

loadmodule "presence_xml.so"

modparam("xcap|presence", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

modparam("presence_xml", "force_active", 1)

modparam("presence", "fallback2db", 0)

#### DIALOG module

loadmodule "dialog.so"

modparam("dialog", "dlg_match_mode", 1)

modparam("dialog", "default_timeout", 21600)

modparam("dialog", "db_mode", 2)

modparam("dialog", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### NAT modules

loadmodule "nathelper.so"

modparam("nathelper", "natping_interval", 10)

modparam("nathelper", "ping_nated_only", 1)

modparam("nathelper", "sipping_bflag", "SIP_PING_FLAG")

 

modparam("nathelper", "sipping_from", "sip:pinger@127.0.0.1")

modparam("nathelper", "received_avp", "$avp(received_nh)")

loadmodule "rtpproxy.so"

modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:12221")

#### DIALPLAN module

loadmodule "dialplan.so"

modparam("dialplan", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### DYNAMMIC ROUTING module

loadmodule "drouting.so"

modparam("drouting", "db_url",

        "mysql://opensips:opensipsrw@localhost/opensips")

#### MI_HTTP module

loadmodule "mi_http.so"

loadmodule "mi_html.so"

modparam("mi_html", "root", "opensips_mi")

 

loadmodule "proto_udp.so"

##############################

####### Routing Logic ########

##############################

# main request routing logic

route {

        # initial NAT handling; detect if the request comes from behind a NAT

        # and apply contact fixing

        force_rport();

        if (nat_uac_test("private-contact,diff-ip-src-via,private-via,diff-port-src-via")) {

                if (is_method("REGISTER")) {

                        fix_nated_register();

                        setbflag("NAT");

                } else {

                        fix_nated_contact();

                        setflag("NAT");

                }

        }

 

        if (!mf_process_maxfwd_header(10)) {

                send_reply(483,"Too Many Hops");

                exit;

        }

 

        if (has_totag()) {

 

                # handle hop-by-hop ACK (no routing required)

                if ( is_method("ACK") && t_check_trans() ) {

                        t_relay();

                        exit;

                }

 

 

                # sequential request within a dialog should

               # take the path determined by record-routing

                if ( !loose_route() ) {

                        if (is_method("SUBSCRIBE") && is_myself("$rd")) {

                                # in-dialog subscribe requests

                                route(handle_presence);

                                exit;

                        }

                        # we do record-routing for all our traffic, so we should not

                        # receive any sequential requests without Route hdr.

                        send_reply(404,"Not here");

                        exit;

                }

                # validate the sequential request against dialog

                if ( $DLG_status!=NULL && !validate_dialog() ) {

                        xlog("In-Dialog $rm from $si (callid=$ci) is not valid according to dialog\n");

                        ## exit;

                }

                if (is_method("BYE")) {

                        # do accounting even if the transaction fails

                        do_accounting("db","failed");

                }

                if (check_route_param("nat=yes"))

                        setflag("NAT");

                # route it out to whatever destination was set by loose_route()

                # in $du (destination URI).

                route(relay);

                exit;

        }

 

        # CANCEL processing

        if (is_method("CANCEL")) {

                if (t_check_trans())

                        t_relay();

                exit;

        }

 

        # absorb retransmissions, but do not create transaction

        t_check_trans();

 

        if ( !(is_method("REGISTER")  || is_from_gw() ) ) {

 

                if (is_from_local()) {

                        # authenticate if from local subscriber

                        # authenticate all initial non-REGISTER request that pretend to be

                        # generated by local subscriber (domain from FROM URI is local)

                        if (!proxy_authorize("", "subscriber")) {

                                proxy_challenge("", "auth");

                                exit;

                        }

                        if ($au!=$fU) {

                                send_reply(403,"Forbidden auth ID");

                                exit;

                        }

 

                        consume_credentials();

                        # caller authenticated

 

                } else {

                        # if caller is not local, then called number must be local

 

                        if (!is_uri_host_local()) {

                                send_reply(403,"Relay Forbidden");

                                exit;

                        }

 

                }

        }

 

        # preloaded route checking

        if (loose_route()) {

                xlog("L_ERR",

                        "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");

                if (!is_method("ACK"))

                        send_reply(403,"Preload Route denied");

                exit;

        }

 

        # record routing

        if (!is_method("REGISTER|MESSAGE"))

                record_route();

 

        # account only INVITEs

        if (is_method("INVITE")) {

 

                # create dialog with timeout

                if ( !create_dialog("B") ) {

                        send_reply(500,"Internal Server Error");

                        exit;

                }

 

                do_accounting("db");

        }

        if (!is_uri_host_local()) {

                append_hf("P-hint: outbound\r\n");

 

                route(relay);

 

        }

        # requests for my domain

        if( is_method("PUBLISH|SUBSCRIBE"))

                        route(handle_presence);

 

        if (is_method("REGISTER")) {

                # authenticate the REGISTER requests

                if (!www_authorize("", "subscriber")) {

                        www_challenge("", "auth");

                        exit;

                }

 

                if ($au!=$tU) {

                        send_reply(403,"Forbidden auth ID");

                        exit;

                }               if (isflagset("NAT")) {

                        setbflag("SIP_PING_FLAG");

                }

                # store the registration and generate a SIP reply

                if (!save("location"))

                        xlog("failed to register AoR $tu\n");

 

                exit;

        }

 

        if ($rU==NULL) {

                # request with no Username in RURI

                send_reply(484,"Address Incomplete");

                exit;

        }

        # apply DB based aliases

 

        alias_db_lookup("dbaliases");

        # apply transformations from dialplan table

        dp_translate( 0, "$rU", $rU);

 

 

        if ($rU=~"^\+[1-9][0-9]+$") {

 

                strip(1);

                if (!do_routing(0)) {

                        send_reply(500,"No PSTN Route found");

                        exit;

                }

 

                route(relay);

                exit;

        }

 

 

        # do lookup with method filtering

        if (!lookup("location", "method-filtering")) {

                if (!db_does_uri_exist("$ru","subscriber")) {

                        send_reply(420,"Bad Extension");

                        exit;

                }

 

                # redirect to a different VM system

                $du = "sip:192.168.100.201:5062";

                xlog("method filtering");

                route(relay);

 

        }

 

        if (isbflagset("NAT")) setflag("NAT");

 

        # when routing via usrloc, log the missed calls also

 

        do_accounting("db","missed");

        route(relay);

 

}

route[relay] {

        # for INVITEs enable some additional helper routes

        if (is_method("INVITE")) {

 

                if (isflagset("NAT") && has_body("application/sdp")) {

                        rtpproxy_offer("ro");

                }

                t_on_branch("per_branch_ops");

                t_on_reply("handle_nat");

                t_on_failure("missed_call");

        }

 

        if (isflagset("NAT")) {

                add_rr_param(";nat=yes");

        }

 

        if (!t_relay()) {

                send_reply(500,"Internal Error");

        }

        exit;

}

# Presence route

route[handle_presence] {

        if (!t_newtran()) {

                sl_reply_error();

                exit;

        }

 

        if(is_method("PUBLISH")) {

                handle_publish();

        } else

        if( is_method("SUBSCRIBE")) {

                handle_subscribe();

        }

 

        exit;

}

branch_route[per_branch_ops] {

        xlog("new branch at $ru\n");

}

onreply_route[handle_nat] {

        if (nat_uac_test("private-contact"))

                fix_nated_contact();

        if ( isflagset("NAT") && has_body("application/sdp") )

                rtpproxy_answer("ro");

        xlog("incoming reply\n");

 

}       

 

failure_route[missed_call] {

        if (t_was_cancelled()) {

                exit;

        }

        # uncomment the following lines if you want to block client

        # redirect based on 3xx replies.

        ##if (t_check_status("3[0-9][0-9]")) {

        ##t_reply(404,"Not found");

        ##      exit;

        ##}

        # redirect the failed to a different VM system

        if (t_check_status("486|408")) {

                # $du = "sip:127.0.0.2:5060";

                # do not set the missed call flag again

                # route(relay);

                route(vm);

        }

}

local_route {

        if (is_method("BYE") && $DLG_dir=="UPSTREAM") {

 

                acc_db_request("200 Dialog Timeout", "acc");

 

        }

}

route[vm] {

        # check if one calling himself

        xlog("i am here");

        if ($fU==$rU) {

           exit;

        }

        sethostport("192.168.100.201:5062");

        t_relay();

        exit;

}

 

5. Start OpenSIPS

#systemctl start opensips

#systemctl status opensips

 

 

ขั้นตอนถัดไป add domain โดย access mariadb

#mysql -uroot -pXXXXX

MariaDB [(none)]> use opensips;

MariaDB [opensips]> insert into domain values(1,'192.168.100.200','first domain',NOW());

MariaDB [opensips]> exit

ใช้ opensips-cli reload domain และ และเพิ่ม users

#opensips-cli

Welcome to my CLI!

(cli)

(cli): mi domain_reload

"OK"

(cli): mi domain_dump

{

    "Domains": [

        {

            "name": "192.168.100.200"

        }

    ]

 

}

แสดงว่าเราเพิ่ม domain สำเร็จแล้ว ขั้นตอนต่อไป คือ การเพิ่ม users

(cli): user add This email address is being protected from spambots. You need JavaScript enabled to view it. pass123456

(cli): user add This email address is being protected from spambots. You need JavaScript enabled to view it. pass123456

 

6. ทดสอบการใช้งาน

ใช้ ip phone หรือ soft phone 2 ตัว register มาที่ OpenSIPS server โดยใช้ user 3000 password pass123456 และ

user 3001 password pass123456 เมื่อ register เรียบร้อย ลองโทรหากัน ถ้าโทรหากันได้

ก็ถือว่าการติดตั้งคอนฟิกในเบื้องต้นเสร็จเรียบร้อยแล้ว

 

7. คำสั่งอื่นๆ

#systemctl start opensips

#systemctl stop opensips

#systemctl restart opensips

#ps -ef | grep opensips