<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Dockge – Serverküche</title><link>https://serverkueche.de/en/tags/dockge/</link><description>Dockge – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>en-US</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Tue, 29 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/en/tags/dockge/index.xml" rel="self" type="application/rss+xml"/><item><title>Dockge: Manage Compose Stacks in the Browser</title><link>https://serverkueche.de/en/tutorials/dockge-manage-compose/</link><pubDate>Tue, 29 Sep 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/en/tutorials/dockge-manage-compose/</guid><description>Set up Dockge 1.5 behind Traefik: edit and deploy Compose stacks in the browser and follow the logs live – without lock-in, the files stay plain compose.yaml.</description><content:encoded><![CDATA[<p>Anyone running several Compose stacks knows the routine: SSH in, change into the right folder,
<code>docker compose pull &amp;&amp; up -d</code>, check the logs, next stack. Dockge brings exactly those steps into
the browser – while writing perfectly ordinary <code>compose.yaml</code> files that you can still touch from the
CLI.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>At the end, <strong>Dockge 1.5.0</strong> runs behind your Traefik at <code>https://YOUR_DOMAIN</code>. You create stacks in
the browser, edit their <code>compose.yaml</code>, deploy them with one click and watch the output of
<code>docker compose up</code> <strong>live</strong> – including container logs and a Bash console per container.</p>
<p>The decisive difference from heavyweight Docker interfaces: Dockge does not invent a format of its
own. Every stack is a folder under <code>/opt/stacks/&lt;name&gt;/</code> with a <code>compose.yaml</code> and an <code>.env</code>.
<code>docker compose ls</code> lists them as normal projects. You can switch Dockge off tomorrow and carry on as
if it had never existed – <strong>no lock-in</strong>.</p>
<p>On resources: the container used around <strong>143 MiB RAM</strong> in the test with virtually no CPU load. The
image, however, is no lightweight at <strong>1.17 GB</strong> – worth knowing if your VPS has a small system disk.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-paprika-400 bg-paprika-50 dark:border-paprika-700 dark:bg-paprika-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🔥</span>Dockge is root on your server
  </p>
  <div class="prose-kitchen text-sm">Dockge needs the Docker socket (<code>/var/run/docker.sock</code>). Anyone with access to this interface can
start arbitrary containers – privileged ones included – and thereby <strong>take over the whole host</strong>. So
this applies more strictly here than for any other app: reachable over HTTPS only, a long unique
password, and if possible restricted to your own IP as well (see
<a href="/en/tutorials/firewall-ufw-setup/">Setting up a firewall with UFW</a>). A Dockge on the open internet
with a weak password is a compromised server.</div>
</div>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>A server running Debian 13 with Docker (tested on a netcup VPS with Docker 29.6.1 and
Compose v5.3.1)</li>
<li><a href="/en/tutorials/docker-compose-basics/">Docker Compose basics</a> – Dockge does not save you the
understanding, only the typing</li>
<li>A <strong>running Traefik</strong> with its <code>proxy</code> network as in
<a href="/en/tutorials/traefik-reverse-proxy/">Traefik as a reverse proxy</a></li>
<li>A subdomain pointing at your server
(<a href="/en/tutorials/connect-domain-to-server/">connecting a domain</a>)</li>
</ul>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20"
     data-track-content data-content-name="Affiliate-Box · /en/tutorials/dockge-manage-compose/" data-content-piece="VPS 1000 G12.5">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Recommendation</span>
    <span title="Links marked with * are affiliate links.">Ad</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12.5</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCores · 8 GB RAM · 128 GB SSD</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">from €14.50/month</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Dockge itself is tiny – what matters is what you run with it.</p>
    </div>
    <a href="https://www.netcup.com/en/server/vps/vps-1000-g12.5-iv-24m-eu?ref=44083#vps-1000-g12.5-iv-12m-eu" rel="sponsored noopener" target="_blank"
   data-track-event="Affiliate|netcup: Affiliate-Box|VPS 1000 G12.5 · {page}"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Go to netcup →
