<?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>DEV Community: Kai Builds</title>
    <description>The latest articles on DEV Community by Kai Builds (@kai_builds).</description>
    <link>https://dev.to/kai_builds</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3901336%2F6dc3251e-ef55-4fc3-b1a1-ac51b8656cdd.png</url>
      <title>DEV Community: Kai Builds</title>
      <link>https://dev.to/kai_builds</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kai_builds"/>
    <language>en</language>
    <item>
      <title>Common Docker Compose Security Mistakes in Self-Hosted Homelabs</title>
      <dc:creator>Kai Builds</dc:creator>
      <pubDate>Tue, 28 Apr 2026 05:28:01 +0000</pubDate>
      <link>https://dev.to/kai_builds/common-docker-compose-security-mistakes-in-self-hosted-homelabs-5deg</link>
      <guid>https://dev.to/kai_builds/common-docker-compose-security-mistakes-in-self-hosted-homelabs-5deg</guid>
      <description>&lt;p&gt;Self-hosting is great because it gives you control.&lt;/p&gt;

&lt;p&gt;You can run your own apps, keep your data closer to you, avoid some vendor lock-in, and learn how your stack actually works.&lt;/p&gt;

&lt;p&gt;But there is a tradeoff: once you self-host, you are also responsible for the boring parts.&lt;/p&gt;

&lt;p&gt;Exposed ports. Container defaults. Secrets. Backups. Updates. Reverse proxies. Databases.&lt;/p&gt;

&lt;p&gt;A lot of self-hosted setups start small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. The app is online. Everything feels fine.&lt;/p&gt;

&lt;p&gt;But a working Docker Compose file is not always a safe Docker Compose file.&lt;/p&gt;

&lt;p&gt;Here are some common security mistakes I keep seeing in self-hosted Docker Compose setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Exposing databases directly
&lt;/h2&gt;

&lt;p&gt;A database usually does not need to be exposed to the public internet.&lt;/p&gt;

&lt;p&gt;This is risky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same applies to services like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL: &lt;code&gt;5432&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;MySQL / MariaDB: &lt;code&gt;3306&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Redis: &lt;code&gt;6379&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;MongoDB: &lt;code&gt;27017&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Elasticsearch / OpenSearch: &lt;code&gt;9200&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In many self-hosted stacks, the database only needs to be reachable by other containers on the same Docker network.&lt;/p&gt;

&lt;p&gt;A safer pattern is often to avoid publishing the database port at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db_data:/var/lib/postgresql/data&lt;/span&gt;

  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you really need local access, bind to localhost instead of all interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:5432:5432"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a complete security solution, but it is usually safer than publishing the database broadly.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Running privileged containers
&lt;/h2&gt;

&lt;p&gt;This is another setting worth reviewing carefully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:latest&lt;/span&gt;
    &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;privileged: true&lt;/code&gt; gives a container much broader access to the host than most services need.&lt;/p&gt;

&lt;p&gt;Sometimes it is required. Many times it is not.&lt;/p&gt;

&lt;p&gt;If a container asks for privileged mode, it is worth asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why does this service need it?&lt;/li&gt;
&lt;li&gt;Can I use specific capabilities instead?&lt;/li&gt;
&lt;li&gt;Is there a documented reason?&lt;/li&gt;
&lt;li&gt;Is this image trusted?&lt;/li&gt;
&lt;li&gt;Is this service exposed publicly?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Privileged containers are not automatically bad, but they should not be invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Using &lt;code&gt;network_mode: host&lt;/code&gt; without thinking
&lt;/h2&gt;

&lt;p&gt;Host networking can be useful, but it also removes some of Docker's network isolation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:latest&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With host networking, the container shares the host network namespace.&lt;/p&gt;

&lt;p&gt;That can make port exposure harder to reason about, especially in a homelab where services are added over time.&lt;/p&gt;

&lt;p&gt;Before using host networking, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this service actually require it?&lt;/li&gt;
&lt;li&gt;Which ports does it open?&lt;/li&gt;
&lt;li&gt;Is it behind a reverse proxy?&lt;/li&gt;
&lt;li&gt;Is it only reachable over a VPN or private network?&lt;/li&gt;
&lt;li&gt;Would a normal Docker network work instead?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Running containers as root
&lt;/h2&gt;

&lt;p&gt;Many containers run as root by default.&lt;/p&gt;

&lt;p&gt;If your Compose file does not specify a user, it may be worth checking whether the image supports non-root execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:1.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more explicit setup might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000:1000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not always possible, and some images need extra configuration. But if a service can run as a non-root user, that is usually worth considering.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Putting secrets directly in &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is easy to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;super-secret-key"&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also easy to forget about.&lt;/p&gt;

&lt;p&gt;Inline secrets can end up in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git history&lt;/li&gt;
&lt;li&gt;shared snippets&lt;/li&gt;
&lt;li&gt;support requests&lt;/li&gt;
&lt;li&gt;screenshots&lt;/li&gt;
&lt;li&gt;public GitHub repositories&lt;/li&gt;
&lt;li&gt;copied backups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A better pattern is to avoid hardcoding sensitive values directly in the Compose file.&lt;/p&gt;

