<?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: Aboubakar Camara</title>
    <description>The latest articles on DEV Community by Aboubakar Camara (@bigabou007dev).</description>
    <link>https://dev.to/bigabou007dev</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%2F3834052%2Fe2a609f1-b7ce-4560-8c7e-0980b2c4a44b.png</url>
      <title>DEV Community: Aboubakar Camara</title>
      <link>https://dev.to/bigabou007dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bigabou007dev"/>
    <language>en</language>
    <item>
      <title>Your AI Agents Run 24/7. Your Laptop Doesn't. I Built a Mobile Docker Dashboard.</title>
      <dc:creator>Aboubakar Camara</dc:creator>
      <pubDate>Tue, 31 Mar 2026 02:32:28 +0000</pubDate>
      <link>https://dev.to/bigabou007dev/your-ai-agents-run-247-your-laptop-doesnt-i-built-a-mobile-docker-dashboard-j2m</link>
      <guid>https://dev.to/bigabou007dev/your-ai-agents-run-247-your-laptop-doesnt-i-built-a-mobile-docker-dashboard-j2m</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;It's 2026. Your infrastructure doesn't sleep.&lt;/p&gt;

&lt;p&gt;You've got n8n pipelines processing data around the clock. AI agents running inference jobs. Deployment managers watching your CI/CD. Scheduled backups, monitoring bots, reverse proxies serving traffic globally. These services run 24/7 because that's the whole point — automation that works while you don't.&lt;/p&gt;

&lt;p&gt;But when something breaks — a container crashes, an agent pipeline stalls, a resource spike cascades — you need to respond &lt;em&gt;now&lt;/em&gt;. Not after you drive home. Not after you open your laptop. Now.&lt;/p&gt;

&lt;p&gt;And you're not at your desk. You're commuting. At dinner. In a meeting. Traveling. Sleeping.&lt;/p&gt;

&lt;p&gt;Your options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SSH from your phone (fat-finger your passphrase three times, squint at truncated output)&lt;/li&gt;
&lt;li&gt;Open Portainer on mobile Safari (pinch-zoom through a desktop UI on a 6-inch screen)&lt;/li&gt;
&lt;li&gt;Wait until you get to your laptop (while your automation is down and your clients are affected)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;None of these are acceptable when your infrastructure runs autonomously.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Portainer, Rancher, and similar tools are excellent — but they were built for a world where you sit at a monitor. That's not how infrastructure works anymore.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Lagoon Cockpit&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Is
&lt;/h2&gt;