</a>

  </div><div class="px-4 pb-4"><div class="not-prose my-3 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200"
     data-voucher-pool="vps-1000" data-voucher-codes="[&#34;6877nc17905136544&#34;,&#34;6877nc17905136543&#34;,&#34;6877nc17905136542&#34;,&#34;6877nc17905136541&#34;,&#34;6877nc17905136540&#34;,&#34;6877nc17905133999&#34;,&#34;6877nc17905133998&#34;,&#34;6877nc17905133997&#34;,&#34;6877nc17905133996&#34;,&#34;6877nc17905133995&#34;,&#34;6877nc17905133994&#34;,&#34;6877nc17905133993&#34;,&#34;6877nc17905133992&#34;,&#34;6877nc17905133991&#34;,&#34;6877nc17905133990&#34;]">
  <p class="flex flex-wrap items-center gap-x-2 gap-y-1">
    <span>💶 <span class="font-semibold">1 month free</span> for new netcup customers:</span>
    <button type="button" data-voucher-code data-track-voucher="6877nc17905136544"
            title="Click to copy" class="cursor-pointer rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 hover:ring-2 hover:ring-herb-500/40 dark:bg-slate-800 dark:text-herb-400">6877nc17905136544</button>
    <button type="button" data-voucher-next hidden
            class="rounded border border-herb-500/40 px-2 py-0.5 text-xs text-herb-800 hover:bg-white dark:text-herb-400 dark:hover:bg-slate-800">another code</button>
  </p>
  <p class="mt-1 text-xs text-slate-500 dark:text-slate-400">
    Single use, valid for VPS 1000 G12.5.
    <a href="https://www.netcup.com/en/checkout/cart?ref=44083" rel="sponsored noopener" target="_blank"
       data-track-event="Affiliate|netcup: Gutschein einlösen|VPS 1000 G12.5 · {page}"
       class="font-medium text-herb-800 underline underline-offset-2 hover:text-herb-900 dark:text-herb-400">Redeem in the cart →</a>
  </p><p class="mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 border-t border-herb-500/30 pt-2">
    <span>💶 <span class="font-semibold">€5 voucher</span> for new netcup customers:</span>
    <button type="button" data-voucher-code data-track-voucher="36nc17844976032"
            title="Click to copy" class="cursor-pointer rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 hover:ring-2 hover:ring-herb-500/40 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</button>
    <span class="text-xs text-slate-500 dark:text-slate-400">always valid · not for domains or VPS Lite</span>
  </p>
</div></div>
</div>

<h2 id="step-by-step">Step by step</h2>
<h3 id="1-decide-on-the-stacks-directory">1. Decide on the stacks directory</h3>
<p>Dockge manages <strong>all stacks below one folder</strong>. The default is <code>/opt/stacks</code>, and we stick with it –
it matches the convention used in the other recipes:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /opt/stacks /opt/dockge/data</span></span></code></pre></div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Host and container path must be identical
  </p>
  <div class="prose-kitchen text-sm">The path has to be the same inside <strong>and</strong> outside the container, i.e. <code>/opt/stacks:/opt/stacks</code>.
