<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dockerizing Asterisk with ODBC.]]></title><description><![CDATA[Dockerizing Asterisk with ODBC.]]></description><link>https://asterisk-odbc.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 07:45:56 GMT</lastBuildDate><atom:link href="https://asterisk-odbc.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Dockerizing Asterisk with ODBC configurations: A Scalable VoIP Setup for the Modern Era]]></title><description><![CDATA[Over the past months, I’ve spent a lot of time setting up Asterisk manually on traditional Linux servers — command by command. From installing libraries, compiling Asterisk from source, managing dependencies, to configuring files one at a time… I’ve ...]]></description><link>https://asterisk-odbc.hashnode.dev/dockerizing-asterisk-with-odbc-configurations-a-scalable-voip-setup-for-the-modern-era</link><guid isPermaLink="true">https://asterisk-odbc.hashnode.dev/dockerizing-asterisk-with-odbc-configurations-a-scalable-voip-setup-for-the-modern-era</guid><category><![CDATA[Asterisk PBX]]></category><category><![CDATA[asterisk]]></category><category><![CDATA[odbc]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[voip]]></category><category><![CDATA[WebRTC]]></category><dc:creator><![CDATA[Aakash Pradhan]]></dc:creator><pubDate>Fri, 19 Sep 2025 18:15:00 GMT</pubDate><content:encoded><![CDATA[<p>Over the past months, I’ve spent a lot of time setting up Asterisk manually on traditional Linux servers — <strong>command by command</strong>. From installing libraries, compiling Asterisk from source, managing dependencies, to configuring files one at a time… I’ve done it all on the kernel level.</p>
<p>It worked — but it was repetitive, fragile, and hard to replicate in new environments.</p>
<p>That’s what led me to this.</p>
<p>I decided to <strong>containerize Asterisk using Docker</strong> — not just to make it easier for myself, but for anyone who wants a <strong>clean, repeatable VoIP setup</strong>. And let me be clear: just containerizing Asterisk isn’t enough.</p>
<p>To make this production-ready, <strong>ODBC integration with PostgreSQL is crucial</strong>. That’s why I’ve documented this process in detail — for those who are truly keen to understand how to build a modern Asterisk environment that talks to a real database.</p>
<p>Let’s dive into how it’s done.</p>
<h2 id="heading-why-containerize-asterisk"><strong>Why Containerize Asterisk?</strong></h2>
<p>When you’re setting up Asterisk on bare metal, every misstep can break the system. Dependencies mismatch. Configurations get overwritten. Permissions cause silent failures.</p>
<p>Containerizing solves all that:</p>
<p><strong>a. Reproducibility across systems</strong><br />b. <strong>Faster rebuilds and upgrades</strong><br /><strong>c. Isolation from the host OS</strong><br /><strong>d. Data persistence via Docker volumes</strong><br /><strong>e. Portability and ease of testing</strong></p>
<h2 id="heading-building-asterisk-with-docker"><strong>Building Asterisk with Docker</strong></h2>
<p>The <code>Dockerfile</code> is where the magic starts. It uses a base Debian image and installs all dependencies including:</p>
<ul>
<li><p>Asterisk build tools</p>
</li>
<li><p>PostgreSQL ODBC driver</p>
</li>
<li><p>Core libraries like <code>libjansson</code>, <code>libxml2</code>, <code>libedit</code>, <code>libssl</code></p>
</li>
</ul>
<pre><code class="lang-yaml"><span class="hljs-string">FROM</span> <span class="hljs-string">debian:bullseye</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">apt-get</span> <span class="hljs-string">update</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">apt-get</span> <span class="hljs-string">install</span> <span class="hljs-string">-y</span> <span class="hljs-string">\</span>
  <span class="hljs-string">build-essential</span> <span class="hljs-string">git</span> <span class="hljs-string">wget</span> <span class="hljs-string">\</span>
  <span class="hljs-string">unixodbc</span> <span class="hljs-string">unixodbc-dev</span> <span class="hljs-string">odbc-postgresql</span> <span class="hljs-string">libpq-dev</span>
