Cisco IP Phone CP-7821(CUCMなし)で内線網を構築してみた話

はい、表題の通りやります。
今回はUbuntu Server 22.04を利用しましたが、おそらくほかの環境でも動くと思います。
  
:::note warn
免責
この記事の通りにやって確実に動くという保証はありません.
おそらくほとんどの場合これらの手順でセットアップ可能とは思いますが,
保証はできませんので、あくまで参考程度にとどめてください.

またあくまで趣味, 実験レベルに留めておいた方が賢明でしょう.
実務で使用する場合は素直にCiscoと契約を結びましょう.
:::

:::note warn
注意
- CUCMを利用しない場合, 一部の機能が利用できません.
- 本記事はある程度ネットワークなどの前提知識がある方を対象としています.
:::

# 必要なもの(物理)
- Cisco IP Phone CP-7821
- LANケーブル
- 電源ケーブル(PoE環境では不要)
- サーバー

# 必要なもの(ソフト)
- Ciscoアカウント
- Ubuntu Server 22.04
- asterisk18
- お好みのTFTPサーバー

# 手順
## 1. asteriskのセットアップ
まずは一旦いつものようにasteriskをセットアップしましょう.
今回はこちらのお二方のこの記事を参考にセットアップを進めました.
この場を借りてお礼申し上げます.
- https://qiita.com/YuuT_38/items/5a418a60f2d08d8bc3cf
- https://qiita.com/xecus/items/3f816e9fa0b31e9f3c2b
### pjsip.confの設定
```conf:pjsip.conf
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
external_media_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
external_signaling_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
local_net=10.12.10.0/24

[6001]
type=endpoint
context=from-internal
allow=ulaw
auth=6001
aors=6001
rewrite_contact=yes
rtp_symmetric=yes
force_rport=yes
direct_media=yes
ice_support=no

[6001]
type=auth
auth_type=userpass
password=unsecurepassword
username=6001

[6001]
type=aor
max_contacts=10
contact=sip:6001@10.12.10.42:5060

[6002]
type=endpoint
context=from-internal
allow=ulaw
auth=6002
aors=6002
rewrite_contact=yes
rtp_symmetric=yes
force_rport=yes
direct_media=yes
ice_support=no

[6002]
type=auth
auth_type=userpass
password=unsecurepassword
username=6002

[6002]
type=aor
max_contacts=10
contact=sip:6002@10.12.10.10:5060
```
この設定は
- ネットワーク: 10.12.10.0/24
- SIPサーバー: 10.12.10.11
- CP-7821: 10.12.10.42
- SIPユーザーエージェント(ソフトフォン): 10.12.10.10
- SIP通信用ポート: 5060
を前提としています.
細かい部分を解説します.
```conf:pjsip.conf
external_media_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
external_signaling_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
local_net=10.12.10.0/24 ; Asteriskサーバーと通信するネットワーク
```
これは特にNAT環境にてセットアップする場合に必要となる項目です.
今回はNAT環境ではありませんが, 設定として入れています.
`local_net=10.12.10.0/24`について、もしほかのネットワークからAsteriskサーバーにアクセスする場合は追加します。

例: 192.168.1.0/24からもアクセスする場合
```conf:pjsip.conf
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
external_media_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
external_signaling_address=10.12.10.11  ; Asteriskサーバーの外部IPアドレス
local_net=10.12.10.0/24
local_net=192.168.1.0/24
```

そしてもう一か所
```conf:pjsip.conf
[6001]
type=aor
max_contacts=10
contact=sip:6001@10.12.10.42:5060
```
このcontactの部分ですが, 本来はなくてもいいはずですが記載しないと私の環境ではうまく動作しませんでした.
もしCP-7821に割り当てる予定のアドレスが`10.12.10.15`の場合は
```conf:pjsip.conf
[6001]
type=aor
max_contacts=10
contact=sip:6001@10.12.10.15:5060
```
のようにご自身のCP-7821に割り当てる予定のアドレスに書き換えてください.