Dockge calls <code>docker compose</code> through the host&rsquo;s socket – so the daemon interprets paths from the
<strong>host&rsquo;s</strong> point of view. If you mount <code>/opt/stacks</code> to <code>/app/stacks</code>, Dockge finds the files in its
own view but the daemon does not: deployments fail with „no such file or directory&quot;.</div>
</div>
<h3 id="2-the-compose-file-for-dockge">2. The Compose file for Dockge</h3>
<p>Create <code>/opt/dockge/compose.yaml</code> and replace <code>YOUR_DOMAIN</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">dockge</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">louislam/dockge:1.5.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">DOCKGE_STACKS_DIR</span><span class="p">:</span><span class="w"> </span><span class="l">/opt/stacks</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/var/run/docker.sock:/var/run/docker.sock</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./data:/app/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/opt/stacks:/opt/stacks</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">proxy]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.enable=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.dockge.rule=Host(`YOUR_DOMAIN`)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.dockge.entrypoints=websecure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.dockge.tls.certresolver=le&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.services.dockge.loadbalancer.server.port=5001&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">proxy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
</div>
<p>How the pieces fit together:</p>
<ul>
<li><strong><code>DOCKGE_STACKS_DIR</code></strong> must match the mount target exactly (step 1).</li>
<li><strong><code>./data</code></strong> holds Dockge&rsquo;s own SQLite database: users, settings, JWT secret.</li>
<li><strong><code>loadbalancer.server.port=5001</code></strong> – inside the container Dockge listens on 5001. We publish
<strong>no</strong> port to the outside; only Traefik reaches it through the <code>proxy</code> network.</li>
<li>No <code>user:</code> entry: Dockge has to talk to the Docker daemon through the socket and write the stack
files.</li>
</ul>
<p>Start it:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /opt/dockge <span class="o">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose ps</span></span></code></pre></div>
</div>
<p>The container ships a healthcheck, so you should see <code>(healthy)</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">NAME              STATUS
</span></span><span class="line"><span class="cl">dockge-dockge-1   Up 12 seconds (healthy)</span></span></code></pre></div>
</div>
<p>A look at the logs confirms the first start:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker logs --tail <span class="m">5</span> dockge-dockge-1</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[SERVER] INFO: Connected to the database
</span></span><span class="line"><span class="cl">[SERVER] INFO: JWT secret is not found, generate one.
</span></span><span class="line"><span class="cl">[SERVER] INFO: Stored JWT secret into database
</span></span><span class="line"><span class="cl">[SERVER] INFO: No user, need setup
</span></span><span class="line"><span class="cl">[SERVER] INFO: Listening on 5001</span></span></code></pre></div>
</div>
<p><code>No user, need setup</code> means the server is waiting for your admin account.</p>
<h3 id="3-create-the-admin-account">3. Create the admin account</h3>
<p>Open <code>https://YOUR_DOMAIN</code>. Dockge redirects to <code>/setup</code> and asks for a username and password. The
interface follows your browser&rsquo;s language.</p>
<p><figure class="my-6"><img src="/en/tutorials/dockge-manage-compose/setup_hu_b0000e243e1bf8b0.webp" srcset="/en/tutorials/dockge-manage-compose/setup_hu_244d634a09c62ea3.webp 480w, /en/tutorials/dockge-manage-compose/setup_hu_b0000e243e1bf8b0.webp 768w, /en/tutorials/dockge-manage-compose/setup_hu_ad7f56296b39ba57.webp 1200w, /en/tutorials/dockge-manage-compose/setup_hu_1b48c88d3e562b2b.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/dockge-manage-compose/setup_hu_45f9ecd2561e8eea.webp"
    alt="The Dockge setup page for creating the admin account, with a language selector and fields for username and password" title="First visit: create the admin account"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">First visit: create the admin account</figcaption></figure></p>
<p>After that the door is shut: there is no open registration, further accounts are created in the
settings. Use a long, unique password from your
<a href="/en/tutorials/vaultwarden-password-manager/">password manager</a> – see the warning above.</p>
<h3 id="4-understanding-the-home-screen">4. Understanding the home screen</h3>
<p>After logging in you see every Compose project Docker knows about on this host – in the example the
existing <code>traefik</code> stack plus the one just created:</p>
<p><figure class="my-6"><img src="/en/tutorials/dockge-manage-compose/stackliste_hu_49b6ef48ea33889e.webp" srcset="/en/tutorials/dockge-manage-compose/stackliste_hu_6b6cc54c77825c19.webp 480w, /en/tutorials/dockge-manage-compose/stackliste_hu_49b6ef48ea33889e.webp 768w, /en/tutorials/dockge-manage-compose/stackliste_hu_31f3361259a73019.webp 1200w, /en/tutorials/dockge-manage-compose/stackliste_hu_dc4b601d3c19f03e.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/dockge-manage-compose/stackliste_hu_e9c1d6b1b59b5cb2.webp"
    alt="The Dockge home screen with the list of active stacks, counters for active, exited and inactive, and the Dockge agents section" title="Home screen: all stacks with their status at a glance"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Home screen: all stacks with their status at a glance</figcaption></figure></p>