</code></pre>
<p>Then fetch and build Asterisk from source:</p>
<pre><code class="lang-yaml"><span class="hljs-string">RUN</span> <span class="hljs-string">wget</span> <span class="hljs-string">http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">\</span>
    <span class="hljs-string">tar</span> <span class="hljs-string">xvfz</span> <span class="hljs-string">asterisk-18-current.tar.gz</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">\</span>
    <span class="hljs-string">cd</span> <span class="hljs-string">asterisk-18.*</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">\</span>
    <span class="hljs-string">./configure</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">\</span>
    <span class="hljs-string">make</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">make</span> <span class="hljs-string">install</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">make</span> <span class="hljs-string">samples</span>
</code></pre>
<p>Why this way? Because it gives full control over module selection and version consistency.</p>
<h2 id="heading-docker-compose-container-lifecycle-simplified"><strong>docker-compose: Container Lifecycle Simplified</strong></h2>
<p>The <code>docker-compose.yml</code> simplifies deployment and allows for persistent data:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">asterisk:</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
      <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile.ast</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"5060:5060/udp"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8088:8088/tcp"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">asterisk_configs1:/etc/asterisk</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">asterisk_logs1:/var/log/asterisk</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">asterisk_voicemail1:/var/spool/asterisk/voicemail</span>
</code></pre>
<p>With volumes mapped to key directories, even after a container is destroyed, <strong>your configs, logs, voicemails, and recordings persist</strong>.</p>
<h2 id="heading-odbc-integration-the-backbone-of-real-time-cdr"><strong>ODBC Integration: The Backbone of Real-Time CDR</strong></h2>
<p>Setting up Asterisk is just the start. <strong>Without ODBC connectivity to a database, you’re missing the real-time power of Asterisk.</strong></p>
<p>I’ve meticulously set up the ODBC layer so Asterisk can talk directly to PostgreSQL, store CDRs, and dynamically read or write configuration.</p>
<p>You need to configure:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># cat /etc/odbc.ini</span>

[<span class="hljs-string">dsn_name</span>]
<span class="hljs-string">Driver</span> <span class="hljs-string">=</span> <span class="hljs-string">PostgreSQL</span>
<span class="hljs-string">Database</span> <span class="hljs-string">=</span> <span class="hljs-string">your_db</span>
<span class="hljs-string">Servername</span> <span class="hljs-string">=</span> <span class="hljs-string">your_db_host</span>
<span class="hljs-string">Port</span> <span class="hljs-string">=</span> <span class="hljs-number">5432</span>
<span class="hljs-string">Username</span> <span class="hljs-string">=</span> <span class="hljs-string">your_user</span>
<span class="hljs-string">Password</span> <span class="hljs-string">=</span> <span class="hljs-string">your_password</span>
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-comment"># cat /etc/asterisk/res_odbc.conf</span>

[<span class="hljs-string">dsn_name</span>]
<span class="hljs-string">enabled</span> <span class="hljs-string">=&gt;</span> <span class="hljs-literal">yes</span>
<span class="hljs-string">dsn</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">dsn_name</span>
<span class="hljs-string">username</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">your_user</span>
<span class="hljs-string">password</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">your_password</span>
<span class="hljs-string">pre-connect</span> <span class="hljs-string">=&gt;</span> <span class="hljs-literal">yes</span>
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-comment"># cat /etc/odbcinst.ini</span>

[<span class="hljs-string">PostgreSQL</span>]
<span class="hljs-string">Description</span> <span class="hljs-string">=</span> <span class="hljs-string">ODBC</span> <span class="hljs-string">for</span> <span class="hljs-string">PostgreSQL</span>
<span class="hljs-string">Driver</span> <span class="hljs-string">=</span> <span class="hljs-string">/usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so</span>
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-comment"># cat /etc/asterisk/modules.conf </span>

<span class="hljs-string">load</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">res_odbc.so</span>
<span class="hljs-string">load</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">cdr_odbc.so</span>
<span class="hljs-string">load</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">func_odbc.so</span>
<span class="hljs-string">load</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">res_config_odbc.so</span>
<span class="hljs-string">load</span> <span class="hljs-string">=&gt;</span> <span class="hljs-string">chan_sip.so</span>

