Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
OwnPBX는 서버를 개인 전화 시스템으로 바꾸는 무료 오픈소스 소프트웨어, 통화·메시지·음성사서함·푸시투톡 제공
OwnPBX is free, open-source software that turns a server you control into a private phone system: calls, messages, voicemail and push-to-talk between your own users, free. Add a VoIP provider for real
소셜Python · KotlinGitHub @DanversKara온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Personal Custom OwnPBX from Scratch using Asterisk as the backbone with working auto updating ANDROID APP sms, calls, voicemail, settings and push to talk
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A self-hosted home/hobby phone system (Asterisk 22 + Kamailio). Published as-is for anyone curious; not actively supported. Forks welcome. Untested 911 - see below.
A home / hobby PBX: a self-hosted phone system for enthusiasts who want to run their own phones at home and learn how it all works. Plain Asterisk 22 does the calling, a small Python service makes every call decision, a clean web panel runs the whole thing, and a separate Kamailio + rtpengine edge box is the only part that faces the internet.
No third-party GUI, no module store, no phoning home. Free software, GPL-2.0-or-later.
⚠️ Project status - please read
Why I Made This I’ve tried a lot of different PBX systems, and while many of them are great, I always found myself running into the same problem: they either had too many features I didn’t need, were missing features I actually wanted, or put certain features behind expensive premium plans.
Sometimes I would find a PBX that had a few of the features I wanted, but other useful features were locked behind a paid plan. Then I’d try another PBX that offered those features for free, only to find that it was missing something else I wanted.
Eventually, I decided to stop looking and build my own.
This project started as a hobby PBX built around the features I personally wanted. The goal isn’t to compete with every major PBX system or include every feature imaginable. Instead, I want to build something that is:
Simple and easy to understand Focused on useful features instead of unnecessary extras Free from unnecessary premium feature restrictions Customizable and easy to expand Built around the features that actually matter to me The project is still a work in progress, and I’ll be adding new features and improving existing ones over time.
Is It Perfect? No. This is a hobby project, and there will probably be bugs, missing features, and things that could be done better.
Is It Secure? Security is something I take seriously, but I’m also realistic about where this project is right now. Use it at your own risk, especially in production or on systems exposed to the internet.
I’ll continue testing, fixing issues, and improving security as the project develops.
At the end of the day, this project is about building the PBX I wanted to use from the beginning and learning along the way.
It’s a work in progress, and I’m looking forward to seeing where it goes.
- Hobby project, not a business product. own-pbx is built and tested as a home/hobby PBX. It is not intended or certified for business, commercial, multi-tenant, carrier or life-safety use. It comes with no warranty; you use it entirely at your own risk (see
LICENSE).- Only tested with VoIP.ms. VoIP.ms is the only SIP trunk provider it has been tested with. Other providers may need changes.
- 911 / E911 has NOT been tested. The 911 features exist but have not been tested end to end. Do not rely on this system to call 911. Always keep another way to reach emergency services (a mobile phone or landline).
- Stripe billing has not been tested with real payments.
- You are responsible for your provider's terms, call-recording consent and any laws that apply where you live.
Published as-is. I'm sharing this for anyone curious. It is not actively supported: I won't be answering questions, fixing issues or taking feature requests. You're welcome to fork it and adapt it however you like, under the GPL-2.0-or-later license.
All screenshots use made-up demo data (names like "Front Desk" are just examples).
Calling
Phones anywhere
Panels
Messaging
Safety and security
Plans / billing (optional, untested with real payments)
Internet
│
TCP 5061 (TLS) + UDP 20000-20099 (SRTP audio)
│
┌──────▼───────┐ Router forwards ONLY these to the edge.
│ Edge server │ Kamailio (SIP proxy) + rtpengine (audio relay)
│ 192.168.1.11 │ fail2ban, flood limit, TLS certificate
└──────┬───────┘
│ plain SIP/RTP on your LAN
┌──────▼───────┐
Office phones ─► PBX server │ Asterisk 22 (calls, audio, voicemail)
(UDP 5060) │ 192.168.1.10 │ pbx-brain (Python: every call decision)
│ │ pbx-agi (Python: text )
│ │ pbx-api (Python: web panel, port 8001)
└──────────────┘ SQLite database /var/lib/pbx/pbx.db
│
SIP trunk provider (outbound registration)
pjsip.conf) whenever you change users or trunks.Ports at a glance:
| Where | Port | What | Who can reach it |
|---|---|---|---|
| PBX | 5060 UDP/TCP | SIP for office phones and the edge | your LAN only |
| PBX | 8001 TCP | web panel (admin + My Phone) | your LAN (optionally My Phone via a tunnel, see section 16) |
| PBX | 8088, 8099, 4573 | Asterisk API, brain status, text handler | the PBX itself only (127.0.0.1) |
| Edge | 5061 TCP | SIP over TLS for outside phones | internet |
| Edge | 20000-20099 UDP | call audio (SRTP) | internet |
| Edge | 5060 UDP | SIP to and from the PBX | your LAN only |
| Edge | 22 TCP | SSH | your LAN only |
nesting=1: pct set <ID> --features nesting=1.sip.example.com),
ideally on Cloudflare for automatic DNS updates and certificates, and a
router where you can forward ports.On the PBX machine, as root:
apt-get update && apt-get install -y unzip git
# copy the project here (git clone, or upload the zip and unzip it), then:
cd /root/own-pbx
# 1. One-time install: builds Asterisk 22 from source (10-20 minutes),
# creates the pbx service user, folders and Python environments.
./scripts/install.sh
# 2. Deploy: database, Asterisk configs, services.
./scripts/deploy.sh
Updating later: one command, as root on the PBX:
pbx-update
It downloads the latest code (the project folder must be a git clone),
re-deploys the PBX, and, only if the edge files changed, copies kamailio/
to the edge box and runs update-edge.sh there. The first time the edge needs
updating it asks for the edge's address and remembers it. pbx-update --edge
updates the edge even when nothing in it changed.
When you log in to the PBX as root (SSH or console), it checks GitHub (at
most once an hour) and tells you if there is an update to install. It never
installs anything by itself: an update restarts the phone services and would
drop calls in progress, so you choose when to run pbx-update.
At the end of the first deploy you are asked to create the admin login (at least 12 characters). Then open the panel from a computer on your network:
http://<PBX-IP>:8001
Check that everything runs:
systemctl status asterisk pbx-brain pbx-api pbx-agi --no-pager
asterisk -rx "pjsip show endpoints"
./scripts/security-check.sh
Lost the admin password? On the PBX run
/opt/pbx/api-venv/bin/python /root/own-pbx/scripts/create-admin.py. It
resets the password of an existing login, or creates a new admin.
Skip this section if all your phones are at home (on your own network).
5.1 Create the machine. For example, a Proxmox LXC on the host:
pct create 200 local:vztmpl/<debian-13-standard template>.tar.zst \
--hostname kamailio-edge --cores 1 --memory 1024 --rootfs local-lvm:8 \
--net0 name=eth0,bridge=vmbr0,ip=192.168.1.11/24,gw=192.168.1.1 \
--features nesting=1 --unprivileged 1
pct start 200
pct enter 200 # then: passwd (set a root password)
5.2 Copy the kamailio/ folder to the edge box, e.g. /root/kamailio,
and install:
cd /root/kamailio
chmod +x *.sh pbx-edge-notify
PUBLIC_HOST=sip.example.com ASTERISK_IP=192.168.1.10 ./install.sh
(If you leave the two values out, the installer asks for them.) This installs:
5.3 Get a real certificate (with your domain on Cloudflare):
CF_Token=<Cloudflare API token with Zone → DNS → Edit> \
./get-cert-cloudflare.sh sip.example.com [email protected]
The certificate renews itself.
5.4 Connect security alerts to the PBX. In the admin panel go to API Keys,
create a key called edge, then on the edge box:
pbx-edge-notify --setup http://192.168.1.10:8001 <the API key>
5.5 Check everything:
./verify-edge.sh
./security-check.sh
All checks should pass.
Later updates of the edge: copy the new kamailio/ folder over and run
./update-edge.sh. It keeps your IPs and domain, and rolls back by itself if
the new config doesn't start.
Router port forwards go to the edge server, never to the PBX:
| Protocol | External port | Internal IP | Internal port |
|---|---|---|---|
| TCP | 5061 | 192.168.1.11 (edge) | 5061 |
| UDP | 20000-20099 | 192.168.1.11 (edge) | 20000-20099 |
Don't forward 5060, 8001 or 22.
DNS: sip.example.com → your public IP, as a plain A record. On Cloudflare
it must be DNS only (grey cloud): Cloudflare's proxy can't carry phone calls.
Changing public IP? Admin → Network: add the domain and a Cloudflare API token and turn on automatic updates. The PBX updates the DNS record, and the edge's timer updates the edge itself.
Do these in order:
ulaw,alaw,g722). Check with asterisk -rx "pjsip show registrations",
which should say Registered.1NXXNXXXXXX, NXXNXXXXXX and 011..Every user can see their own phone settings in My Phone → Settings → Phone setup.
| Setting | In the office | Away from the office |
|---|---|---|
| Server / domain | PBX IP, e.g. 192.168.1.10 | sip.example.com |
| Port | 5060 | 5061 |
| Transport | UDP | TLS |
| Outbound proxy | (none) | sip.example.com:5061 |
| Media encryption | off | SRTP (SDES) |
| Username / auth name | extension number, e.g. 8800 | same |
| Password | the extension's SIP password | same |
| Re-register | default | every 60-120 seconds |
Zoiper on a mobile phone (away): account → domain sip.example.com,
transport TLS, outbound proxy sip.example.com:5061. Under Advanced →
Encryption choose SRTP (SDES), not ZRTP. Android and iOS can close a
background app's connection, so allow Zoiper to run in the background (or use
push), or incoming calls go to voicemail.
Desk phones: set Proxy, Registrar and Outbound proxy to the PBX IP, port
5060, transport UDP, and turn SRTP off on the LAN. If you use "dial 9 for an
outside line", update the phone's dial plan (e.g. 9xxxxxxxxxx).
Check it: the phone appears under Dashboard → Signed in now as Online, showing whether it's internal or external.
Android: instead of (or as well as) Zoiper, users can use the
My Phone app. It sets up its own phone login
with one tap and signs in on the extension's separate app line
(<username>-app), so it rings together with the desk phone or Zoiper
without replacing them.
Admin pages only open on your home network (the panel calls it the "office network"): someone coming in through the internet gets My Phone only, and the admin menu is hidden. That can be changed under Network, but it isn't recommended.
Users are extensions: username, panel password, extension number, SIP username and password, display name, notification email, admin recording (see section 13) and enabled. Disabling a login signs it out everywhere at once.
Onboard new users without handing out passwords: Invites → Generate invite picks the next free extension, auto-generates the SIP username/secret, and gives you a single-use link — shown once, copy it or email it straight to the user (SMTP must be set up under Email). The link expires after 1–30 days (your choice), dies after one use, and can be revoked anytime. The recipient opens it, picks their own login password, and enters display name + voicemail email; the login is created on the spot. Tokens are 256-bit and stored hashed, so a database read alone can't mint accounts. The generator also picks the account type — normal or guest (below) — and the guest rules it starts with.
A guest extension is a restricted account type for courtesy, lobby or visitor phones. Internal calling — other extensions, feature codes, internally dialed ring groups — always works. Everything that reaches outside the PBX is off unless the admin turns that one thing on for that guest:
billing). Free plans never
convert an account, and guests never upgrade on their own.Set the type when creating a login or generating an invite, or convert an existing account either way under Logins → Edit — the account, its extension and its history are kept; the change takes effect immediately. Guest rules are hard caps on top of plans: a plan can never grant a guest something its guest rules leave off.
Your SIP provider(s): registrar, username, secret and codecs.
Turn on Routes → (a number) → Detect faxes. Calls to that number are then answered at once and the caller hears ringing while the PBX listens for a fax machine's tone (3-8 seconds, 4 by default). A fax is received (G.711, or T.38 when the provider offers it), turned into a PDF and:
Anything that isn't a fax carries on exactly as before (ring, menu, cells, voicemail). It works with an ordinary voip.ms DID. If the helper service is down, calls skip the listening and ring normally.
One-time setup: Asterisk needs fax support (spandsp). New installs have it.
On an existing PBX run pbx-update --with-fax when the phones are quiet: it
compiles Asterisk with fax (about 10-20 minutes; calls keep working) and
restarts it once no call is in progress. The Routes and Faxes pages say if it's
still missing.
Sending faxes (My Phone → Faxes → Send a fax, or the app's Faxes tab): upload a PDF or a photo (up to 20 MB, 50 pages), enter the fax number, pick which of your numbers it comes from (numbers whose route rings you; admins can use any), and optionally add a cover page with To, Subject and a message. Faxes go out one at a time over your outbound route with a header line on each page. A busy line or no answer is tried again (3 attempts, 3 minutes apart). The Sent list shows waiting / sending / will retry / sent / failed, and the sender is emailed the result. Answered time counts toward the plan's outside minutes (30 faxes a day per user at most).
Fax is a plan feature (Billing → plan → Fax, like push-to-talk): new accounts have it off; plans that include it turn it on, and you can make a per-user exception. Without it a user has no Faxes tab, can't send, and a fax number that only rings them isn't listened on. Admins always can.
Branding: under Faxes → Fax branding set the PBX's logo (turned into crisp fax black & white), logo text / company name, address, phone, email, website, a footer notice (e.g. confidentiality) and the header line printed on every page; Preview cover page shows exactly what's sent. Tick Let users use their own branding and each user can set theirs under My Phone → Faxes → My fax branding. With nothing set the cover page is plain (no PBX name on it).
In the app: a Faxes tab appears for anyone a fax number rings or who can send faxes: received and sent faxes, an in-app viewer (zoom, share, open in another app), a new-fax notification, and the send form above.
Billing → App store mode (or Logins → Edit → Hide plans & billing in the My Phone app): for all users or the ones you tick, the app shows no plan, usage, texts/minutes left, prices or "not in your plan" wording. Settings shows "For account details, visit " (plain text) and unavailable features say "This isn't available on your account." The PBX enforces it as well; plans and limits still apply, and the web portal is unchanged.
Calls to the group's internal number aren't billed.
Company menus with a greeting (upload WAV/MP3) and key options: ring an extension, ring several extensions, voicemail, another menu, repeat, or hang up. Also controls how many personal menus users may build.
Call records (kept 90 days), every voicemail, every recording and every text, with select / delete all. The Recordings page also holds the recording settings (see section 13).
A public sign-up page at https://<your panel>/store: new customers pick a
plan (and, optionally, a phone number from the ones you list for sale), then
enter their card on Stripe's own checkout page. Nobody is charged and
nothing is created until you approve the order on Admin → Store:
New orders are emailed to you (or the security alert address). The form has a bot trap, a time-limited signed token and the same per-address rate limits as sign-in; only one order per email can wait at a time. A number is offered only while nothing else answers it. The admin page is office-network only; the public page works through your tunnel. Needs Stripe keys and published plans (Billing) and SMTP (Email) for the customer emails.
Stripe keys, plans and User access (defaults for users without a plan, plus per-user exceptions). A plan also lists the star codes it includes (see section 11). See section 14.
SMTP settings, a test email, the panel address used in email links, and Security alerts: who gets them, and for what (blocked IPs, sign-in lockouts, kill switch / lock / E911 / recording changes, user reports). Every 911 call is always emailed.
Remote-access domain and TLS port, office server address, Cloudflare dynamic DNS (status, IP history), and panel access from the internet.
Single sign-on for the web panel through an OpenID Connect provider you
already run (Authentik, Keycloak, Authelia…). The login page gets a
Sign in with … button above the password form. Options: go straight to
the provider, or hide the password form (/login?password=1 always brings it
back, so a provider that is down never locks you out).
Accounts aren't created by sign-on: add the login (with its extension) first. The first sign-in links it by username (the provider's username is the PBX login name) or by email (the login's notification email, optionally only if the provider verified it); after that it stays linked to that provider account until you unlink it. Admin pages stay office-network only, and admins can be kept to password sign-in. The My Phone app is not affected.
In Authentik: create an OAuth2/OpenID provider (Confidential), set the
redirect URI shown on the page (https://<your panel>/login/oidc/callback),
create an application for it, then copy the client ID, client secret and
OpenID Configuration Issuer into Admin → Sign-on.
See section 12.
Calls and texts that users reported from My Phone. Mark them resolved, reopen or delete them. To stop someone, disable their login.
Bearer tokens for the REST API (docs/API.md) and for the edge's security
alerts. A key is shown only once; revoke it any time.
White-label the panel: site name, header logo (upload or URL, shown as text, logo, or both) with an optional separate dark-mode logo that auto-swaps with the theme, header and button colors with one-click presets (Ocean, Sunset, Royal…), an animated gradient header option, default dark/light theme (visitors can flip it with the 🌙/☀️ icon; their choice sticks in the browser), login page logo/title/subtitle (also with a dark-mode variant), favicon, and an optional footer line. Logos are stored in the database, so they ride along with backups.
Regional: time zone selector (defaults to Los Angeles); all call, message, voicemail and recording times display in 12-hour format in that zone.
Every user signs in at http://<PBX-IP>:8001 (or your published address,
see section 16) with their panel username and password.
| Page | What it does |
|---|---|
| Overview | phone status, Do Not Disturb, new voicemail, missed calls, where 911 sends help, plan usage, recent calls |
| Calls | 90-day history (can't be deleted), recordings, Block and Report for each call |
| Voicemail | listen, download, move, delete; greeting upload or record by phone (*98) |
| Recordings | the user's own recordings |
| Messages | conversations, send a text to any extension (including Zoiper and other SIP apps), Block, Report; updates by itself. ESP32 devices can make calls too, see the ESP32-S3-Box-3 project |
| IVR | personal menus (if their plan allows) |
| Billing | choose, switch or cancel a plan (Stripe) |
| App | pair the Android app: Get a pairing code shows a QR code, tap-to-copy code and server, and an Open in the My Phone app button; Show phone login QR gives the app its phone login; see and sign out signed-in phones |
| Settings | DND, forwarding, ring time, answer with IVR, "Record my calls" (with legal acknowledgement), notification email, text emails on/off, receive/send texts on/off, call filtering (block list: per number choose "not in service", straight to voicemail, or forward to another number), 911 notice, phone setup, SIP password, panel password |
A free, open-source Android app (GPL-2.0-or-later; the built-in phone engine, Linphone, is GPL-3.0) for every user. No ads, no tracking, no Google Play Services or Firebase. Android 8.0 or newer.
Tap a screenshot to see it full size.
Screenshots from app 0.5; newer versions add the dial pad, Call buttons and the Notifications and Calling settings.
| Screen | What it does |
|---|---|
| Messages | inbox with search and unread dots, swipe or multi-select delete with Undo, Start chat to any extension or number, copy, block, call |
| Calls | All / Missed / Hidden (hide calls instead of deleting; they go after 90 days with the rest), call back, text, block, dial pad; the missed-call badge clears when you look |
| Voicemail | New / Old, player with seek bar and 1x / 1.5x / 2x, call back, text, move, block, delete |
| Settings | the same switches as My Phone, plus Notifications, Calling and App security |
Get it: GitHub Actions → Android app → latest green run →
Artifacts → my-phone-debug-apk, unzip, and open the .apk on the phone.
Connect: the easiest way is Sign in with my browser in the app: it
opens My Phone in an in-app browser tab, you sign in there (password or single
sign-on), and the phone connects by itself (/ucp/app/connect makes the
pairing code and hands it back; the app only auto-connects for the sign-in it
started). Or, in My Phone (web) open App → Get a pairing code, then in the
app tap Scan QR code (or scan with the phone's camera, tap Open in the My
Phone app on the phone itself, or type the code). The app never sees the
panel password; each phone stays signed in for 60 days after it was last used.
Calls: in the app, Settings → Calling → Phone login → Get from my PBX →
Save. Calls go through the edge like a remote Zoiper (TLS 5061, SRTP). For
incoming calls the app signs in on the extension's app line,
<sip_username>-app (created for every extension, same password and caller
ID), never on the main line, so desk phones and Zoiper stay signed in; the PBX
rings the app line together with the main line and the first answer wins.
The app rings with the phone's ringtone, full screen, over the lock screen;
Settings → Calling → Incoming calls turns it off. Needs the remote-access
domain under Admin → Network.
Notifications: new texts, missed calls and voicemail, with a count on the app icon. Settings → Notifications → Check for new things: Instant (the app stays connected and the PBX answers within seconds; Android shows a small "My Phone is connected" notification), every 30 s, 1 min or 5 min, or every 15 min to save battery. If Android's battery saver pauses the app, use Let it run in the background.
Missed calls notify with who called and when ("Missed call · (555) 123-4567 · 2:14 PM"), including calls that rolled to voicemail. If the app rang and nobody answered, it notifies the moment the ringing stops; a call picked up on another phone doesn't count. If the phone was offline and never rang, the notification comes as soon as it reaches the PBX again, with the time of each call.
PIN lock: 6 or 12 digits, optional fingerprint, lock immediately or after 1 / 5 / 15 minutes away (even if Android closed the app in between), screens hidden from screenshots (switchable). Coming back through the PIN keeps your place. An incoming call shows over the PIN.
For the admin: nothing to configure; pbx-update adds the app API
(/api/v1/app/*, /api/v1/me/*, documented in docs/API.md), its tables and
the segno package for QR codes. No new ports: the app uses the published
My Phone address (section 16) and the existing edge. More detail in
android/README.md.
| Dial | What it does |
|---|---|
911 (also 9911/prefix + 911) | Emergency call. Always connects (see section 12). |
933 | Address test line at many providers: reads back your E911 address |
*97 | Check your voicemail |
*98 | Record your voicemail greeting |
*60 | Join the conference room |
*555<ext> | Monitor an extension's calls: stays on the line, auto-follows new calls (admins only by default) |
*555 | Scan mode: listen to any active call on the system |
*70 | DISA: outside dial tone after a PIN (only if a PIN has been configured) |
*86 (during a call) | Block the caller: press it mid-call on a call someone made to you. The call ends, the caller hears "the number you have dialed is not in service", and their number goes on your block list. Only keys from your own phone count; the caller pressing *86 does nothing |
| ring group or IVR number | Ring that group or menu |
While monitoring (*555), press * / 1 for the previous call and # / 2
for the next call. A beep confirms each hop. Hang up to stop monitoring.
The Features page in the admin panel controls every star code: turn each
one on/off for the whole system, set the default access (By plan, All
users, Admins only, or No one), and override per user with
Allow/Deny. For example, you can give *555 (ChanSpy) to a supervisor without
making them a full admin, or disable *70 (DISA) entirely. Each user's row
shows whether they can use the code right now, and why.
By plan (the default for every code except *555, which is admins only):
a new account starts with no star codes. A user gets a code when their
active plan includes it (Billing → plan → Star codes included); it goes
off again if the plan lapses or changes. Without a plan they get the
Star codes (no plan) set under Billing → User access, empty by
default; tick *97/*98 there if you don't sell plans and want everyone to
reach their voicemail. Admins can always use every code, and a per-user
Allow/Deny always wins. Users who existed before this change kept the codes
they had (an Allow override each); set them back to Default to hand them to
their plan.
⚠️ NOT TESTED. The 911/E911 features below have not been tested end to end. Do not rely on own-pbx for emergency calls. Keep a mobile phone or landline available, and if you use these features, test them yourself (e.g. with your provider's 933 test line) and confirm the address with your provider.
911 always connects. US 911 rules (Kari's Law and RAY BAUM's Act) don't allow a phone system to block 911. Every phone can dial 911, including users without E911, users with no plan, phones on DND, phones outside the office, and while the safety lock is on.
The address 911 gets comes from your provider, not this panel. It's the address registered there for the caller-ID number the call is sent with:
The E911 page is locked with a separate 6-12 digit code. Unlock it for 10 minutes to make changes. Wrong codes are limited and alerted, and every change is logged and emailed.
Every 911 call shows on the dashboard and is emailed straight away, with who called, which address was used, and whether the phone was outside the office.
Users are warned in My Phone which address 911 will send help to, and that it doesn't follow the phone.
Test every phone by dialing 933 if your provider offers it.
Lost E911 code: sqlite3 /var/lib/pbx/pbx.db "DELETE FROM kv_settings WHERE key='e911_code_hash'",
then set a new one.
This system helps you route 911 correctly but you are responsible for registering accurate addresses with your provider and for meeting the 911 rules that apply to you. This is not legal advice.
Recording calls without everyone's consent is illegal in some places ("two-party" or all-party consent states such as California, and other countries), and can break workplace or union rules.
Optional, and not tested with real payments - only use Stripe's test mode unless you have tested it yourself. Most home users don't need billing at all: just give people access under Billing → User access.
What a plan sets: monthly outside minutes, voicemail, texts per month, recording, and the number of IVR menus.
No plan: users can only call other extensions. Admins are never limited.
Setting it up:
https://<your-public-panel>/stripe/webhook. Copy the signing
secret.Overriding plans: Billing → User access sets defaults for users
without a plan, and per-user exceptions such as unlimited minutes for a
lobby phone.
Without Stripe: just use User access to give people what they need.
Network design: only the edge faces the internet, and only on TLS port 5061 plus the audio ports. The PBX has no ports forwarded to it at all.
Edge server:
Panel:
Server hardening:
Emergency tools: the kill switch, the safety lock, and per-user block lists and reports.
Check regularly:
scripts/security-check.sh on both servers. It reports pending security
updates, open ports, SSH settings, permissions and vulnerable Python
packages.apt-get update && apt-get upgrade.To let users reach My Phone from anywhere, publish the panel through
Cloudflare Tunnel (optionally behind Nginx Proxy Manager), e.g.
https://myphone.example.com → http://<PBX-IP>:8001. Then:
http://<PBX-IP>:8001 at the office.sip.example.com stays a
grey-cloud A record.PBX: run pbx-update (gets the latest code from GitHub and deploys it),
or replace /root/own-pbx with the new version and run
./scripts/deploy.sh. Database changes, new Python packages and the phone
config (pjsip.conf) are applied automatically, and your data and settings
stay.
Android app: install the newest APK from Actions → Android app over
the old one. After an app update, run pbx-update too: new app features
often need the matching PBX side.
Edge: copy the new kamailio/ folder to /root/kamailio, then run
./update-edge.sh.
| Data | Kept for |
|---|---|
| Sign-in log | 24 hours |
| Security events in the Activity feed | 24 hours (the change log itself is kept, including recording-consent records) |
| Call history | 90 days (users can't delete it) |
| Voicemail, recordings, texts | until deleted |
Backups: back up /var/lib/pbx/ (database, greetings), /var/spool/pbx/
(voicemail, recordings) and /etc/pbx/.
Logs:
journalctl -u pbx-brain -u pbx-api -u pbx-agiasterisk -rvvvjournalctl -u kamailio -u rtpengine -u fail2ban| Problem | Check |
|---|---|
| Phone won't register | Dashboard → Recent sign-ins and Activity; asterisk -rx "pjsip show endpoints"; on the edge fail2ban-client status kamailio-edge (unban with fail2ban-client unban <ip>) |
| Outside calls fail | User has outside minutes (Billing → User access)? Outbound route matches? asterisk -rx "pjsip show registrations" says Registered? journalctl -u pbx-brain shows outbound ... via trunk? |
| Incoming calls skip someone | They need outside minutes; check journalctl -u pbx-brain | grep skipped |
| Remote phone: no audio | Router forwards UDP 20000-20099 to the edge; the phone uses SRTP (SDES); ./verify-edge.sh |
| Remote phone: "SDP mismatch" when answering | Set the phone's media encryption to SRTP (SDES) |
| Remote phone never rings | Zoiper killed in the background (phone settings / push); the edge config is current (./update-edge.sh) |
| Hang-up doesn't end the call on the other side | The edge config is current; the certificate matches sip.example.com |
| Calls drop after an IP change | systemctl status pbx-edge-ip.timer on the edge; Network page shows "In sync" |
| No emails | Email page → Send test; port 587 or 465 (many ISPs block 25) |
| Can't open admin pages | Use http://<PBX-IP>:8001 from the office network, not the published address |
| Android app: "doesn't support the app yet", or "Not Found" | The PBX is older than the app: pbx-update |
| Android app: no notifications | App Settings → Notifications → Send a test notification; Let it run in the background → Allow; the line under Check now shows the last check |
| Android app: calls fail | Settings → Calling → Phone login → Get from my PBX → Save; "Remote calling isn't set up" = set the domain under Admin → Network; Copy details on the call screen gives the SIP code |
pbx-api/ web panel + REST API (FastAPI)
app.py admin pages, auth, sessions, dashboard, v1 API,
voip.ms SMS webhook + inbound poller, /sms-routes admin UI
voipms_sms.py voip.ms helper: sendSMS/sendMMS, getSMS/getMMS polling,
DID normalization, route lookups
ucp.py My Phone
app_api.py JSON API for the Android app: pairing / QR, notifications
long poll (/me/wait), phone login (/me/sip), hidden calls
ring_groups_ui.py, ivr_ui.py, billing.py, e911_ui.py, email_ui.py,
network_ui.py, safety_ui.py, security.py, ddns.py, entitlements.py, mailer.py
pbx-brain/ call engine (ARI) - app.py, e911.py, agi_server.py (texts,
incl. external SMS/MMS via voip.ms API), voipms_sms.py (shared helper)
config-gen/ renders Asterisk pjsip.conf from the database; static Asterisk configs
db/ schema.sql (applied on every deploy), prod-seed.sql (example)
scripts/ install.sh, deploy.sh, create-admin.py, security-check.sh,
systemd units, privileged helper scripts
kamailio/ edge server: install.sh, update-edge.sh, kamailio.cfg.template,
rtpengine.conf.template, fail2ban/, certificate + IP scripts,
verify-edge.sh, pbx-edge-notify
android/ My Phone app for Android (Kotlin, Jetpack Compose, Linphone);
built by GitHub Actions (.github/workflows/android.yml)
dev/ developer and test tools (not needed to run own-pbx),
incl. test-app-*.py and test-brain-ring.py
docs/ API.md (REST API), SCREENSHOTS.md (all screenshots), screenshots/
(screenshots/android/ for the app), ANDROID_APP_PLAN.md,
VOIPMS_SMS_SETUP.md (voip.ms SMS/MMS setup and troubleshooting)
On the PBX:
/opt/pbx/var/lib/pbx (database pbx.db, greetings)/var/spool/pbx/etc/pbx/ari.passOn the edge:
/etc/kamailio/etc/rtpengine/etc/fail2ban/jail.d/etc/pbx-edge/notify.envNeed a VoIP provider? Here is a voip.ms referral link to get your own account — reasonable plans that work with this project.
Your voip.ms DIDs can send and receive real SMS/MMS, routed to your extensions. Each DID maps to one extension: inbound texts go to that extension's Zoiper (SIP MESSAGE), My Phone conversation, and any ESP/HA device polling the inbox. Replies and new outbound texts go out through the voip.ms API from the mapped DID.
Inbound — two paths, no lost messages:
https://<your-panel>/hooks/voipms-sms with to, from, message, id, date.
The PBX checks the token, dedupes by message ID, looks up the DID route,
stores the message, and pushes it to Zoiper via SIP MESSAGE.getSMS/getMMS per routed
DID and ingests anything the webhook missed. Same dedupe table, so nothing
is ever delivered twice. Webhook = instant, poll = source of truth.Outbound:
+15551234567 (or 15551234567) as a SIP MESSAGE
destination. The [pbx-msg] dialplan hands it to the AGI, which detects
the external number and sends it via voip.ms sendSMS from the DID mapped
to your extension. The API call runs in the background, so Zoiper gets its
reply immediately even if voip.ms is slow.POST http://<pbx>:8099/messages/send with
{"to": "+1555...", "from": "8801", "body": "..."} — external numbers
route out through voip.ms automatically; GET /messages/inbox?ext=8801
reads the thread.MMS: voip.ms callbacks carry no media, so inbound MMS is enriched via the
getMMS API (webhook) or picked up by the poller. Pictures arrive as
[MMS: <link>] entries — tappable in Zoiper, My Phone and ESP.
Sender DID selection (outbound): replies go out from the DID the conversation is already on (each message records its DID), so a thread stays on one number even when several DIDs route to the same extension. For a brand-new conversation: the DID whose route points at your extension, else the configured default DID, else the first route.
https://<panel>/hooks/voipms-sms?token=...&to={TO}&from={FROM}&message={MESSAGE}&id={ID}&date={TIMESTAMP}),
choose E.164 number format, turn on callback retry, Apply.Details, troubleshooting and the ESP API shapes: docs/VOIPMS_SMS_SETUP.md.
own-pbx is free software under the GNU General Public License, version 2 or
(at your option) any later version (LICENSE). Asterisk, Kamailio,
rtpengine and the other programs it uses are installed separately and keep
their own licenses. See THIRD_PARTY.md.
own-pbx is a home / hobby project, tested only with the VoIP.ms trunk, and
its 911/E911 features have not been tested. It comes with no warranty
of any kind (see LICENSE, sections 11-12). It is not intended for business,
commercial or life-safety use. You are responsible for how you use it,
including 911, your provider's terms, call-recording consent and the laws
that apply where you live.
| Android app doesn't ring | The line under Settings → Calling → Incoming calls must say Signed in; the phone login must end in -app (Get from my PBX); asterisk -rx "pjsip show contacts" | grep -- -app |