<p>On the left, Dockge counts <code>active</code>, <code>exited</code> and <code>inactive</code>. Important: the list shows <strong>all</strong>
projects, but Dockge can only manage those below <code>/opt/stacks</code>. How to adopt existing stacks is step 7.</p>
<h3 id="5-create-and-deploy-the-first-stack">5. Create and deploy the first stack</h3>
<p>Click <strong>Compose</strong> at the top. You land in the editor: on the left a form for the stack name and
containers, on the right the <code>compose.yaml</code> – both sides are linked, so you can click <strong>or</strong> write
YAML.</p>
<p><figure class="my-6"><img src="/en/tutorials/dockge-manage-compose/editor_hu_371a8803c00cecee.webp" srcset="/en/tutorials/dockge-manage-compose/editor_hu_24cf17fbaf0d066f.webp 480w, /en/tutorials/dockge-manage-compose/editor_hu_371a8803c00cecee.webp 768w, /en/tutorials/dockge-manage-compose/editor_hu_8c5c48e743b4e9eb.webp 1200w, /en/tutorials/dockge-manage-compose/editor_hu_712ebcece45015b1.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/dockge-manage-compose/editor_hu_436f70368ad348c6.webp"
    alt="The Dockge compose editor with a field for the stack name, the container form and the YAML editor beside it" title="The editor: form and YAML keep each other up to date"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">The editor: form and YAML keep each other up to date</figcaption></figure></p>
<p>Give the stack a name (lowercase only – it becomes the folder and project name) and adjust the YAML. A
click on <strong>Deploy</strong> runs <code>docker compose up -d</code>, and the real output scrolls by in the terminal pane:</p>
<p><figure class="my-6"><img src="/en/tutorials/dockge-manage-compose/deployed_hu_4371a262d9e7eae.webp" srcset="/en/tutorials/dockge-manage-compose/deployed_hu_15703d4da0b143b1.webp 480w, /en/tutorials/dockge-manage-compose/deployed_hu_4371a262d9e7eae.webp 768w, /en/tutorials/dockge-manage-compose/deployed_hu_6b149f0e0ab0a6bd.webp 1200w, /en/tutorials/dockge-manage-compose/deployed_hu_23980e25ef377622.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/dockge-manage-compose/deployed_hu_bb318893295d2a40.webp"
    alt="A freshly deployed stack in Dockge with a running container, live logs of the nginx container and the compose.yaml below" title="After deploying: live logs straight in the browser"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">After deploying: live logs straight in the browser</figcaption></figure></p>
<p>The container entry shows status and published ports, with the logs running below. Each container also
gets a <strong>Bash</strong> button that opens a console inside it – handy for quickly checking a configuration.</p>
<h3 id="6-what-happens-on-disk">6. What happens on disk</h3>
<p>This is the part that sets Dockge apart from heavyweight interfaces. After deploying, the server holds
exactly what you would expect:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">find /opt/stacks -type f</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">/opt/stacks/whoami-test/.env
</span></span><span class="line"><span class="cl">/opt/stacks/whoami-test/compose.yaml</span></span></code></pre></div>
</div>
<p>And Docker knows the stack as a perfectly ordinary Compose project:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose ls</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">NAME                STATUS              CONFIG FILES
</span></span><span class="line"><span class="cl">dockge              running(1)          /opt/dockge/compose.yaml
</span></span><span class="line"><span class="cl">traefik             running(1)          /opt/traefik/compose.yaml
</span></span><span class="line"><span class="cl">whoami-test         running(1)          /opt/stacks/whoami-test/compose.yaml</span></span></code></pre></div>
</div>
<p>So you can SSH into the folder at any time and carry on as usual:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /opt/stacks/whoami-test <span class="o">&amp;&amp;</span> docker compose ps</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">NAME                   STATUS         PORTS
</span></span><span class="line"><span class="cl">whoami-test-nginx-1    Up 35 seconds  0.0.0.0:8080-&gt;80/tcp, [::]:8080-&gt;80/tcp</span></span></code></pre></div>
</div>
<p>Both hold at the same time: changes in the browser are visible to the CLI, changes from the CLI show
up in the browser after a reload. Dockge is a remote control, not a new system.</p>
<h3 id="7-adopt-existing-stacks">7. Adopt existing stacks</h3>
<p>A stack outside <code>/opt/stacks</code> appears in the list but cannot be touched – Dockge says so plainly:
„This stack is not managed by Dockge.&quot; There is neither an edit nor a deploy button.</p>
<p>To adopt it, move the folder. Assuming your stack lives in <code>/opt/myapp</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /opt/myapp <span class="o">&amp;&amp;</span> docker compose down
</span></span><span class="line"><span class="cl">mv /opt/myapp /opt/stacks/myapp
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /opt/stacks/myapp <span class="o">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div>
</div>
<p>The project name is derived from the folder name – keep it the same and your containers keep their
names and <strong>named volumes survive</strong>. Dockge then manages the stack fully:</p>
<p><figure class="my-6"><img src="/en/tutorials/dockge-manage-compose/uebernommen_hu_83a9ea2c7b37aa5b.webp" srcset="/en/tutorials/dockge-manage-compose/uebernommen_hu_dbd146f7b184fe2.webp 480w, /en/tutorials/dockge-manage-compose/uebernommen_hu_83a9ea2c7b37aa5b.webp 768w, /en/tutorials/dockge-manage-compose/uebernommen_hu_747dcf5fd2fd8807.webp 1200w, /en/tutorials/dockge-manage-compose/uebernommen_hu_7af806022cea6e87.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/dockge-manage-compose/uebernommen_hu_ec36399e0e54d4c7.webp"
    alt="An adopted stack in Dockge with the edit, restart, update, stop and delete buttons plus the container&rsquo;s live logs" title="After moving it: edit, restart, update, stop, delete"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">After moving it: edit, restart, update, stop, delete</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Tip
  </p>
  <div class="prose-kitchen text-sm">Don&rsquo;t do everything at once: move one non-critical stack, verify, then the next. I would touch your