### extensions.confの設定
```conf:extenstions.conf
[from-internal]
# 6001がコールされたらSIPの6001を呼び出す
exten = 6001,1,Dial(PJSIP/6001,30,r)
same = n.Hangup()

# 6001がコールされたらSIPの6001を呼び出す

exten = 6002,1,Dial(PJSIP/6002,30,r)
same = n.Hangup()
```
他にも音楽が聴ける番号や天気予報や時報をご自身で作ってみても面白いかもしれません.
ここは様々なサイトで解説されていますので, いろいろ試してみてください.

## 2. TFTPサーバーのセットアップ
今回はServaを使用しました.
もしお好みのTFTPサーバーがあればそれを使っていただいても大丈夫です.
これについては解説記事も多数ありますので, 今回は割愛します.

## 3. CP-7821のセットアップ
### 3-1. 電源投入からネットワークへの接続まで
電話機裏面に各種ポートがありますので, LANケーブルとPoE環境でない方は電源ケーブルを接続してください.
起動すると「Network Unavailable」もしくは「Phone not registered」と表示されると思います.
ダイヤルキー左上のアプリケーションボタン(設定マーク)->Admin Settings->Network Setup->IPv4 Setupと進みます.

まず, DHCPについては今回は固定IPで利用したいので無効にしてしまいます.
次にIP Addressを先ほど`pjsip.conf`で設定したものと同じものに設定します.
最初に提示した設定例の場合: `10.12.10.42`

サブネットマスクはCP-7821を接続したネットワークのものを設定します.
私の環境では: `255.255.255.0`

Default Routerは言うまでもないかもしれませんが, 原則としてそのセットワークのルータのIPアドレスを指定してください.
私の環境では: `10.12.10.1`

DNS Server 1についてもそのネットワークで利用しているDNSサーバーを指定してください.
私の環境では一つ上位のネットワークの`192.168.1.56`を指定しています.

そして少し進んで, TFTP Server 1の項目に先ほど構築したTFTPサーバーのIPアドレスを指定します.
私の環境では: `10.12.10.1`

以上の設定が終わったら設定を保存します.

### CP-7821のコンフィグを準備
続いてTFTPサーバー上に設置するコンフィグファイルを準備します.
この手順でCP-7821のMacアドレスが必要になりますので, 
アプリケーション(設定ボタン)->Admin Settings->Network Setup->Host Name
の部分に表示されているMacアドレスを控えておいてください.
(もし何らかの方法でHost Nameを書き換えている場合はアプリケーション->Phone Information内のMacアドレスを控えてください.)

それではTFTPサーバーのルートディレクトリ(/home/shared/tftp/など, TFTPサーバー上のルートディレクトリ)に`SEP[Macアドレスから:を抜いたもの].cnf.xml`というファイルを作成します.
先ほどの手順でHost Nameを控えた方はそのまま`SEP[先ほど控えたもの].cnf.xml`で大丈夫です.
※[]は不要です. 例: `SEP0057D2D19500.cnf.xml`

