<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Personal Blog</title>
        <link>https://justin.cx</link>
        <description><![CDATA[Whatever is on my mind]]></description>
        <atom:link href="https://justin.cx/rss.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>Tue, 28 Apr 2026 00:00:00 UT</lastBuildDate>
        <item>
    <title>NGINX is the best HTTP-Server</title>
    <link>https://justin.cx/posts/the-best-http-server-nginx.html</link>
    <description><![CDATA[<p>If you are a sysadmin, or have ever setup a server with a HTTP service, you will undoubtedly have used NGINX at least once in your career.</p>
<p>And not without good reason, NGINX is, by far, the best HTTP(S) server available on Linux, below I will share why I believe this, introduce you to some features you might not be familiar with.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#ngx_http_limit_req_module">Rate Limiting</a>
<ul>
<li><a href="#rate_limiting_ai-crawlers">Rate limiting AI-Crawlers</a></li>
</ul></li>
<li><a href="#reverse_proxy">Reverse Proxy</a>
<ul>
<li><a href="#load_balancing">Load Balancing</a></li>
</ul></li>
<li><a href="#other_cool_snippets">Cool snippets</a>
<ul>
<li><a href="#aggressively_rate-limit_clients_without_user-agents">Aggressively rate-limit clients without User-Agents</a></li>
<li><a href="#access-control_based_on_ip-address">Access-Control based on IP-Address</a></li>
</ul></li>
</ul>
<h2 id="rate-limiting">Rate Limiting</h2>
<p>If you are anything like me, you did not initially know that this is even a thing.</p>
<p>I used to think that implementing rate-limiting was up to the
micro/macro/whatever service that NGINX is <a href="#reverse_proxy">“managing”</a>.</p>
<p>In reality, NGINX ships with a very powerful and well-thought-out rate-limiting module by default, and it’s pretty expressive and useful when you have some tricks up your sleeve.</p>
<p>I will not cover the fundamentals here, you can find the technical details in the <a href="https://nginx.org/en/docs/http/ngx_http_limit_req_module.html">official NGINX documentation</a>.
Instead I want to introduce some more advanced useful use-cases I found for this module.</p>
<h3 id="rate-limiting-ai-crawlers">Rate limiting AI-Crawlers</h3>
<p>Lets face reality for a second. OpenAIs ChatGPT, Anthropics Claude, and Googles Gemini are here to stay.
Unfortunately for us poor system administrators, this means an unusual amount of traffic we need to deal with, for as long as the arms-race for the best possible model between these behemoths runs.</p>
<p>Fortunately for us, we can rate limit <strong><em>only</em></strong> the AI-Crawlers without restraining actual organic traffic.</p>
<p>Meet the <strong>map</strong>-directive and how we can leverage this to select only
particular user agents.
a[ai_crawlers]</p>
<div class="codeblock file" data-digits="2" data-name="nginx.conf">
  <div class="inner">
    
    <pre><code class="language-">map $http_user_agent $ai_crawlers {
    default &amp;quot;&amp;quot;;
    ~(GPTBot|ClaudeBot|anthropic-ai|Google-Extended|GoogleOther|Bytespider|CCBot|Amazonbot|FacebookBot|AppleBot-Extended|Cohere-ai) $1;
}

limit_req_zone $ai_crawlers zone=ai_zone:16m rate=1r/s;
limit_req_status 429;

server {
    location / {
        limit_req zone=ai_zone nodelay burst=5;
    }
}</code></pre>
  </div>
</div>
<p>This limits all <code>User-Agents</code> contained in the above RegExp to 1 request per second.</p>
<p>I first encountered this on <a href="https://serverfault.com/questions/639671/nginx-how-to-limit-request-rate-based-on-user-agent">StackOverflow</a> where the solutions are similar, but in my opinion not as elegant as this one.</p>
<p>The <strong><code>map</code></strong> matches against a regular expression that lists multiple strings contained within the AI-Crawler User-Agents.
By matching those strings in a capture list, we can access the string we found via the $1 capture variable, which is what we use as the value at the end of the line.</p>
<p>You could also drop the <code>$1</code> from that line in favour of something else, say <code>bad bad bot</code>.</p>
<p>If you do that, all those User-Agents evaluate to the <code>bad bad bot</code> string, which means that every client whose User-Agent evaluates to that string shares the rate-limit. I.e. Googles Gemini would share the rate-limit with Anthropic, etc.</p>
<p>The value <code>bad bad bot</code> itself doesn’t matter, this is arbitrary. I will explain shortly.</p>
<p>Let us understand what the <strong>limit_req_zone</strong> does.</p>
<p><strong>limit_req_zone</strong> defines a shared memory zone (what the workers use to communicate, the <code>zone=ai_zone:16m</code> in our example means the zone will be 16MiB in size.) into which a <strong>hashmap</strong> is placed.
The first parameter (<code>$ai_crawlers</code>, the map) serves as the key into the hashmap.</p>
<p>Lets manually unravel the logic. Say a client with the User-Agent
<code>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.3; +https://openai.com/gptbot</code>
hits our server, if we follow the <code>$ai_crawlers</code> map, we see that this User-Agent gets mapped to <strong><code>GPTBot</code></strong></p>
<p>NOTE: Actually, it maps to <code>$1</code>, but expanding that according to the capture list, it becomes <code>GPTBot</code>.</p>
<p>The request gets inserted in the the shared hashmap at <code>key(GPTBot)</code>, any further requests that match the User-Agent also get sent into that key. This limits all clients matching that string (<code>GPTBot</code>).</p>
<p>As an attentive reader, you might be concerned about the <code>default &quot;&quot;</code>, would this not mean that all User-Agents <em>not</em> matching that User-Agent also get limit to <code>1r/s</code>?
Since <code>key(&quot;&quot;)</code> will always yield the same value?</p>
<p>No. NGINX got our back, as per the documentation:</p>
<blockquote>
<p>Syntax: limit_req_zone key zone=name:size rate=rate;
Default: —
Context: http
Sets parameters for a shared memory zone that will keep states for various keys. In particular, the state stores the current number of excessive requests. The key can contain text, variables, and their combination. <strong>Requests with an empty key value are not accounted.</strong>
<a href="https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req">NGINX Documentation</a></p>
</blockquote>
<h2 id="reverse-proxy">Reverse Proxy</h2>
<p>The most widely utilised feature of NGINX is its reverse proxy capability.
How to set this up is trivial and <a href="https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/">documented</a> <a href="https://linuxvox.com/blog/setting-up-an-nginx-reverse-proxy/">in</a> <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-as-a-reverse-proxy-on-ubuntu-22-04">thousands</a> <a href="https://linuxconfig.org/how-to-setup-nginx-reverse-proxy">of</a> <a href="https://linuxconfig.org/how-to-setup-nginx-reverse-proxy">places.</a></p>
<p>But did you know about load balancing?</p>
<p>Load balancing is done by the <a href="https://nginx.org/en/docs/http/ngx_http_upstream_module.html"><code>ngx_http_upstream_module</code> module</a>, which has a handful of nifty features improving reliability of your service under pressure.</p>
<p>First of all, lets see how a basic <code>upstream</code> can look:</p>
<div class="codeblock file" data-digits="2" data-name="nginx.conf">
  <div class="inner">
    
    <pre><code class="language-">upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com  backup;
}</code></pre>
  </div>
</div>
<p>As you can see, servers can be a multitude of things.
1. UNIX sockets
<em>. External Domains/Servers
</em>. IP-Addresses</p>
<p>But each <code>server</code> can also have <code>parameters</code>, and these are where we start having fun, you can read more about all <a href="https://nginx.org/en/docs/http/ngx_http_upstream_module.html#server">possible parameters here.</a></p>
<h3 id="load-balancing">Load Balancing</h3>
<p>Within a <code>upstream</code> group, we can instruct NGINX to perform load balancing for incoming requests via directives.
There a number of them we should be aware of, by default NGINX dials our upstreams servers round-robin.</p>
<ol type="1">
<li><code>least_conn</code> Routes incoming requests to whatever server has the least amount of active connections.
<em>. <code>least_time</code> Routes incoming requests to whatever server has the shortest average response time <em>and</em> least amount of connections.
</em>. <code>ip_hash</code> Fixes incoming requests to a given upstream by the clients IP address, all requests originating from that client will end up on the same server.
_. <code>hash *key*</code> Same as <code>ip_hash</code>, but the key is freely definable, if you have read <a href="#rate_limiting_ai-crawlers">limiting AI-Crawlers</a>, same principle is applicable here. Remember that we can <strong><code>map</code></strong> lots of things!</li>
</ol>
<h2 id="other-cool-snippets">Other cool snippets</h2>
<h3 id="aggressively-rate-limit-clients-without-user-agents">Aggressively rate-limit clients without User-Agents</h3>
<p>On a production server, I noticed that an unusual amount of bad bots scanning for vulnerabilities do not send a User-Agent.</p>
<div class="codeblock file" data-digits="2" data-name="nginx.conf">
  <div class="inner">
    
    <pre><code class="language-">map $http_user_agent $ua_missing {
    &amp;quot;&amp;quot;      1;
    default 0;
}

location / {
    if ($ua_missing) {
        return 403;
    }
}</code></pre>
  </div>
</div>
<h3 id="access-control-based-on-ip-address">Access-Control based on IP-Address</h3>
<p>A colleague once asked me whether it is possible to only allow specific IPs to certain routes.</p>
<p>It is</p>
<div class="codeblock file" data-digits="2" data-name="nginx.conf">
  <div class="inner">
    
    <pre><code class="language-">location /api {
    satisfy any;
    allow     10.0.0.0/8;
    allow    127.0.0.0/8;
    allow  172.16.0.0/20;
    allow 192.168.0.0/16;
    deny all;

    # ...
}</code></pre>
  </div>
</div>]]></description>
    <pubDate>Tue, 28 Apr 2026 00:00:00 UT</pubDate>
    <guid>https://justin.cx/posts/the-best-http-server-nginx.html</guid>
    <dc:creator>Justin Andreas Lacoste</dc:creator>