<strong>Traefik</strong> last – if that goes wrong, Dockge is unreachable too.</div>
</div>
<h3 id="8-convert-docker-run-commands">8. Convert <code>docker run</code> commands</h3>
<p>Many projects only document a long <code>docker run</code> command. The home screen has a field for exactly
that: paste the command, click <strong>Convert to Compose</strong> – and you land in the editor with finished YAML.
This</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run -d --name uptime -p 3001:3001 -v uptime-data:/app/data <span class="se">\
</span></span></span><span class="line"><span class="cl">  --restart unless-stopped louislam/uptime-kuma:2.5.3</span></span></code></pre></div>
</div>
<p>becomes:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">uptime-kuma</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">uptime</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">3001</span><span class="p">:</span><span class="m">3001</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">uptime-data:/app/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">louislam/uptime-kuma:2.5.3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">uptime-data</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">uptime-data</span></span></span></code></pre></div>
</div>
<p>Very handy – with one trap: the named volume is written as <strong><code>external: true</code></strong>, i.e. „already
exists&quot;. On a fresh installation the volume does not exist yet, and the deployment fails. Either
delete those two lines (then Compose creates the volume itself) or create it beforehand with
<code>docker volume create uptime-data</code>. For the difference, see
<a href="/en/tutorials/docker-volumes-vs-bind-mounts/">volumes vs. bind mounts</a>.</p>
<h3 id="9-console-and-agents--decide-deliberately">9. Console and agents – decide deliberately</h3>
<p>Two features you should know about before switching them on:</p>
<p><strong>Console.</strong> The console menu entry is <strong>disabled</strong> by default, and that is a good thing. Dockge
states why itself: it allows arbitrary commands <em>inside</em> the Dockge container – and that container has
the Docker socket. Enabled, it means a root shell on your host in the browser. Leave it off; for the
rare case, SSH is enough.</p>
<p><strong>Agents (beta).</strong> Dockge can attach further servers and manage their stacks in the same interface.
That is convenient if you run several machines – but the feature is marked <strong>beta</strong>, and every
attached agent increases the damage if this one interface is ever compromised. To start with: one
server, one Dockge.</p>
<h3 id="10-updates-with-one-click">10. Updates with one click</h3>
<p>The <strong>Update</strong> button on a stack does exactly what you would otherwise type: pull new images and bring
the stack back up. If the image is already current, nothing happens – in the test the container kept
running unchanged afterwards (same start time), so it is not restarted without reason. That is
convenient – and precisely why you should keep <strong>pinning</strong> your images instead of using <code>latest</code>.
Otherwise one click turns into a jump across several major versions without you noticing. Why that
matters is covered in
<a href="/en/tutorials/keep-docker-stack-updated/">keeping your Docker stack up to date</a>.</p>
<h2 id="when-things-go-wrong">When things go wrong</h2>
<div class="troubleshoot not-prose">
<p><strong>Traefik answers with 404 although the container is <code>healthy</code>.</strong> Usually
<code>traefik.http.services.dockge.loadbalancer.server.port=5001</code> is missing. Inside the container Dockge
listens on 5001; without that line Traefik guesses. Also check that the container is attached to the
<code>proxy</code> network.</p>
<p><strong>The deployment aborts with „no such file or directory&quot;.</strong> The host and container paths of the stacks
directory do not match. It must be mounted as <code>/opt/stacks:/opt/stacks</code> with
<code>DOCKGE_STACKS_DIR=/opt/stacks</code> – Dockge has the host&rsquo;s Docker daemon do the work, and that daemon
only knows host paths.</p>
<p><strong>A stack is visible but all buttons are missing.</strong> Then it lives outside <code>/opt/stacks</code> and Dockge
shows „This stack is not managed by Dockge.&quot; Move the folder as in step 7 – Dockge neither adopts it
by itself nor makes a copy.</p>
<p><strong>The stack name is rejected.</strong> Only lowercase letters, digits and hyphens are allowed, because they
become the folder and Compose project name. <code>My App</code> won&rsquo;t do, <code>my-app</code> will.</p>
<p><strong>After a restart the login is gone.</strong> Then <code>./data</code> was not mounted persistently – that is where the
database and JWT secret live. Check that <code>/opt/dockge/data</code> exists and is bound in the Compose file.</p>
<p><strong>The interface is in the wrong language.</strong> Dockge follows the browser and falls back to English for
unknown combinations; the settings let you pin the language.</p>