```xml:SEP[MACAddress].cnf.xml
<device>
    <deviceProtocol>SIP</deviceProtocol>
    <sshUserId>120</sshUserId>
    <sshPassword>phone120</sshPassword>
    <devicePool>
        <dateTimeSetting>
            <dateTemplate>M/D/YY</dateTemplate>
            <timeZone>Tokyo Standard Time</timeZone>
            <ntps>
                <ntp>
                    <name>pool.ntp.org</name>
                    <ntpMode>Unicast</ntpMode>
                </ntp>
            </ntps>
        </dateTimeSetting>
        <callManagerGroup>
            <members>
                <member priority="0">
                    <callManager>
                        <ports>
                            <sipPort>5060</sipPort>
                            <securedSipPort>5061</securedSipPort>
                        </ports>
                        <processNodeName>10.12.10.11</processNodeName>
                    </callManager>
                </member>
            </members>
        </callManagerGroup>
    </devicePool>
    <sipProfile>
        <sipProxies>
            <backupProxy></backupProxy>
            <backupProxyPort>5060</backupProxyPort>
            <emergencyProxy></emergencyProxy>
            <emergencyProxyPort></emergencyProxyPort>
            <outboundProxy></outboundProxy>
            <outboundProxyPort></outboundProxyPort>
            <registerWithProxy>true</registerWithProxy>
        </sipProxies>
        <sipCallFeatures>
            <cnfJoinEnabled>true</cnfJoinEnabled>
            <callForwardURI>x-serviceuri-cfwdall</callForwardURI>
            <callPickupURI>x-cisco-serviceuri-pickup</callPickupURI>
            <callPickupListURI>x-cisco-serviceuri-opickup</callPickupListURI>
            <callPickupGroupURI>x-cisco-serviceuri-gpickup</callPickupGroupURI>
            <meetMeServiceURI>x-cisco-serviceuri-meetme</meetMeServiceURI>
            <abbreviatedDialURI>x-cisco-serviceuri-abbrdial</abbreviatedDialURI>
            <rfc2543Hold>false</rfc2543Hold>
            <callHoldRingback>2</callHoldRingback>
            <localCfwdEnable>true</localCfwdEnable>
            <semiAttendedTransfer>true</semiAttendedTransfer>
            <anonymousCallBlock>2</anonymousCallBlock>
            <callerIdBlocking>2</callerIdBlocking>
            <dndControl>0</dndControl>
            <remoteCcEnable>true</remoteCcEnable>
        </sipCallFeatures>
        <sipStack>
            <sipInviteRetx>6</sipInviteRetx>
            <sipRetx>10</sipRetx>
            <timerInviteExpires>180</timerInviteExpires>
            <timerRegisterExpires>3600</timerRegisterExpires>
            <timerRegisterDelta>5</timerRegisterDelta>
            <timerKeepAliveExpires>120</timerKeepAliveExpires>
            <timerSubscribeExpires>120</timerSubscribeExpires>
            <timerSubscribeDelta>5</timerSubscribeDelta>
            <timerT1>500</timerT1>
            <timerT2>4000</timerT2>
            <maxRedirects>70</maxRedirects>
            <remotePartyID>false</remotePartyID>
            <userInfo>None</userInfo>
        </sipStack>
        <autoAnswerTimer>1</autoAnswerTimer>
        <autoAnswerAltBehavior>false</autoAnswerAltBehavior>
        <autoAnswerOverride>true</autoAnswerOverride>
        <transferOnhookEnabled>false</transferOnhookEnabled>
        <enableVad>false</enableVad>
        <dtmfAvtPayload>101</dtmfAvtPayload>
        <dtmfDbLevel>3</dtmfDbLevel>
        <dtmfOutofBand>avt</dtmfOutofBand>
        <alwaysUsePrimeLine>false</alwaysUsePrimeLine>
        <alwaysUsePrimeLineVoiceMail>false</alwaysUsePrimeLineVoiceMail>
        <kpml>3</kpml>
        <phoneLabel>SVROOM</phoneLabel>
        <stutterMsgWaiting>1</stutterMsgWaiting>
        <callStats>false</callStats>
        <silentPeriodBetweenCallWaitingBursts>10</silentPeriodBetweenCallWaitingBursts>
        <disableLocalSpeedDialConfig>false</disableLocalSpeedDialConfig>
        <sipLines>
    <line button="1">
        <featureID>9</featureID>
        <featureLabel>6001</featureLabel>
        <proxy>10.12.10.11</proxy>
        <port>5060</port>
        <name>6001</name>
        <displayName>6001</displayName>
        <authName>6001</authName>
        <authPassword>unsecurepassword</authPassword>
    </line>
</sipLines>
        <voipControlPort>5060</voipControlPort>
        <startMediaPort>10000</startMediaPort>
        <stopMediaPort>20000</stopMediaPort>
        <dscpForAudio>184</dscpForAudio>
        <ringSettingBusyStationPolicy>0</ringSettingBusyStationPolicy>
        <dialTemplate>dialplan.xml</dialTemplate>
        <softKeyFile></softKeyFile>
    </sipProfile>
    <commonProfile>
        <phonePassword></phonePassword>
        <backgroundImageAccess>true</backgroundImageAccess>
        <callLogBlfEnabled>2</callLogBlfEnabled>
    </commonProfile>
    <loadInformation>sip78xx.14-2-1-0201-40</loadInformation>
    <vendorConfig>
        <disableSpeaker>false</disableSpeaker>
        <disableSpeakerAndHeadset>false</disableSpeakerAndHeadset>
        <pcPort>0</pcPort>
        <settingsAccess>1</settingsAccess>
        <garp>0</garp>
        <voiceVlanAccess>0</voiceVlanAccess>
        <videoCapability>0</videoCapability>
        <autoSelectLineEnable>0</autoSelectLineEnable>
        <webAccess>0</webAccess>
        <SSHAccess>0</SSHAccess>
        <daysDisplayNotActive>1,2,3,4,5,6,7</daysDisplayNotActive>
        <displayOnTime>00:00</displayOnTime>
        <displayOnDuration>00:00</displayOnDuration>
        <displayIdleTimeout>00:30</displayIdleTimeout>
        <spanToPCPort>1</spanToPCPort>
        <loggingDisplay>1</loggingDisplay>
        <loadServer></loadServer>
    </vendorConfig>
    <userLocale>
        <name></name>
        <uid></uid>
        <langCode>ja_JP</langCode>
        <version>1.0.0.0-1</version>
        <winCharSet>iso-8859-1</winCharSet>
    </userLocale>
    <networkLocale></networkLocale>
    <networkLocaleInfo>
        <name></name>
        <uid></uid>
        <version>1.0.0.0-1</version>
    </networkLocaleInfo>
    <deviceSecurityMode>1</deviceSecurityMode>
    <authenticationURL></authenticationURL>
    <directoryURL></directoryURL>
    <servicesURL></servicesURL>
    <idleURL></idleURL>
    <informationURL></informationURL>
    <messagesURL></messagesURL>
    <proxyServerURL></proxyServerURL>
    <dscpForSCCPPhoneConfig>96</dscpForSCCPPhoneConfig>
    <dscpForSCCPPhoneServices>0</dscpForSCCPPhoneServices>
    <dscpForCm2Dvce>96</dscpForCm2Dvce>
    <transportLayerProtocol>2</transportLayerProtocol>
    <capfAuthMode>0</capfAuthMode>
    <capfList>
        <capf>
            <phonePort>3804</phonePort>
        </capf>
    </capfList>
    <phoneServices useHTTPS="false">
        <provisioning>2</provisioning>
        <phoneService type="1" category="0">
            <name>Missed Calls</name>
            <url>Application:Cisco/MissedCalls</url>
            <vendor />
            <version />
        </phoneService>
        <phoneService type="1" category="0">
            <name>Received Calls</name>
            <url>Application:Cisco/ReceivedCalls</url>
            <vendor />
            <version />
        </phoneService>
        <phoneService type="1" category="0">
            <name>Placed Calls</name>
            <url>Application:Cisco/PlacedCalls</url>
            <vendor />
            <version />
        </phoneService>
        <phoneService type="2" category="0">
            <name>Voicemail</name>
            <url>Application:Cisco/Voicemail</url>
            <vendor />
            <version />
        </phoneService>
    </phoneServices>
    <certHash></certHash>
    <encrConfig>false</encrConfig>
</device>
```
はい, 長いです.
変更が必要な場所を一か所ずつ設定していきましょう.
```xml:SEP[MACAddress].cnf.xml
                <member priority="0">
                    <callManager>
                        <ports>
                            <sipPort>5060</sipPort>
                            <securedSipPort>5061</securedSipPort>
                        </ports>
                        <processNodeName>10.12.10.11</processNodeName>
                    </callManager>
                </member>
```
ここのsipPortとprosessNodeNameをSIPサーバーのものに設定します.