&lt;p&gt;Depending on your setup, you might use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; files with proper permissions&lt;/li&gt;
&lt;li&gt;Docker secrets&lt;/li&gt;
&lt;li&gt;a secrets manager&lt;/li&gt;
&lt;li&gt;environment injection from your deployment system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even then, be careful not to commit &lt;code&gt;.env&lt;/code&gt; files.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Using &lt;code&gt;latest&lt;/code&gt; everywhere
&lt;/h2&gt;

&lt;p&gt;This is common:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:latest&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that &lt;code&gt;latest&lt;/code&gt; is not a version. It is a moving target.&lt;/p&gt;

&lt;p&gt;This can be especially risky for stateful services like databases.&lt;/p&gt;

&lt;p&gt;A safer pattern is to pin versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16.2&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7.2.4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You still need to update, but now updates are intentional instead of accidental.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. No visible backup strategy
&lt;/h2&gt;

&lt;p&gt;If your Compose file has persistent volumes, there is probably data worth protecting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db_data:/var/lib/postgresql/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Compose file cannot tell the whole backup story.&lt;/p&gt;

&lt;p&gt;But when there are database volumes and no visible backup service, no backup documentation, and no restore-test process, it is a signal to slow down and check.&lt;/p&gt;

&lt;p&gt;A good backup plan should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What data is backed up?&lt;/li&gt;
&lt;li&gt;Where is it backed up to?&lt;/li&gt;
&lt;li&gt;How often?&lt;/li&gt;
&lt;li&gt;Is it encrypted?&lt;/li&gt;
&lt;li&gt;Has restore been tested?&lt;/li&gt;
&lt;li&gt;Who knows how to recover it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Backups are not real until restore has been tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Assuming a reverse proxy makes everything safe
&lt;/h2&gt;

&lt;p&gt;Reverse proxies like Traefik, Caddy, Nginx Proxy Manager, SWAG, and others are useful.&lt;/p&gt;

&lt;p&gt;But they can also make exposure harder to understand.&lt;/p&gt;

&lt;p&gt;A service might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;internal only&lt;/li&gt;
&lt;li&gt;bound to localhost&lt;/li&gt;
&lt;li&gt;directly exposed&lt;/li&gt;
&lt;li&gt;exposed through a reverse proxy&lt;/li&gt;
&lt;li&gt;accessible only over VPN&lt;/li&gt;
&lt;li&gt;accidentally exposed through an old port mapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important thing is not just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do I have a reverse proxy?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important thing is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do I understand which services are reachable, from where, and why?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A simple review checklist
&lt;/h2&gt;

&lt;p&gt;Before exposing a self-hosted Docker Compose stack, I like to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are any databases published to the host?&lt;/li&gt;
&lt;li&gt;Are any admin panels exposed?&lt;/li&gt;
&lt;li&gt;Are any services using &lt;code&gt;privileged: true&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Are any services using &lt;code&gt;network_mode: host&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Are containers running as root?&lt;/li&gt;
&lt;li&gt;Are secrets hardcoded?&lt;/li&gt;
&lt;li&gt;Are images pinned to specific versions?&lt;/li&gt;
&lt;li&gt;Are persistent volumes backed up?&lt;/li&gt;
&lt;li&gt;Are restore tests documented?&lt;/li&gt;
&lt;li&gt;Do I know what is public, private, and internal?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not replace a full security audit, but it catches a lot of easy-to-miss issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built DockAudit
&lt;/h2&gt;

&lt;p&gt;I built DockAudit to make this kind of lightweight review easier.&lt;/p&gt;

&lt;p&gt;DockAudit is an open-source security auditor for self-hosted Docker Compose stacks.&lt;/p&gt;

&lt;p&gt;It scans &lt;code&gt;docker-compose.yml&lt;/code&gt; files and highlights risky settings like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exposed databases and admin panels&lt;/li&gt;
&lt;li&gt;privileged containers&lt;/li&gt;
&lt;li&gt;host networking&lt;/li&gt;
&lt;li&gt;containers running as root&lt;/li&gt;
&lt;li&gt;inline secrets&lt;/li&gt;
&lt;li&gt;unpinned images&lt;/li&gt;
&lt;li&gt;missing backup hints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs locally and does not send your Compose files anywhere.&lt;/p&gt;

&lt;p&gt;The goal is not to replace a full security audit. It is a small, local-first tool for catching common self-hosted Docker Compose risks before they become incidents.&lt;/p&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kaibuild/dockaudit?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dockaudit_launch" rel="noopener noreferrer"&gt;https://github.com/kaibuild/dockaudit?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dockaudit_launch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run self-hosted Docker Compose stacks, I would love feedback on what checks would be useful.&lt;/p&gt;

&lt;p&gt;And if you find it useful, a GitHub star would help a lot.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>security</category>
    </item>
  </channel>
</rss>