</div>
<p class="mt-3 text-sm text-slate-500 dark:text-slate-400">
  Your problem is not listed?
  <a href="/en/errors/" class="font-medium text-paprika-700 hover:underline dark:text-paprika-400">Search all error messages →</a>
</p>

<h2 id="maintenance--backups">Maintenance &amp; backups</h2>
<p><strong>Honest about the project&rsquo;s state.</strong> Dockge is popular (around 24,000 stars) and still being
developed – the most recent commits in the repository are from April 2026, among them container
controls and a resource display. <strong>The last stable release 1.5.0, however, dates from 30 March 2025</strong>,
more than a year ago. There is a <code>nightly</code> tag with the newer features – but it is explicitly not a
release.</p>
<p>In practice that means: stay on <code>1.5.0</code> (completely unproblematic with Docker 29.6.1 and Compose
v5.3.1 in the test), do not expect quick bug fixes, and do not make an operational decision that
depends on a new version arriving tomorrow. For „manage stacks conveniently&quot; it is enough – you just
want to know what you are getting into.</p>
<p><strong>Updating Dockge itself</strong> works like any other stack, but from the CLI (the interface cannot restart
itself):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /opt/dockge <span class="o">&amp;&amp;</span> docker compose pull <span class="o">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div>
</div>
<p><strong>Backups.</strong> Two things need saving, and both are small:</p>
<ul>
<li><code>/opt/dockge/data</code> – Dockge&rsquo;s database with accounts and settings</li>
<li><code>/opt/stacks</code> – <strong>this is where the actual work lives</strong>: every <code>compose.yaml</code> and <code>.env</code> of your
services</li>
</ul>
<p>That makes <code>/opt/stacks</code> your central configuration location from now on – one more reason to back it
up daily with <a href="/en/tutorials/restic-backups/">Restic</a>. The data of your applications (volumes, bind
mounts) is <strong>not</strong> covered by Dockge; that still needs its own strategy.</p>
<p><strong>Review access regularly.</strong> Because Dockge means root rights on the host, maintenance includes the
question: who can actually reach it? The Traefik logs show who requests the login page – if unfamiliar
IPs turn up there, an IP restriction or access only via
<a href="/en/tutorials/wireguard-vpn-setup/">WireGuard</a> is the better answer than an even longer password.</p>
]]></content:encoded></item></channel></rss>