Files
Containr/site/index.html
Tomas DvorakandDevin a23fa2a0cc fix(site): blinking title cursor in hero mockup, matching the app
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-23 18:12:59 +02:00

380 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Containr - Self-hosted platform for containerized services</title>
<meta name="description" content="Containr turns any Docker host into a full deployment platform. Visual project canvases, git-push builds, managed databases, preview environments, and HA failover on your own hardware.">
<meta property="og:title" content="Containr">
<meta property="og:description" content="Railway-style project canvases on your own hardware. Open source, MIT licensed.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://containr-lyart.vercel.app/">
<meta property="og:image" content="https://containr-lyart.vercel.app/screenshots/canvas.png">
<link rel="canonical" href="https://containr-lyart.vercel.app/">
<meta name="theme-color" content="#0c0d0f">
<link rel="icon" type="image/svg+xml" href="containr.svg">
<script>document.documentElement.classList.add('js');</script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<div class="wrap nav-inner">
<a href="#" class="brand">
<img src="containr.svg" alt="Containr logo">
contain<em>r</em>
</a>
<div class="nav-links">
<a href="#features">Features</a>
<a href="#product">Product</a>
<a href="templates.html">Templates</a>
<a href="https://github.com/Dvorinka/Containr/tree/main/docs/guides" target="_blank" rel="noopener">Docs</a>
</div>
<div class="nav-right">
<a class="gh-link" href="https://github.com/Dvorinka/Containr" target="_blank" rel="noopener" aria-label="Containr on GitHub">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"/></svg>
</a>
<a class="btn btn-primary" href="#install">Get started</a>
</div>
</div>
</nav>
<header class="hero">
<div class="wrap">
<span class="pill">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><rect x="3" y="7" width="18" height="12" rx="2"/><path d="M8 7v12M13 7v12M18 7v12M6 22h12"/></svg>
Self-hosted PaaS · MIT license
</span>
<h1>Deploy containers on <em>your own cloud</em></h1>
<p class="sub">Containr turns a Docker host into a full deployment platform. Git builds, managed databases, previews, failover.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="#install">
Get started
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</a>
<a class="btn btn-ghost" href="https://github.com/Dvorinka/Containr" target="_blank" rel="noopener">View on GitHub</a>
</div>
<div class="shot-frame reveal">
<div class="shot-bar"><span class="addr">containr &#8250; core-platform &#8250; canvas</span></div>
<div class="cv" aria-label="Containr project canvas preview">
<div class="cv-top">
<span class="cv-back">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M11 18l-6-6 6-6"/></svg>
Projects
</span>
<b>Core Platform<span class="cv-cursor">_</span></b>
<span class="cv-meta">5 services &#183; 4 running</span>
<span class="cv-tabs">
<i class="on">Canvas</i><i>Observability</i><i>Logs</i><i>Settings</i>
</span>
<span class="cv-active">&#9679; ACTIVE</span>
</div>
<div class="cv-stage">
<svg class="cv-edges" viewBox="0 0 1000 360" preserveAspectRatio="none" aria-hidden="true">
<path d="M 222 101 C 287 101 287 177 358 177" />
<path class="live" d="M 222 238 C 287 238 287 177 358 177" />
<path d="M 536 168 C 618 168 618 83 706 83" />
<path d="M 536 195 C 618 195 618 216 706 216" />
</svg>
<svg class="cv-edges-m" viewBox="0 0 1000 360" preserveAspectRatio="none" aria-hidden="true">
<path d="M 468 105 C 494 105 494 185 520 185" />
<path class="live" d="M 468 278 C 494 278 494 185 520 185" />
<path d="M 949 62 C 985 62 985 155 949 155" />
<path d="M 949 300 C 985 300 985 215 949 215" />
</svg>
<div class="cv-pill env"><i></i>production<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></div>
<div class="cv-node cv-n1">
<div class="cv-row">
<span class="cv-ic" style="background:rgba(97,218,251,.14);color:#61dafb"><img src="https://cdn.simpleicons.org/react/61dafb" alt="" onerror="this.replaceWith('R')"></span>
<div><h4>Web Frontend</h4><p>web</p></div>
</div>
<div class="cv-addr"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M10 14 21 3M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg><span>web.containr.local</span></div>
<div class="cv-foot"><span class="cv-st run"></span><em>running</em><code>ghcr.io/web:v42</code></div>
</div>
<div class="cv-node cv-n2">
<div class="cv-row">
<span class="cv-ic" style="background:rgba(180,227,74,.14);color:var(--accent)"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m4 17 6-6-6-6M12 19h8"/></svg></span>
<div><h4>Queue Worker</h4><p>worker</p></div>
</div>
<div class="cv-addr"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="m9 9 6 6M15 9l-6 6"/></svg><span>queue-worker</span></div>
<div class="cv-foot"><span class="cv-st dep"></span><em style="color:#f2c94c">deploying</em><code>worker:edge</code></div>
</div>
<div class="cv-node sel cv-n3">
<div class="cv-row">
<span class="cv-ic" style="background:rgba(0,173,216,.14);color:#00add8"><img src="https://cdn.simpleicons.org/go/00add8" alt="" onerror="this.replaceWith('G')"></span>
<div><h4>API Gateway</h4><p>web &#183; 2 replicas</p></div>
</div>
<div class="cv-addr"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M10 14 21 3M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg><span>api.containr.local</span></div>
<div class="cv-foot"><span class="cv-st run"></span><em>running</em><code>api:v2.4.1</code></div>
</div>
<div class="cv-node cv-n4">
<div class="cv-row">
<span class="cv-ic" style="background:rgba(65,105,225,.16);color:#7ab8ff"><img src="https://cdn.simpleicons.org/postgresql/7ab8ff" alt="" onerror="this.replaceWith('P')"></span>
<div><h4>Postgres</h4><p>database</p></div>
</div>
<div class="cv-addr"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5"/></svg><span>postgres:5432</span></div>
<div class="cv-foot"><span class="cv-st run"></span><em>running</em><code>postgres:16</code></div>
</div>
<div class="cv-node cv-n5">
<div class="cv-row">
<span class="cv-ic" style="background:rgba(255,68,68,.13);color:#ff6b6b"><img src="https://cdn.simpleicons.org/redis/ff6b6b" alt="" onerror="this.replaceWith('R')"></span>
<div><h4>Redis Cache</h4><p>database</p></div>
</div>
<div class="cv-addr"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5"/></svg><span>redis:6379</span></div>
<div class="cv-foot"><span class="cv-st run"></span><em>running</em><code>dragonfly:1</code></div>
</div>
<div class="cv-pill zoom">
<span>&#8722;</span><b>100%</b><span>+</span><i></i>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 15-4.5 4.5M9 15l6-6M8 4l.9 2.6L11.5 8 9 9.5 6.4 8 8 5.4zM19 13l.7 2 2 .7-2 .7-.7 2-.7-2-2-.7 2-.7zM13 3l.6 1.7L15.3 5l-1.7.6L13 7.3 12.4 5.6 10.7 5l1.7-.6z"/></svg>
</div>
<div class="cv-minimap"><i style="left:6%;top:14%"></i><i style="left:6%;top:52%"></i><i style="left:38%;top:35%"></i><i style="left:72%;top:9%"></i><i style="left:72%;top:46%"></i></div>
</div>
</div>
</div>
</div>
</header>
<div class="install" id="install">
<div class="wrap">
<div class="install-inner reveal">
<div class="install-copy">
<h2>One command, running stack</h2>
<p>Requires Docker and openssl. Installs into ./containr, never overwrites your .env.</p>
</div>
<div class="cmd">
<code id="install-cmd">curl -fsSL https://raw.githubusercontent.com/Dvorinka/Containr/main/install.sh | bash</code>
<button class="copy-btn" id="copy-btn" aria-label="Copy install command">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
</button>
</div>
</div>
</div>
</div>
<section id="features">
<div class="wrap">
<div class="sec-head reveal">
<h2>A control plane, not a pile of YAML</h2>
<p>Everything a deployment platform needs, running on hardware you already own. One install, one dashboard.</p>
</div>
<div class="bento">
<div class="cell wide reveal">
<div>
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/><path d="M10 6.5h5.5a2 2 0 0 1 2 2V14M6.5 10v5.5a2 2 0 0 0 2 2H14"/></svg>
</div>
<h3>Visual project canvas</h3>
<p>Services appear as nodes on a Railway-style canvas. Drag, group, and wire them together; connections and shared variables are inferred automatically. Start, stop, restart, or roll back with a right-click.</p>
</div>
<div class="cell-media"><img src="screenshots/service-detail.png" alt="Service view with metrics, logs, and configuration tabs" loading="lazy"></div>
</div>
<div class="cell tinted reveal">
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5"/><path d="M4 11v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"/></svg>
</div>
<h3>Managed databases</h3>
<p>Provision engines from the dashboard, with backups and restore built in.</p>
<div class="chips">
<span>PostgreSQL</span><span>MySQL</span><span>MariaDB</span><span>MongoDB</span><span>Redis</span><span>Dragonfly</span><span>ClickHouse</span>
</div>
</div>
<div class="cell reveal">
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="12" cy="18" r="2.5"/><path d="M8 7.5 10.5 16M16 7.5 13.5 16M8.5 6h7"/></svg>
</div>
<h3>Private networking</h3>
<p>Every project gets an isolated Docker network. Services reach each other by name.</p>
<div class="snippet">web:3000 <b>&#8594;</b> ${{service.KEY}}</div>
</div>
<div class="cell reveal">
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3v12"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="6" r="2.5"/><path d="M18 8.5a5 5 0 0 1-5 5H9"/></svg>
</div>
<h3>Git-push deploys</h3>
<p>Connect GitHub, GitLab, Bitbucket, or Gitea. Builds, history, and image rollback included.</p>
</div>
<div class="cell reveal">
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>
</div>
<h3>HA and autoscaling</h3>
<p>Failover policies, health checks, node agents, and metric-driven replica scaling.</p>
</div>
<div class="cell reveal">
<div class="icon">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 6v6c0 5 3.4 8.6 8 10 4.6-1.4 8-5 8-10V6l-8-4Z"/><path d="m9 12 2 2 4-4"/></svg>
</div>
<h3>Admin and audit</h3>
<p>Approval console, user management, audit logs, and vulnerability scans behind sign-in.</p>
</div>
</div>
</div>
</section>
<section id="product">
<div class="wrap">
<div class="sec-head reveal">
<h2>The whole fleet on one screen</h2>
<p>Logs, metrics, builds, and rollbacks without leaving the dashboard. Host telemetry included.</p>
</div>
<div class="gallery reveal">
<div class="shot-tabs" role="tablist" aria-label="Product screenshots">
<button class="shot-tab on" role="tab" aria-selected="true" data-shot="dashboard" data-cap="Projects dashboard with host CPU, memory, and disk telemetry.">Dashboard</button>
<button class="shot-tab" role="tab" aria-selected="false" data-shot="canvas" data-cap="Visual service canvas with auto-inferred connections.">Canvas</button>
<button class="shot-tab" role="tab" aria-selected="false" data-shot="service-detail" data-cap="Service detail with metrics, logs, and config tabs.">Service detail</button>
<button class="shot-tab" role="tab" aria-selected="false" data-shot="databases" data-cap="Managed databases with backup and restore.">Databases</button>
</div>
<img id="gallery-img" src="screenshots/dashboard.png" alt="Containr dashboard" loading="lazy">
<p class="cap" id="gallery-cap">Projects dashboard with host CPU, memory, and disk telemetry.</p>
</div>
</div>
</section>
<section id="templates">
<div class="wrap">
<div class="sec-head reveal">
<h2>A catalog worth browsing</h2>
<p>Thirty official templates plus community presets. <a href="templates.html" style="color: var(--accent);">Browse the full catalog</a> or publish your own.</p>
</div>
<div class="marquee reveal" aria-label="Template catalog">
<div class="marquee-track" id="marquee-track">
<span class="tpl"><img src="https://cdn.simpleicons.org/n8n/8b919e" alt="" loading="lazy" onerror="this.remove()">n8n</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/nextcloud/8b919e" alt="" loading="lazy" onerror="this.remove()">Nextcloud</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/immich/8b919e" alt="" loading="lazy" onerror="this.remove()">Immich</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/vaultwarden/8b919e" alt="" loading="lazy" onerror="this.remove()">Vaultwarden</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/grafana/8b919e" alt="" loading="lazy" onerror="this.remove()">Grafana</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/supabase/8b919e" alt="" loading="lazy" onerror="this.remove()">Supabase</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/gitea/8b919e" alt="" loading="lazy" onerror="this.remove()">Gitea</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/uptimekuma/8b919e" alt="" loading="lazy" onerror="this.remove()">Uptime Kuma</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/pihole/8b919e" alt="" loading="lazy" onerror="this.remove()">Pi-hole</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/jellyfin/8b919e" alt="" loading="lazy" onerror="this.remove()">Jellyfin</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/meilisearch/8b919e" alt="" loading="lazy" onerror="this.remove()">Meilisearch</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/mastodon/8b919e" alt="" loading="lazy" onerror="this.remove()">Mastodon</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/homeassistant/8b919e" alt="" loading="lazy" onerror="this.remove()">Home Assistant</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/plausibleanalytics/8b919e" alt="" loading="lazy" onerror="this.remove()">Plausible</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/minio/8b919e" alt="" loading="lazy" onerror="this.remove()">MinIO</span>
<span class="tpl"><img src="https://cdn.simpleicons.org/appwrite/8b919e" alt="" loading="lazy" onerror="this.remove()">Appwrite</span>
</div>
</div>
</div>
</section>
<section>
<div class="wrap">
<div class="sec-head reveal">
<h2>Open for visitors, locked for owners</h2>
<p>The platform doubles as a public showcase. Approved projects are browsable anonymously; secrets never are.</p>
</div>
<div class="access reveal">
<div>
<h3>Anonymous</h3>
<ul>
<li>Browse approved projects</li>
<li>Template catalog and docs</li>
<li>HA status overview</li>
</ul>
</div>
<div>
<h3>Signed in</h3>
<ul>
<li>Projects, services, databases</li>
<li>Logs, variables, builds, deploys</li>
<li>Custom templates</li>
</ul>
</div>
<div>
<h3>Admin</h3>
<ul>
<li>Project approval and moderation</li>
<li>User flags and agent tokens</li>
<li>Platform settings</li>
</ul>
</div>
</div>
</div>
</section>
<div class="cta">
<div class="wrap reveal">
<h2>Run your own cloud.</h2>
<p>One Docker host is all it takes. Free, open source, and yours to keep.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="#install">
Get started
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</a>
<a class="btn btn-ghost" href="https://github.com/Dvorinka/Containr" target="_blank" rel="noopener">Star on GitHub</a>
</div>
</div>
</div>
<footer>
<div class="wrap foot">
<span class="l"><img src="containr.svg" alt="">Containr - MIT License</span>
<nav>
<a href="https://github.com/Dvorinka/Containr" target="_blank" rel="noopener">GitHub</a>
<a href="https://github.com/Dvorinka/Containr/tree/main/docs" target="_blank" rel="noopener">Docs</a>
<a href="https://github.com/Dvorinka/Containr/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener">Contribute</a>
<a href="https://github.com/Dvorinka/Containr/blob/main/SECURITY.md" target="_blank" rel="noopener">Security</a>
</nav>
</div>
</footer>
<script>
// Copy install command
document.getElementById('copy-btn').addEventListener('click', async (e) => {
const cmd = document.getElementById('install-cmd').textContent;
try {
await navigator.clipboard.writeText(cmd);
} catch {
const r = document.createRange();
r.selectNodeContents(document.getElementById('install-cmd'));
const s = getSelection();
s.removeAllRanges();
s.addRange(r);
}
const btn = e.currentTarget;
btn.style.color = 'var(--accent)';
setTimeout(() => (btn.style.color = ''), 1200);
});
// Screenshot gallery tabs
const img = document.getElementById('gallery-img');
const cap = document.getElementById('gallery-cap');
document.querySelectorAll('.shot-tab').forEach((tab) => {
tab.addEventListener('click', () => {
document.querySelectorAll('.shot-tab').forEach((t) => {
t.classList.remove('on');
t.setAttribute('aria-selected', 'false');
});
tab.classList.add('on');
tab.setAttribute('aria-selected', 'true');
img.src = 'screenshots/' + tab.dataset.shot + '.png';
img.alt = 'Containr ' + tab.textContent.trim() + ' screenshot';
cap.textContent = tab.dataset.cap;
});
});
// Duplicate marquee track for seamless loop
const track = document.getElementById('marquee-track');
track.innerHTML += track.innerHTML;
// Scroll reveal
const io = new IntersectionObserver(
(entries) => entries.forEach((en) => en.isIntersecting && en.target.classList.add('in')),
{ threshold: 0.12 }
);
document.querySelectorAll('.reveal').forEach((el) => io.observe(el));
</script>
</body>
</html>