```xml:SEP[MACAddress].cnf.xml
        <sipProxies>
            <backupProxy></backupProxy>
            <backupProxyPort>5060</backupProxyPort>
            <emergencyProxy></emergencyProxy>
            <emergencyProxyPort></emergencyProxyPort>
            <outboundProxy></outboundProxy>
            <outboundProxyPort></outboundProxyPort>
            <registerWithProxy>true</registerWithProxy>
        </sipProxies>
```
backupProxyPortをSIPサーバーのものに変更します.

`<phoneLabel>SVROOM</phoneLabel>`を任意の値に設定します.
この値は無事にセットアップが終わればCP-7821のホーム画面の右上に表示されます.

```xml:SEP[MACAddress].cnf.xml
        <sipLines>
    <line button="1">
        <featureID>9</featureID>
        <featureLabel>6001</featureLabel>
        <proxy>10.12.10.11</proxy>
        <port>5060</port>
        <name>6001</name>
        <displayName>6001</displayName>
        <authName>6001</authName>
        <authPassword>unsecurepassword</authPassword>
    </line>
</sipLines>
```
ここをSIPサーバーで設定したものに書き換えます.

```xml:SEP[MACAddress].cnf.xml
        <voipControlPort>5060</voipControlPort>
        <startMediaPort>10000</startMediaPort>
        <stopMediaPort>20000</stopMediaPort>
```
ここをそれぞれ適切な値に設定します.