</item>
<item>
    <title>Why Gentoo is awesome</title>
    <link>https://justin.cx/posts/why-gentoo.html</link>
    <description><![CDATA[<p>I’ve been running Gentoo since fall of 2025 and I want to share my thoughts about why this distribution rocks.</p>
<h2 id="what-is-gentoo">What is Gentoo</h2>
<p>To those unfamiliar, Gentoo is a Linux distribution with a unusually unique approach to package management.</p>
<p>While virtually every major distribution under the sun distributes binary packages in their package repositories, Gentoo’s package manager <a href="https://wiki.gentoo.org/wiki/Portage">portage</a> primarily distributes not binary packages, but recipes to compile the package locally on your machine.</p>
<p>With that out of the way, let’s dive in why this is better than Ubuntu, or even Arch.</p>
<h2 id="the-good">The good</h2>
<h3 id="maturity">… Maturity</h3>
<p>Gentoo is mature. Having been around since 2002, it stood against the test of time.</p>
<h3 id="source-first">… Source-first</h3>
<p>Gentoo most prominent perk is that the distribution is source-first.</p>
<p>This means is that every package, and dependency your machine needs will be compiled on your machine, with your compiler, your compiler flags, and your specific requirements (called USE-flags).</p>
<p>You might think, <em>“Why would I want to compile all my packages, that takes ages!”</em>, You aren’t wrong. A system update usually takes a few hours.
<strong><em>But</em></strong>, you get rewarded with a remarkably stable system. When I first started with Gentoo, I expected the distribution to be either rolling-release, or even bleeding-edge, but surprisingly the Gentoo team is very determined to keep systems as stable as can be.</p>
<p>They succeed at this, too. With tools like <code>eselect news read</code> which directly distributes concise, easy-to-follow, news about your installed packages directly in the terminal.</p>
<h3 id="customization">… Customization</h3>
<p>Gentoo heavily lies into customization via <code>USE flags</code>, these enable the user to only enable certain parts of software that they actually need.</p>
<p>If you read this blog post, you’re probably pretty familiar with <code>configure</code> scripts, and the general process of compiling software. If not, this following passage will probably not sound like such a great feature to you, but alas.
USE-flags in Gentoo specify what features of a package should be enabled when it is compiled.
This is directly useful to make you system slim, and prevent bloating the installation with stuff you don’t actually need.</p>
<h4 id="examples">Examples</h4>
<p><strong>PostgreSQL</strong>: For development, I need the PostgreSQL headers, and client installed on my system. Depending on the distribution, you might be forced to pull in both client and server, when you only need the client.
On Gentoo, I set the USE-flag <code>dev-db/postgresql -server</code>, with this, Portage only builds the client. The server binary is never produced.</p>
<p><strong>Waybar</strong>: Waybar has tons of modules for different purposes, <code>GPS</code>, or <code>WiFi</code>, or <code>Backlight</code>, etc. Most of which I don’t need, I am on a desktop, I don’t have WiFi, nor Backlight, nor a battery nor GPS.
Gentoo enables me to only select the parts of Waybar that I need, I don’t need to pull in <code>mpd</code> or something that I don’t want or need on my system. This directly reduces the amount of dependencies on my system, as well as the compilation times. Neat.</p>
<p><strong>Emacs</strong>: Certain features are hidden between flags. When Treesitter support first landed in Emacs 29, the (IIRC, Arch-Linux Package) didn’t have it enabled by default, and there was no way of enabling Treesitter until the packagers came around to publishing a new version with new dependencies.
Back then, I removed Emacs via <code>pacman</code> and manually compiled it to get the functionality, but then I was pinned to that point in time, unless I manually update it.
On Gentoo, I now just cherry-pick the USE-flags my Emacs installation needs, and I only get those features compiled, no need to add in X11 support, I am on Wayland.</p>
<h3 id="security">… Security</h3>
<p>Security is what Gentoo provides in a manner that Ubuntu, and consorts cannot due to their packaging philosophy.</p>
<p>If you’re familiar with tech and open-source, you have not missed the increase in <strong>supply-chain attacks</strong> in recent time. First there was the almost catastrophic <a href="https://en.wikipedia.org/wiki/XZ_Utils_backdoor"><code>libxz</code> takeover</a>, then there have been numerous attacks on the NPM ecosystem.
These are all very real threats that we need to be aware of, whether you’re a private user, or you maintain a number of servers.</p>
<p>What Gentoo offers me is peace of mind. My machine compiles the packages it needs locally plus they are pinned for long enough, that transient threats (such as the <code>libxz</code> attack) will <em>probably</em> have blown over by the time they land on my system.
Now granted, you cannot be 100% secure against supply-chain attacks, but being source-first mitigates the threat stemming from “black box” binaries.
I shiver to this day when I think about what could have been if <strong>Andres Freund</strong> hadn’t caught the <code>libxz</code> attack…</p>
<p>With binary blobs, you cannot even check what your system is running. Sure, you might go to <a href="//github.com">GitHub</a>/<a href="//freedesktop.org">FreeDesktop</a>/<a href="//codeberg.org">Whatever</a> and check the source out, but can you guarantee that the source wasn’t patched before landing on your system as a binary blob?
… Let’s paint an even darker picture, what if the packagers themselves are not even malicious, but instead were infected with a <a href="https://irreal.org/blog/?p=11754">backdoored compiler</a> by some state actor?</p>
<p>What running binary blobs means is that you are running code compiled by someone you probably do not know, with patches you have not seen, on a machine you do not trust.</p>
<p>Now, in the real world the threat from all this is rather slim.
Ubuntu, as far as I am aware, builds the core PPA in their build-farm, i.e. dedicated machines that do nothing but compile packages, already quite good.
Generally, I believe it’s save to say that commercially supported distributions such as Ubuntu or Fedora <em>should</em> carry less risk here.
Archlinux, with the AUR and its *-bin packages, carries the biggest risk. Introducing malware to uninformed users has the lowest entry burden here.</p>
<p>Now, in a perfect world, packages are compiled by in-person verified and trusted parties on strictly air-gapped machines that themselves have been produced from-source by verifiably non-backdoored compilers, where package sources are carried over via USB-Stick…</p>
<p>… Yeah, that doesn’t sound feasible.
This threat of being fed malicious software stays pervasive on any distribution, not even Gentoo is immune against this, but being source-first, Gentoo does a damn good job of minimising the threat from binaries.</p>
<h3 id="documentation">… Documentation</h3>
<p>The <a href="https://wiki.gentoo.org/wiki/Main_Page">Gentoo Wiki</a> is a <strong><em>phenomenal</em></strong>, well written, knowledge base about all aspects of your system.</p>
<p>But the real kicker are the tools distributed with the <a href="https://wiki.gentoo.org/wiki/Portage">portage</a>.</p>
<h4 id="equery">equery</h4>
<p><code>equery</code> has a long list of things it can do, but what I more often than not had to use it for are three things:</p>
<ol type="1">
<li><code>equery u app-editors/emacs</code>: shows you what USE-flags are enabled, and disabled for this package. With a short description about what the flag does if enabled.
<em>. <code>equery f app-editors/emacs</code>: lists all files installed by this package.
</em>. <code>equery b /usr/share/emacs/site-lisp</code>: does the reverse of <code>f</code>, and searches for the package that installed the given file.</li>
</ol>
<h4 id="eselect">eselect</h4>
<p><code>eselect</code> has two main use-cases.</p>
<p>One that is similar to<code>update-alternatives</code>, updating symlinks to use a particular version of Java, Rust, Lua, whatever.</p>
<p>The other is reading news, this is where Gentoo maintainers publish upcoming changes, bumping the default python version, etc.
All with documentation on what this means for you, and what you might need to do to ensure clean updates.</p>
<h2 id="the-bad">The bad</h2>
<h3 id="compile-times">… Compile times</h3>
<p>Being a source-first distribution, your machine will spend a lot of time compiling your packages, even on beefy hardware. Running an <code>emerge --update @world</code> might take a few hours (looking at you, <code>www-browser/chromium</code>)</p>
<p>Granted, this <em>can</em> be mitigated by using <code>--getbinpkg</code>, but that directly negates <a href="#the%20good">the good</a> this distribution brings.</p>
<h3 id="installation">… Installation</h3>
<p>It has only been a few months since moving to this distro, and yet I remember the installation being a pain in the ass.</p>
<p>Installing Archlinux back in the day with <code>pacstrap</code> and whatnot after coming from a GUI-based distribution was already a challenge. But the complexity of installing Gentoo does absolutely surpass that of a text-based Archlinux installation.</p>
<h3 id="conflicts">… Conflicts</h3>
<p>While updating <em>usually</em> works, when you do run into some incompatibility, it is a major pain in the ass.</p>
<p>The most painful case are updates to deep-rooted dependencies.
<code>dev-libs/boost</code> dropping a new version can delay updates until dependant packages get pushed to the new version.</p>
<p>To outline this, here is how a dependency conflict looks, when the above case occurs:</p>
<div class="codeblock shell" data-digits="2">
  <div class="shell">emerge -avuDN @world</div>
  <div class="inner">
    
    <pre><code class="language-">Calculating dependencies... done!
Dependency resolution took 12.00 s (backtrack: 0/20).


Total: 0 packages, Size of downloads: 0 KiB

WARNING: One or more updates/rebuilds have been skipped due to a dependency conflict:

x11-libs/wxGTK:3.2-gtk3

  (x11-libs/wxGTK-3.2.8.1-r2:3.2-gtk3/3.2::gentoo, ebuild scheduled for merge) USE=&amp;quot;X libnotify lzma opengl sdl spell tiff wayland -curl -debug -doc -gstreamer -keyring (-pch) -test -webkit&amp;quot; ABI_X86=&amp;quot;(64) -32 (-x32)&amp;quot; conflicts with
    &amp;gt;=x11-libs/wxGTK-3.2.7:3.2-gtk3=[gstreamer,libnotify,opengl,sdl,tiff,X] required by (dev-python/wxpython-4.2.4:4.0/4.0::gentoo, installed) USE=&amp;quot;-debug -test -webkit&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; PYTHON_TARGETS=&amp;quot;python3_13 -python3_11 -python3_12 -python3_14&amp;quot;
                                     ^^^^^^^^^                             
    &amp;gt;=x11-libs/wxGTK-3.2.7:3.2-gtk3/3.2=[gstreamer,libnotify,opengl,sdl,tiff,X] required by (dev-python/wxpython-4.2.4:4.0/4.0::gentoo, installed) USE=&amp;quot;-debug -test -webkit&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; PYTHON_TARGETS=&amp;quot;python3_13 -python3_11 -python3_12 -python3_14&amp;quot;
                                         ^^^^^^^^^                             

media-video/ffmpeg:0

  (media-video/ffmpeg-8.1:0/60.62.62::gentoo, ebuild scheduled for merge) USE=&amp;quot;X alsa bzip2 cairo dav1d drm dvd fontconfig gnutls gpl jpegxl lame lcms libass opengl opus pulseaudio sdl svg svt-av1 theora truetype vaapi vorbis vpx vulkan webp x264 xml zlib -amf -amr -amrenc (-appkit) -bluray -bs2b -cdio -chromaprint -chromium -codec2 (-cuda) -doc -fdk -flite -frei0r -fribidi -gcrypt -gme -gmp -gsm -iec61883 -ieee1394 -jack -jpeg2k -kvazaar -ladspa -libaom -libaribb24 -libcaca -libilbc -liblc3 -libplacebo -librtmp -libsoxr -lv2 -lzma -modplug -nvenc -ocr -openal -opencl -opencolorio -openh264 -openmpt -openssl -qrcode -qsv -quirc -rabbitmq -rav1e -rist -rubberband -samba -snappy -sndio -speex -srt -ssh -twolame -v4l -vdpau -verify-sig -vidstab -vmaf -x265 -xvid -zeromq -zimg -zvbi&amp;quot; ABI_X86=&amp;quot;(64) -32 (-x32)&amp;quot; conflicts with
    media-video/ffmpeg:0/59.61.61= required by (dev-qt/qtmultimedia-6.10.3:6/6.10.3::gentoo, installed) USE=&amp;quot;X alsa dbus ffmpeg opengl pipewire pulseaudio qml v4l vulkan wayland -custom-cflags -eglfs -gstreamer -test -vaapi&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot;
                      ^^^^^^^^^^^^
    &amp;gt;=media-video/ffmpeg-6.1:0/59.61.61=[opus,x264] required by (media-video/obs-studio-32.1.0-r1:0/0::gentoo, installed) USE=&amp;quot;alsa pipewire pulseaudio truetype wayland -browser -decklink -fdk -jack -lua (-mpegts) -nvenc -python -qsv -sndio -speex -test-input -v4l -vlc -websocket&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; LUA_SINGLE_TARGET=&amp;quot;luajit&amp;quot; PYTHON_SINGLE_TARGET=&amp;quot;python3_13 -python3_11 -python3_12 -python3_14&amp;quot;
                            ^^^^^^^^^^^^           
    media-video/ffmpeg:0/59.61.61= required by (media-libs/tg_owt-0_pre20250515-r2:0/20250515::gentoo, installed) USE=&amp;quot;X screencast&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot;
                      ^^^^^^^^^^^^
    media-video/ffmpeg:0/59.61.61= required by (net-misc/freerdp-3.24.2:3/3::gentoo, installed) USE=&amp;quot;X aad alsa client cups ffmpeg fuse icu jpeg pulseaudio sdl usb xv -camera -debug -gstreamer -kerberos -openh264 -server -smartcard -systemd -test -valgrind -verify-sig (-wayland) -xinerama&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot;
                      ^^^^^^^^^^^^
    media-video/ffmpeg:0/59.61.61=[encode(+),lame(-),opus,theora,vorbis,vpx,x264,xvid] required by (media-gfx/blender-4.4.3:4.4/4.4::gentoo, installed) USE=&amp;quot;X bullet color-management cycles cycles-bin-kernels embree ffmpeg fftw fluid gmp nanovdb nls oidn openexr opengl openmp openpgl opensubdiv openvdb pdf pipewire potrace pugixml pulseaudio sdl sndfile tbb tiff truetype vulkan wayland webp -alembic -collada (-cuda) -debug -doc -gnome (-hip) (-hiprt) -jack -jemalloc -jpeg2k -man -ndof -openal -optix -osl -renderdoc -test -valgrind&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; LLVM_SLOT=&amp;quot;19 -18&amp;quot; PYTHON_SINGLE_TARGET=&amp;quot;python3_13 -python3_11 -python3_12&amp;quot;
                      ^^^^^^^^^^^^                                               ^^^^ 
    &amp;gt;=media-video/ffmpeg-6.1:0/59.61.61=[encode(+),threads(+)] required by (media-video/mpv-0.41.0-r1:0/2::gentoo, installed) USE=&amp;quot;X alsa cdda cli drm dvd egl iconv jpeg lcms libmpv lua pipewire pulseaudio uchardet vulkan wayland xv zlib (-aqua) -archive -bluray (-coreaudio) -debug -dvb -gamepad -jack -javascript -libcaca -nvenc -openal -rubberband -sdl (-selinux) -sixel -sndio -soc -test -tools -vaapi -vdpau -zimg&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; LUA_SINGLE_TARGET=&amp;quot;(luajit) (-lua5-1)&amp;quot; PYTHON_SINGLE_TARGET=&amp;quot;python3_13 -python3_11 -python3_12 -python3_14&amp;quot;
                            ^^^^^^^^^^^^                      
    &amp;lt;media-video/ffmpeg-8:=[encode(+),lame(-),opus,theora,vorbis,vpx,x264,xvid] required by (media-gfx/blender-4.4.3:4.4/4.4::gentoo, installed) USE=&amp;quot;X bullet color-management cycles cycles-bin-kernels embree ffmpeg fftw fluid gmp nanovdb nls oidn openexr opengl openmp openpgl opensubdiv openvdb pdf pipewire potrace pugixml pulseaudio sdl sndfile tbb tiff truetype vulkan wayland webp -alembic -collada (-cuda) -debug -doc -gnome (-hip) (-hiprt) -jack -jemalloc -jpeg2k -man -ndof -openal -optix -osl -renderdoc -test -valgrind&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot; LLVM_SLOT=&amp;quot;19 -18&amp;quot; PYTHON_SINGLE_TARGET=&amp;quot;python3_13 -python3_11 -python3_12&amp;quot;
    ^                   ^                                                 ^^^^ 
    &amp;gt;=media-video/ffmpeg-6:0/59.61.61=[opus,vpx] required by (net-im/telegram-desktop-6.5.1:0/0::gentoo, installed) USE=&amp;quot;X dbus fonts libdispatch screencast wayland -enchant -webkit&amp;quot; ABI_X86=&amp;quot;(64)&amp;quot;
                          ^^^^^^^^^^^^          


Nothing to merge; quitting.</code></pre>
  </div>
</div>
<ol type="1">
<li><code>dev-qt/qtmultimedia</code></li>
<li><code>media-video/obs-studio</code></li>
<li><code>media-libs/tg_owt</code></li>
<li><code>net-misc/freerdp</code></li>
<li><code>media-gfx/blender</code></li>
<li>…</li>
</ol>
<p>… all still depend on <code>media-video/ffmpeg-59.61.61</code></p>
<h2 id="afterthoughts">Afterthoughts</h2>
<p>I am still very new to Gentoo, but in the short time I have yet had with the distribution, it is, by a long shot, my favourite approach to Linux.</p>
<p>Before moving to Gentoo, I used to run <a href="https://artixlinux.org/">Artix</a> (<a href="https://archlinux.org/">Archlinux</a> without <code>systemd</code>), but I have never felt more in satisfied with my computer and the software it is running than I have since moving to Gentoo.</p>]]></description>
    <pubDate>Sun, 26 Apr 2026 00:00:00 UT</pubDate>
    <guid>https://justin.cx/posts/why-gentoo.html</guid>
    <dc:creator>Justin Andreas Lacoste</dc:creator>
</item>

    </channel>
</rss>
