Medo's Home Page https://medo64.com/ A personal website dedicated to technology, software development, and practical tools. en Processing Data on CAPsMAN https://medo64.com/posts/processing-data-on-capsman <p><a href="https://medo64.com/posts/processing-data-on-capsman/mikrotik-on-capsman.webp"><img src="https://medo64.com/posts/processing-data-on-capsman/mikrotik-on-capsman.small.webp" class="inline right" alt="Illustration" width="320" height="261"></a></p><p>As I was going over <a href="https://www.youtube.com/watch?v=5MtgE54BOGA">changelog for Mikrotik’s RouterOS 7.21</a>, I noticed the new functionality: “On CAPsMAN Data Processing”. Well, when I say new, it’s actually the functionality that was available on 6.x and earlier. However, with RouterOS 7.x it was gone. Since I used it, I did try to resist as long as I could but eventually I had to cry myself through RouterOS 7 upgrade.</p><p>But, let’s rewind a bit. What this feature actually allows? For this we need to understand how “normally” CAPsMAN on Mikrotik processed wireless traffic.</p><p>CAPsMAN is a way for Mikrotik to allow centralized control over multiple wireless devices. In my example, than meant controlleing two different access points from my (non-wireless) router. When doing so, you do essentially all configuration on router (CAPsMAN) and wireless devices (CAPs) get their configuration automatically updated to match. CAP devices essentially become just fancy wireless switches without much logic outside of (admittedly quite a few) customizations.</p><p>As switches, that means that anything on the same medium, i.e. wireless network, gets to communicate with each other. Of course, you can isolate users of networks but there is no real way to centrally allow some users to communicate with others or not. I am lying a bit here - you can always setup local firewall rules for stuff happening between networks but it gets annoying to keep config on multiple devices. I mean, CAPSman was there to centralize config, not to leave us in the same mess we were in before.</p><p>If you were willing to sacrifice some speed, RouterOS 6.x allowed you to redirect ALL wireless traffic to your CAPsMAN. This ensured your router sees each packet and thus you get to use firewall on your router. Even for devices connected on the same network on the same access-point. This made configuration really centralized.</p><p>But, those more familiar with enterprise setups might tell I am doing it wrong. And yes, this is not a feature for places where you want complete isolation and control. This is more of a control-light approach.</p><p>In enterprise networks, guest network will be completely isolated - usually using VLANs. And it should be. In my network, I will isolate guest network using firewall. And that is way less secure as you’re always one error away from complete mess. But, for home network where even guests are reasonably trusted, it is a small price to pay for flexibility. For example, allowing guests to access rest of home computers for the purpose of a local LAN game becomes trivial.</p><p>This is not a feature for professionals and strict environments. But it simplifies home network design a lot. And finally, RouterOS 7 line brings that feature back.</p> Sat, 14 Mar 2026 17:00:00 PDT Josip Medved https://medo64.com/posts/processing-data-on-capsman Sudo Can Asterisk https://medo64.com/posts/sudo-can-asterisk <p>With sudo tool getting its Rust variant, it was bound sooner or later to have an incompatibility that is in the eye of the beholder. That dubious honor fell onto <code>pwfeedback</code> setting.</p><p>Most complete reporting was already done by <a href="https://www.youtube.com/watch?v=VrgZijnbCZY">Brodie Robertson</a> so watch that video for details. Suffice to say, I am firmly in the camp of those who believe that the new behavior is correct. Let them have asterisk!</p><p>But, if you don’t want to wait for the bright future but you want this password echo behavior now, this is really easy to achieve.</p><pre class="language-sh"><code class="language-sh"><span class="token builtin class-name">echo</span> <span class="token string">"Defaults pwfeedback"</span> <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /etc/sudoers.d/pwfeedback <span class="token operator">></span>/dev/null <span class="token function">sudo</span> <span class="token function">chmod</span> <span class="token number">440</span> /etc/sudoers.d/pwfeedback</code></pre><p>Now you can experience the future today.</p> Sat, 07 Mar 2026 16:00:00 PST Josip Medved https://medo64.com/posts/sudo-can-asterisk Upgrading Inventree Postgres to 17 https://medo64.com/posts/upgrading-inventree-postgres-to-17 <p>Due to me moving, I haven’t really played with electronics lately. However, that was about to change. So I started <a href="https://inventree.org/">InvenTree</a>, my electronics inventory handling tool, only to be greeted by an error. The darn thing was not working because it upgraded to 1.2.x which requires Postgres 14 at minimum and I had Postgres 13. Well, I figured to just simply upgrade the database. Let the yak shaving begin!</p><p>Before I started with anything I pinned my Inventree to 1.1.12 (last version to use Postgres 13) and made backup of my docker containers and data. Then, the first stop was <a href="https://docs.inventree.org/en/latest/start/migrate/#remove-old-database-files">Inventree’s migration instructions</a>. Instructions are clearly written and I am almost positive they worked before. Unfortunately, since I procrastinated, they worked no longer. I tried a few variations but each ended in <code>transaction_timeout</code> issue.</p><pre class="language-plain"><code class="language-plain">pg_restore: error: could not execute query: ERROR: unrecognized configuration parameter "transaction_timeout"</code></pre><p>After investigating a bit, I found out that my migration from 13 to 14 might be slightly complicated by the fact Inventree dumped database using binaries for Postgres 17. Again, this wouldn’t have been an issue if I haven’t been lazy with my upgrades. However, even when I tried to go directly to 17, I ended up with the seeminly empty database. Yes, database wasn’t really empty, but does it really matter if nothing appears in UI?</p><p>So I decided to go with a different route - <a href="https://docs.inventree.org/en/latest/start/migrate/#export-data">export followed by import</a>. It just makes sense it would work. But no, restoration always resulted in issue with key duplication</p><pre class="language-plain"><code class="language-plain">psycopg.errors.UniqueViolation: duplicate key value violates unique constraint "common_inventreesetting_key_key"</code></pre><p>After messing with it for a while to no avail, I decided to do the most straightforward thing possible. Why not just dump and restore the database manually without involving Inventree? Procedure that ended up working for me was as follows:</p><ol><li>At first, I just dumped database while running Inventree 1.1.12 on top of Postgres 13.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> inventree-db pg_dump <span class="token parameter variable">-U</span> pguser inventree <span class="token operator">></span> inventree_backup.sql</code></pre><ol start="2"><li>With that out of way, I stopped the containers.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> compose down</code></pre><ol start="3"><li>Delete old database copy so we have it clean. Remember to do the backup beforehand.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">rm</span> <span class="token parameter variable">-rf</span> data/pgdb/</code></pre><ol start="4"><li><p>Edit <code>compose.yaml</code> and bump Postgres to 17</p></li><li><p>Bring up containers and let them create new database (once it is done, use <code>d</code> to &quot;detach).</p></li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> compose up</code></pre><ol start="6"><li>Stop Inventree services, in my case <code>inventree-server</code> and <code>inventree-worker</code>.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> compose stop inventree-server inventree-worker</code></pre><ol start="7"><li>Drop the database and recreate it empty.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> inventree-db psql <span class="token parameter variable">-U</span> pguser <span class="token parameter variable">-d</span> postgres <span class="token parameter variable">-c</span> <span class="token string">"DROP DATABASE inventree;"</span> <span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> inventree-db psql <span class="token parameter variable">-U</span> pguser <span class="token parameter variable">-d</span> postgres <span class="token parameter variable">-c</span> <span class="token string">"CREATE DATABASE inventree;"</span></code></pre><ol start="8"><li>Restore from backup</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-i</span> inventree-db psql <span class="token parameter variable">-U</span> pguser inventree <span class="token operator">&lt;</span> ./inventree_backup.sql</code></pre><ol start="9"><li>Start Inventree services back up.</li></ol><pre class="language-sh"><code class="language-sh"><span class="token function">docker</span> compose start inventree-server inventree-worker</code></pre><ol start="10"><li>Now upgrade 1.2.x version, in my case by setting <code>INVENTREE_TAG=stable</code> (in <code>.env</code> file)</li></ol><p>Since we kept the same version of Inventree for steps 1-9, we avoided the need to schema update. Inventree was not aware of any change and Postgres could simply upgrade its data to the version 17. Once we were at version 17, Inventree’s automatic upgrade scripts knew how to handle version bump from 1.1.12 to 1.2.3 as version 17 is supported by both.</p><p>Now, onto getting some soldering done.</p> Sat, 28 Feb 2026 16:00:00 PST Josip Medved https://medo64.com/posts/upgrading-inventree-postgres-to-17 GoAccess for Caddy https://medo64.com/posts/goaccess-for-caddy <p>My current web server setup kinda grew based on my WordPress setup years back. Due to Ansible, I can redeploy it quickly but, in reality, it’s just a bunch of stuff thrown together because I needed it at one time or other. Add to that me running multiple websites on the same server and you have a bit of a mess. First step to cut through all that mess was placing it all behind load balancer running behind docker.</p><p>I won’t go too deep into why exactly I opted for <a href="https://caddyserver.com/">Caddy</a>. I suspect <a href="https://nginx.org/">nginx</a> would do nicely. Even <a href="https://apache.org/">Apache</a> might have worked as well. But, after a bit of testing and playing with CertBot integration, I decided Caddy was best match for me.</p><p>The next step was to ensure I have some visibility into what was going on and there I found <a href="https://www.goaccess.com/">GoAccess</a>. But guides I found didn’t really work. Some had issues with log format, some had issues with web sockets, some even had issues with syntax.</p><p>After a bit of twiddling, I ended up with the following <code>compose.yaml</code>.</p><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">services</span><span class="token punctuation">:</span> <span class="token key atrule">caddy</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> caddy<span class="token punctuation">:</span>latest <span class="token key atrule">container_name</span><span class="token punctuation">:</span> caddy <span class="token key atrule">restart</span><span class="token punctuation">:</span> unless<span class="token punctuation">-</span>stopped <span class="token key atrule">cap_add</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> NET_ADMIN <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token datetime number">80:80</span> <span class="token punctuation">-</span> 443<span class="token punctuation">:</span><span class="token number">443</span> <span class="token punctuation">-</span> 443<span class="token punctuation">:</span>443/udp <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> ./config/<span class="token punctuation">:</span>/etc/caddy/ <span class="token punctuation">-</span> ./logs/<span class="token punctuation">:</span>/var/log/caddy/ <span class="token punctuation">-</span> ./stats/<span class="token punctuation">:</span>/var/www/goaccess/<span class="token punctuation">:</span>ro <span class="token key atrule">stats</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> allinurl/goaccess<span class="token punctuation">:</span>latest <span class="token key atrule">container_name</span><span class="token punctuation">:</span> stats <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> ./logs/<span class="token punctuation">:</span>/var/log/caddy/<span class="token punctuation">:</span>ro <span class="token punctuation">-</span> ./stats/<span class="token punctuation">:</span>/var/www/goaccess/ <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> 7890<span class="token punctuation">:</span><span class="token number">7890</span> <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token string">"/var/log/caddy/access.log --log-format=CADDY -o /var/www/goaccess/index.html --real-time-html --ws-url=wss://stats.example.com:443/ws --port=7890"</span></code></pre><p>Caddy setup is quite straight-forward. It will use three volumes: one for <code>config</code>, one for output <code>logs</code>, and the last one for viewing <code>stats</code> (read-only).</p><p>Stats themselves are setup similarly too, this time with only two volumes needed. Logs are read from <code>logs</code> (read-only) and the web pages are written into <code>stats</code>. Command being ran is one allowing for real-time monitoring. And that requires websocket support.</p><p>Caddy configuration would look something like this:</p><pre class="language-caddyfile"><code class="language-caddyfile">example.com { log { output file /var/log/caddy/access.log format json } respond "Hello World!" } stats.example.com { root * /var/www/goaccess file_server reverse_proxy /ws stats:7890 }</code></pre><p>And this setup will allow you to see stats as they come.</p> Sat, 21 Feb 2026 16:00:00 PST Josip Medved https://medo64.com/posts/goaccess-for-caddy In-Wall Doorbell Transformer https://medo64.com/posts/in-wall-doorbell-transformer <p><a href="https://medo64.com/posts/in-wall-doorbell-transformer/doorbell-transformer-before.webp"><img src="https://medo64.com/posts/in-wall-doorbell-transformer/doorbell-transformer-before.small.webp" class="inline right" alt="Illustration" width="224" height="320"></a></p><p>One really puzzling thing to me is how undefined location and mounting of doorbell transformer is in US dwellings. Not only that it has no specificed location but they also have no real mounting specification. Yes, it is specified in NEC they must be separated from high-voltage wires, but other than that is a free-for-all. I’ve seen 1/2&quot; hole, wall box edge screw, and free-style two-screw mounting as most common examples, but you really cannot know for sure until you open it.</p><p>For example, my transformer has a nice plate mounting for a square edge mount but the transformer itself is not mounted in. Assuming it was ever mounted properly, by the virtue of sticking out, it was eventually dislodged. And don’t let me even start about low-voltage wires just entering drywall willy-nilly.</p><p>Since I wanted to upgrade transformer anyhow, I decided to clean this up. But surprisingly, there are still no real solutions for this. Almost everything I found assumes this transformer is either hanging of the wall or hanging in the wall. It took me a while but I think I found reasonable solution for my use case.</p><p>First of all, I wanted it all enclosed in the box. Since NEC forbids high-voltage (110V in this case) wires next to low-voltage ones, I needed one box with multiple compartments. <a href="https://www.southwire.com/electrical-components/non-metallic-boxes-covers/three-gang-non-metallic-multi-mount-romex-box-55-cu-in-/p/MSBMMT3G">Southwire MSBMMT3G</a> 3-gang box is a rare one that fits my needs. AC side was not actually the problem but most of other dual voltage boxes had 1-gang for high-voltage and 1-gang for low-voltage side. This wouldn’t do in my case since my transformer was bigger than a single “gang” width and I really wanted it fully enclosed as to avoid “fell into the wall” accidents. It’s not ideal mind you since wire-clamps get in the way but it was best I’ve found.</p><p>Next task was selection of transformer. My existing one was 16 V so I opted to go with the same. Due to doorbell, I needed a rating of at least 30VA and that finally drove me toward <a href="https://www.amazon.com/gp/product/B07GND8RMQ/">Maxdot 16V 30VA</a>. It has 1/2&quot; hole mounting and it fits into my selected box with a bit of space to spare.</p><p>Since I had a 3D printer and voltage monitor display, my thoughts immediately went toward making a custom cover. One of more annoying steps needed to troubleshoot failing transformer is measuring voltage and with a voltage monitor, that would be trivial. And it would look cool.</p><p>I went as far as designing the cover and printing it out before remembering the NEC rules. Any cover must also be UL listed and certified for purpose. PLA, being both easily malleable with increasing temperature and fairly flamable is definitely not fit for the purpose. Thus, I ended up with shattered dreams and a plain 3-gang cover.</p> Sat, 14 Feb 2026 16:00:00 PST Josip Medved https://medo64.com/posts/in-wall-doorbell-transformer