また, 今回はUDPにてSIPサーバーをセットアップしましたが, TCP, TLS環境ではそれぞれ以下のように書き換えてください.
TCP: `<transportLayerProtocol>1</transportLayerProtocol>`
TLS: `<transportLayerProtocol>3</transportLayerProtocol>`

コンフィグはこれで以上です.

構文ミスや不用意に値を変えると, 正しく設定できなかったりなんやかんやします.
もしうまく設定がうまくいった後にコンフィグをいじる場合は必ず元のコンフィグをバックアップしておきましょう.

## CP-7821をアップデート
このコンフィグは最新版にアップデートする前提で作成されています.
そのためCP-7821をアップデートしましょう.

まずはファームウェアをダウンロードしましょう.
- https://software.cisco.com/download/home/284892535/type/282074288/release/14.2(1)SR2
二つ項目がありますが, 下の firmware files only の方をダウンロード, ダウンロードしたファイルを展開してTFTPサーバーのルートディレクトリ(さっき説明しましたね?)に設置します.

暫くたってアプリケーション(設定ボタン)->Phone Information->Active Loadの下あたりに[Update in progress]的な表記が出て, その後Active Loadがsip78xx.14-2-1-0201-40のような表記になっていれば完了です.

あとは再起動してしばらく経てばセットアップが完了するはず...です!

# まとめ
全く日本語の記事がなかったということで, 自分がうまくいった手順をわかる範囲で列挙してみましたが, ほかの環境でこの手順でうまくいくかどうか全くの未知数ですし, ほかに試されている方も今のところお見かけしたことがないため正直なところ何もわからないというのが本音です.

ただ, 全く情報がないよりは駄文でも存在した方が解決の糸口になるかと思い, 記事にまとめました.
参考になれば幸いです.
助けになるかわかりませんが, 万が一ご質問があればお気軽にどうぞ!

Twitter(現: X): https://twitter.com/mlr4i
Facebook: https://www.facebook.com/m1r4i

# トラブルシューティングのすゝめ
2024年6月14日 追記

ネットワークになんとか接続さえできれば電話機のログをリモートで確認できるようになります.
コンフィグのどこが間違っているのか, あるいはSIPサーバーへの登録ができていないのかなど,
トラブルシューティングに大いに役立ちますので, 情報を追記します.

ブラウザにて
`http://[IP電話機のIPアドレス]/CGI/Java/Serviceability?adapter=device.statistics.consolelog`
にアクセスし messagesをクリックすると現在のログが表示されます.

:::note warn
**注意**
電話機を再起動して上記URLにアクセスしたあと`messages`をクリックしないとログが生成されないようですので, 再起動後などは`http://[IP電話機のIPアドレス]/FS/messages`に直接アクセスせず上記URLに戻ってから再度`messages`をクリックしてください.
:::