<span class="hljs-comment"># append these line, don't overwrite</span>
</code></pre>
<p>This ODBC setup ensures <strong>Asterisk can insert CDRs into PostgreSQL in real-time</strong>, query dynamic dialplans, and scale effortlessly with database-level access control.</p>
<h2 id="heading-validation-amp-restart"><strong>Validation &amp; Restart</strong></h2>
<p>Once everything is in place, restart and test:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># inside asterisk container</span>

<span class="hljs-string">asterisk</span> <span class="hljs-string">-rx</span> <span class="hljs-string">"core restart now"</span>
<span class="hljs-string">asterisk</span> <span class="hljs-string">-rvv</span>
<span class="hljs-string">odbc</span> <span class="hljs-string">show</span>
<span class="hljs-string">module</span> <span class="hljs-string">show</span> <span class="hljs-string">like</span> <span class="hljs-string">odbc</span>
<span class="hljs-string">sip</span> <span class="hljs-string">show</span> <span class="hljs-string">peers</span>
<span class="hljs-string">...</span>
</code></pre>
<p>Check ODBC connectivity directly with:</p>
<pre><code class="lang-yaml"><span class="hljs-string">isql</span> <span class="hljs-string">-v</span> <span class="hljs-string">dsn_name</span> <span class="hljs-string">user</span> <span class="hljs-string">'password'</span>
</code></pre>
<h2 id="heading-database-permissions-matter"><strong>Database Permissions Matter</strong></h2>
<p>For Asterisk to fully leverage the DB, the right permissions are essential:</p>
<pre><code class="lang-yaml"><span class="hljs-string">GRANT</span> <span class="hljs-string">SELECT,</span> <span class="hljs-string">INSERT,</span> <span class="hljs-string">UPDATE,</span> <span class="hljs-string">DELETE</span> <span class="hljs-string">ON</span> <span class="hljs-string">ALL</span> <span class="hljs-string">TABLES</span> <span class="hljs-string">IN</span> <span class="hljs-string">SCHEMA</span> <span class="hljs-string">public</span> <span class="hljs-string">TO</span> <span class="hljs-string">your_user;</span>
<span class="hljs-string">ALTER</span> <span class="hljs-string">DEFAULT</span> <span class="hljs-string">PRIVILEGES</span> <span class="hljs-string">IN</span> <span class="hljs-string">SCHEMA</span> <span class="hljs-string">public</span> <span class="hljs-string">GRANT</span> <span class="hljs-string">SELECT,</span> <span class="hljs-string">INSERT,</span> <span class="hljs-string">UPDATE,</span> <span class="hljs-string">DELETE</span> <span class="hljs-string">ON</span> <span class="hljs-string">TABLES</span> <span class="hljs-string">TO</span> <span class="hljs-string">your_user;</span>
</code></pre>
<p>These permissions ensure <strong>CDRs log correctly, and future tables remain accessible</strong>.</p>
<h2 id="heading-wrapping-up-from-kernel-to-containers"><strong>Wrapping Up: From Kernel to Containers</strong></h2>
<p>Coming from a background of setting up Asterisk the traditional way — <strong>command by command on bare metal</strong> — this shift to Docker has been powerful.</p>
<p>I’ve experienced firsthand how painful it is to debug missing modules, broken libraries, and permission issues. This containerized approach eliminates all of that.</p>
<p>Now, with <strong>Asterisk in a Docker container + ODBC to PostgreSQL</strong>, I can:</p>
<ul>
<li><p>Deploy with one command</p>
</li>
<li><p>Scale easily</p>
</li>
<li><p>Rebuild or replicate the entire setup instantly</p>
</li>
</ul>
<p>If you’re serious about Asterisk or VoIP in general, and want a future-proof way to deploy, manage, and scale it — <strong>this is the setup you need.</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Docker didn’t containerize Asterisk; it containerized my suffering.</strong></div>
</div>]]></content:encoded></item></channel></rss>