&lt;p&gt;Lagoon Cockpit is an open-source, mobile-native command center for Docker infrastructure. It has three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A lightweight API agent&lt;/strong&gt; (&lt;code&gt;cockpit-api&lt;/code&gt;) — a Docker container that runs on your server and talks to the Docker Engine via the unix socket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A native mobile app&lt;/strong&gt; — built with Expo/React Native, designed for phone screens with biometric lock&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CLI&lt;/strong&gt; — 25+ commands for terminal workflows (&lt;code&gt;npx lagoon-cockpit-cli&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phone (Expo app) / CLI / PWA
  │ HTTPS
  │
[cockpit-api]  ← Docker container on your server (~22MB RAM)
  ├── Docker Engine API (/var/run/docker.sock)
  ├── /proc (system metrics)
  ├── SQLite (users, audit log)
  └── Prometheus export (37 metrics at /metrics)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API container uses ~22MB of RAM and 0% CPU at idle. It's not another heavy monitoring platform — it's a thin layer between your phone and your Docker daemon.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Actually Do From Your Phone
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftzw93aj6ffp95n8mhci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftzw93aj6ffp95n8mhci.png" alt="Overview Dashboard" width="786" height="1704"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The overview dashboard — CPU, RAM, disk, container count, stack health at a glance&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Real-Time Dashboard
&lt;/h3&gt;

&lt;p&gt;One screen shows you everything: CPU, RAM, disk usage, container count, stack health, and recent alerts. Auto-refresh via SSE every 15 seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  Container Lifecycle
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kw7coccfb9c4g7aebj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kw7coccfb9c4g7aebj3.png" alt="Container List" width="786" height="1704"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Browse all containers with real-time status indicators&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Browse all containers with status indicators. Tap into any container to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live CPU and memory stats&lt;/li&gt;
&lt;li&gt;Network I/O and PID count&lt;/li&gt;
&lt;li&gt;Full log output with regex search&lt;/li&gt;
&lt;li&gt;Exec into containers with security-hardened command whitelist&lt;/li&gt;
&lt;li&gt;Start / Stop / Restart with confirmation dialogs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Docker Compose Stack Management
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckpt0won9jxbicccs6qr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckpt0won9jxbicccs6qr.png" alt="Compose Stacks" width="786" height="1704"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Stacks auto-discovered from Docker labels — no config needed&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Containers are automatically grouped by their &lt;code&gt;com.docker.compose.project&lt;/code&gt; label — no config needed. Start, stop, or restart an entire stack at once. One tap to bring your automation pipeline back online.&lt;/p&gt;
&lt;h3&gt;
  
  
  Visual System Map
&lt;/h3&gt;

&lt;p&gt;See your entire Docker topology at a glance — stacks grouped, networks connected, health color-coded. Tap any node to manage it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Management Hub
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetc2oyzxvh5pru4balrk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetc2oyzxvh5pru4balrk.png" alt="Management Hub" width="786" height="1704"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;SSL monitoring, endpoint probes, scheduled actions, webhook integrations&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  SSL &amp;amp; Endpoint Monitoring
&lt;/h3&gt;

&lt;p&gt;The API probes your configured domains and endpoints on request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP status codes and response times&lt;/li&gt;
&lt;li&gt;SSL certificate expiry (days remaining, color-coded)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Custom Alerts + Webhooks
&lt;/h3&gt;

&lt;p&gt;Set alert rules (CPU &amp;gt; 90% for 5 minutes → push notification). Integrate with Slack, Discord, or n8n for automated incident response.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scheduled Actions
&lt;/h3&gt;

&lt;p&gt;Set cron schedules for container actions — restart your memory-leaky service every Sunday at 3 AM without waking up.&lt;/p&gt;
&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No public ports&lt;/strong&gt; — access via Tailscale, VPN, or reverse proxy with IP restriction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual auth&lt;/strong&gt;: API key mode (single admin) or multi-user mode with roles (admin/operator/viewer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Biometric lock&lt;/strong&gt; on the mobile app (fingerprint/face)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT with refresh token rotation&lt;/strong&gt;, rate limiting, audit logging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 independent security audits&lt;/strong&gt; — 35 findings, all fixed before release&lt;/li&gt;
&lt;li&gt;All container IDs validated to prevent path traversal on the Docker socket&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Multi-Server
&lt;/h3&gt;

&lt;p&gt;Add your production, staging, and dev servers. Switch between them from any screen.&lt;/p&gt;
&lt;h2&gt;
  
  
  How the Docker API Client Works
&lt;/h2&gt;

&lt;p&gt;Instead of shelling out to &lt;code&gt;docker ps&lt;/code&gt; and parsing text (fragile, slow, blocks the event loop), the API talks directly to the Docker Engine REST API via the unix socket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dockerAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;socketPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/var/run/docker.sock&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/v1.43&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// List all containers&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;dockerAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/containers/json?all=true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get one-shot stats&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;dockerAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/containers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/stats?stream=false`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Restart a container&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;dockerAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/containers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/restart`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero dependencies for the Docker client. Node.js's built-in &lt;code&gt;http&lt;/code&gt; module handles unix sockets natively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack Discovery Without Config
&lt;/h2&gt;

&lt;p&gt;Docker Compose automatically labels containers with &lt;code&gt;com.docker.compose.project&lt;/code&gt;. We use this to group containers into stacks without needing access to compose files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;dockerAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/containers/json?all=true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;com.docker.compose.project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stacks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??=&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the API doesn't need to mount your compose files — it discovers stacks purely from Docker labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deploy the API (one command)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/lagoon-tech-systems/cockpit:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Docker Compose for production setups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Lagoon-Tech-Systems/lagoon-cockpit.git
&lt;span class="nb"&gt;cd &lt;/span&gt;lagoon-cockpit/packages/api
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Edit .env: set API_KEY, JWT_SECRET, SERVER_NAME&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container joins your Docker network with no public ports. Access it via your VPN or reverse proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the Mobile App
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;lagoon-cockpit/packages/app
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npx expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scan the QR code with Expo Go on your phone. Add your server URL + API key, and you're in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Or Use the CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lagoon-cockpit-cli overview
npx lagoon-cockpit-cli ps
npx lagoon-cockpit-cli logs my-container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Terminal/exec into containers from the app&lt;/li&gt;
&lt;li&gt;[ ] Docker image pull/update&lt;/li&gt;
&lt;li&gt;[ ] Resource usage graphs (historical)&lt;/li&gt;
&lt;li&gt;[ ] App Store / Play Store release&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Lagoon-Tech-Systems/lagoon-cockpit" rel="noopener noreferrer"&gt;github.com/Lagoon-Tech-Systems/lagoon-cockpit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AGPL-3.0 licensed. Stars, issues, and PRs welcome.&lt;/p&gt;

&lt;p&gt;Your agents run 24/7. Now you can manage them from anywhere.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://lagoontechsystems.com" rel="noopener noreferrer"&gt;Lagoon Tech Systems&lt;/a&gt; in Abidjan, Côte d'Ivoire.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>opensource</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
