34.1 KB
docker.html
{{template "docs.html" .}}
{{define "title"}}Self-Hosting{{end}}
{{define "content"}}
<article class="space-y-16">
<header>
<div class="w-12 h-1 rounded-full bg-gradient-to-r from-violet-500 to-cyan-500 mb-6"></div>
<h1 class="text-3xl font-bold text-white mb-3">Self-Hosting</h1>
<p class="text-[#888] text-lg">Run ReadySite on your own server with Docker or from source.</p>
</header>
<section>
<a href="/pricing" class="block border border-violet-400/20 rounded-lg p-6 bg-gradient-to-r from-violet-400/[0.06] to-transparent hover:border-violet-400/40 hover:from-violet-400/[0.1] transition-all group">
<div class="flex items-center justify-between gap-4">
<div>
<p class="text-white font-semibold text-lg">Don't want to self-host?</p>
<p class="text-[#888] text-sm mt-1">Launch on ReadySite Cloud — free tier included. We handle servers, SSL, and updates so you don't have to.</p>
</div>
<span class="px-4 py-2 bg-violet-500 text-white text-sm font-medium rounded-lg group-hover:bg-violet-400 transition-colors flex-shrink-0">
View Plans
</span>
</div>
</a>
</section>
<!-- Table of Contents -->
<section class="space-y-4">
<h2 class="text-lg font-semibold text-white">On this page</h2>
<div class="grid sm:grid-cols-2 gap-2 text-sm">
<a href="#docker" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-violet-400"></span> Docker
</a>
<a href="#configuration" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-cyan-400"></span> Configuration
</a>
<a href="#cloud-providers" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> Cloud Providers
</a>
<a href="#database" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-amber-400"></span> Database
</a>
<a href="#source" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-pink-400"></span> Source
</a>
<a href="#cloud-deployment" class="flex items-center gap-2 text-[#888] hover:text-white transition-colors px-3 py-2 rounded-lg hover:bg-white/5">
<span class="w-1.5 h-1.5 rounded-full bg-violet-400"></span> Cloud Deployment
</a>
</div>
</section>
<section id="docker" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h2 class="text-xl font-semibold text-white">Docker</h2>
<p class="text-[#888] mt-1">The fastest way to get started with ReadySite:</p>
</div>
<!-- Registry Toggle -->
<div class="flex gap-2 p-1 bg-[#1a1a1a] border border-white/10 rounded-lg w-fit">
<button id="btn-dockerhub" onclick="selectRegistry('dockerhub')" class="px-4 py-2 text-sm font-medium rounded-md transition-all bg-white/10 text-white">
Docker Hub
</button>
<button id="btn-selfhosted" onclick="selectRegistry('selfhosted')" class="px-4 py-2 text-sm font-medium rounded-md transition-all text-[#888] hover:text-white">
Self-Hosted
</button>
</div>
</div>
<div class="space-y-6">
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">1</span>
<span class="text-white font-medium">Pull the image</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> docker pull <span id="pull-image">ccutch/readysite:latest</span></code></pre>
<button id="copy-pull" onclick="copyCommand('pull')" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<!-- Self-hosted note -->
<p id="selfhosted-note" class="hidden text-sm text-[#888] mt-3">
<span class="text-amber-400">Note:</span> Self-hosted registry requires configuring Docker for insecure registries.
<a href="#insecure-registry" class="text-violet-400 hover:text-violet-300">See below</a>.
</p>
</div>
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">2</span>
<span class="text-white font-medium">Run the container</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> docker run -p 8080:5000 <span id="run-image">ccutch/readysite</span></code></pre>
<button id="copy-run" onclick="copyCommand('run')" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<p class="text-sm text-[#888] mt-3">
Your site will be running at <code class="text-emerald-400 bg-emerald-400/10 px-1.5 py-0.5 rounded">http://localhost:8080</code>
</p>
</div>
</div>
</section>
<section id="insecure-registry" class="space-y-4 hidden">
<h2 class="text-xl font-semibold text-white">Self-Hosted Registry Setup</h2>
<p class="text-[#888]">To pull from the self-hosted registry, configure Docker to allow insecure registries:</p>
<div class="space-y-3">
<p class="text-white text-sm font-medium">Edit <code class="text-violet-400 bg-violet-400/10 px-1.5 py-0.5 rounded">/etc/docker/daemon.json</code>:</p>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]">{
"insecure-registries": ["readysite.org"]
}</code></pre>
<button onclick="navigator.clipboard.writeText('{"insecure-registries": ["readysite.org"]}'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<p class="text-sm text-[#888]">Then restart Docker: <code class="text-[#e5e5e5] bg-white/5 px-1.5 py-0.5 rounded">sudo systemctl restart docker</code></p>
</div>
</section>
<section id="configuration" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<h2 class="text-xl font-semibold text-white">Configuration</h2>
<p class="text-[#888]">Environment variables for customizing your ReadySite instance:</p>
<div class="border border-white/10 rounded-lg divide-y divide-white/10">
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-violet-400 bg-violet-400/10 px-2 py-0.5 rounded font-medium w-fit">PORT</code>
<div>
<p class="text-white text-sm">Server port</p>
<p class="text-[#666] text-sm mt-1">Default: 5000</p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-violet-400 bg-violet-400/10 px-2 py-0.5 rounded font-medium w-fit">ENV</code>
<div>
<p class="text-white text-sm">Environment mode</p>
<p class="text-[#666] text-sm mt-1">Set to "production" for production settings</p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-violet-400 bg-violet-400/10 px-2 py-0.5 rounded font-medium w-fit">AUTH_SECRET</code>
<div>
<p class="text-white text-sm">JWT signing secret</p>
<p class="text-[#666] text-sm mt-1">Required in production. Auto-generated if not set in development.</p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-violet-400 bg-violet-400/10 px-2 py-0.5 rounded font-medium w-fit">TLS_CERT</code>
<div>
<p class="text-white text-sm">Path to TLS certificate</p>
<p class="text-[#666] text-sm mt-1">Enable HTTPS by providing certificate path</p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-violet-400 bg-violet-400/10 px-2 py-0.5 rounded font-medium w-fit">TLS_KEY</code>
<div>
<p class="text-white text-sm">Path to TLS private key</p>
<p class="text-[#666] text-sm mt-1">Required when TLS_CERT is set</p>
</div>
</div>
</div>
</section>
<section id="cloud-providers" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<div>
<h2 class="text-xl font-semibold text-white">Cloud Providers</h2>
<p class="text-[#888] mt-1">Deploy the Docker image to your favorite cloud platform:</p>
</div>
<div class="grid sm:grid-cols-2 gap-4">
<a href="https://fly.io/docs/languages-and-frameworks/dockerfile/" target="_blank" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="flex items-center gap-3 mb-3">
<svg class="w-6 h-6" viewBox="0 0 32 32" fill-rule="evenodd"><path d="M16.06 26.56c.038.01.077.017.112.033s.066.042.098.063l.006.006.032.028.055.05.238.222.43.432.442.495.266.337.235.34.186.317.136.292c.07.172.12.354.138.54l.006.103v.1l-.01.154c-.02.206-.066.4-.143.6a1.96 1.96 0 0 1-.2.372 2 2 0 0 1-.22.266 2.01 2.01 0 0 1-.206.182 2.08 2.08 0 0 1-.18.126l-.155.1c-.3.162-.653.253-1 .288l-.16.012-.178.004a3.24 3.24 0 0 1-.367-.022c-.203-.024-.404-.067-.597-.134a2.45 2.45 0 0 1-.477-.222c-.16-.098-.3-.215-.438-.352l-.23-.295c-.063-.1-.118-.205-.162-.314a2.09 2.09 0 0 1-.141-.57l-.012-.184.002-.147a1.65 1.65 0 0 1 .04-.267 2.18 2.18 0 0 1 .088-.284 3.09 3.09 0 0 1 .123-.276l.18-.32.22-.325.375-.474.427-.47.4-.4.172-.16.14-.126a.56.56 0 0 1 .21-.097zM16.244.004l.275.007.122.007.747.06 1.03.144.075.017 1 .246.282.083.32.1.4.146.302.126.47.22.263.133.532.3.163.098.726.524.177.154.5.452.43.456.118.13.503.662.076.12.388.648.1.207.22.482.228.562.076.218.243.877.2 1.185.033.368.03.53.002.077-.01.592-.007.1-.03.233-.167.945-.025.115-.384 1.186-.357.855-.454.9-.814 1.405-.42.633-.507.75-.366.496-.713.945-.5.6-.723.873-.505.585-.785.876-.494.537-1.495 1.546-.783.762-.433.407-.027.025-.033.03-.043.03-.03.014-.085.028-.204-.01-.018-.006-.1-.07-.014-.013-.015-.013-.058-.054-.173-.162-1.434-1.4-.444-.456-1.135-1.208-.27-.293-1.368-1.584-.383-.47-1.21-1.552-.12-.158-.916-1.335-.248-.397-.666-1.12-.2-.347-.575-1.2-.1-.235-.33-.92L6 11.45l-.093-.378-.08-.413-.063-.462-.024-.28-.01-.527.002-.1.014-.284.115-1.15.027-.148.26-1.148.006-.02.043-.128.183-.53.056-.134.297-.65.202-.378.286-.468.285-.416.198-.26.233-.278.255-.28.208-.2.548-.478.4-.332.484-.325.344-.22.73-.382 1.088-.447.922-.267.362-.08.498-.1.337-.05.52-.064.35-.03.704-.038.26-.003h.063l.224.005zm-.6 1.63l-.3.045c-.154.03-.306.07-.455.12a3.48 3.48 0 0 0-.467.199l-.292.168c-.705.448-1.244 1.12-1.64 1.847l-.188.37-.196.454-.215.6-.2.763-.186.98-.133 1.26-.033.804.018.924a13.86 13.86 0 0 0 .337 2.137c.205.886.472 1.758.773 2.616l1.28 3.178 1.888 3.8.05.093V1.633l-.024.002zm2.665.05a9.82 9.82 0 0 1 1.382.39c.64.234 1.257.54 1.823.92.768.516 1.44 1.172 1.96 1.938a7.25 7.25 0 0 1 .759 1.449c.292.75.46 1.547.53 2.348l.033.632-.012.588c-.035.44-.127.872-.25 1.294a10.06 10.06 0 0 1-.358 1.018l-.57 1.217a23.02 23.02 0 0 1-1.56 2.54c-.7 1.005-1.457 1.97-2.247 2.906l-2.582 2.844-.114.117 1.775-3.598.862-2.06.804-2.316.462-1.777a14.25 14.25 0 0 0 .251-1.554l.048-.684.003-.626-.03-.8c-.065-1.074-.23-2.144-.545-3.174l-.228-.656-.208-.488c-.404-.873-.97-1.7-1.733-2.285l-.256-.186z" fill="url(#fly-grad)"/><defs><linearGradient id="fly-grad" x2="81.448" gradientUnits="userSpaceOnUse" x1="5.74" y1="0" y2="32"><stop offset="0" stop-color="#109cf8"/><stop offset="1" stop-color="#935ee9"/></linearGradient></defs></svg>
<span class="text-white font-medium">Fly.io</span>
</div>
<p class="text-sm text-[#888] mb-3">Deploy globally with automatic SSL and scaling.</p>
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded">fly launch --image ccutch/readysite</code>
</a>
<a href="https://docs.railway.app/guides/dockerfiles" target="_blank" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="flex items-center gap-3 mb-3">
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="white"><path d="M.113 10.27A13.026 13.026 0 000 11.48h18.23c-.064-.125-.15-.237-.235-.347-3.117-4.027-4.793-3.677-7.19-3.78-.8-.034-1.34-.048-4.524-.048-1.704 0-3.555.005-5.358.01-.234.63-.459 1.24-.567 1.737h9.342v1.216H.113v.002zm18.26 2.426H.009c.02.326.05.645.094.961h16.955c.754 0 1.179-.429 1.315-.96zm-17.318 4.28s2.81 6.902 10.93 7.024c4.855 0 9.027-2.883 10.92-7.024H1.056zM11.988 0C7.5 0 3.593 2.466 1.531 6.108l4.75-.005v-.002c3.71 0 3.849.016 4.573.047l.448.016c1.563.052 3.485.22 4.996 1.364.82.621 2.007 1.99 2.712 2.965.654.902.842 1.94.396 2.934-.408.914-1.289 1.458-2.353 1.458H.391s.099.42.249.886h22.748A12.026 12.026 0 0024 12.005C24 5.377 18.621 0 11.988 0z"/></svg>
<span class="text-white font-medium">Railway</span>
</div>
<p class="text-sm text-[#888] mb-3">One-click deploy with automatic builds.</p>
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded">Deploy from Docker Hub</code>
</a>
<a href="https://render.com/docs/docker" target="_blank" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="flex items-center gap-3 mb-3">
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="#46E3B7"><path d="M18.263.007c-3.121-.147-5.744 2.109-6.192 5.082-.018.138-.045.272-.067.405-.696 3.703-3.936 6.507-7.827 6.507-1.388 0-2.691-.356-3.825-.979a.2024.2024 0 0 0-.302.178V24H12v-8.999c0-1.656 1.338-3 2.987-3h2.988c3.382 0 6.103-2.817 5.97-6.244-.12-3.084-2.61-5.603-5.682-5.75"/></svg>
<span class="text-white font-medium">Render</span>
</div>
<p class="text-sm text-[#888] mb-3">Simple cloud hosting with free tier.</p>
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded">ccutch/readysite:latest</code>
</a>
<a href="https://cloud.google.com/run/docs/deploying" target="_blank" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="flex items-center gap-3 mb-3">
<svg class="w-6 h-6" viewBox="0 0 64 64"><path d="M18.8,3.2c-2,0-3.9,1.2-4.9,2.9l0,0L0.8,29c-1,1.8-1,3.9,0,5.7l0,0l13.1,23c1,1.8,2.9,3,4.9,3l0,0h26.3c2.1-0.1,3.9-1.2,4.9-3l0,0l13.1-22.9C63.7,34,64,33,64,32l0,0c0-1-0.3-2-0.8-2.9l0,0L50.1,6.2c-1-1.8-2.9-2.9-4.9-2.9l0,0H18.8z" fill="#4285F4"/><path d="M59.1,42l-9,15.7c-1,1.8-2.9,3-4.9,3h-10L20.5,46l4.3-13.9l-4.3-14.1l4.4,3l6,6l-2.8-9l20.8,14L59.1,42z" fill-opacity="0.07"/><path d="M20.5,18.1l4.4,3l3.5,11.2L25,43l-4.5,3l4.3-13.9L20.5,18.1z M31.8,23L34,30h8.2L31.8,23z M49,32.1L28.1,46l4.3-13.9l-4.3-14L49,32.1z" fill="white"/></svg>
<span class="text-white font-medium">Google Cloud Run</span>
</div>
<p class="text-sm text-[#888] mb-3">Serverless containers with pay-per-use.</p>
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded">gcloud run deploy</code>
</a>
</div>
<p class="text-sm text-[#888]">
Use the Docker Hub image <code class="text-cyan-400 bg-cyan-400/10 px-1.5 py-0.5 rounded">ccutch/readysite</code> with any platform that supports container deployments.
</p>
</section>
<section id="database" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<h2 class="text-xl font-semibold text-white">Database</h2>
<p class="text-[#888]">ReadySite automatically selects the database based on environment variables:</p>
<div class="border border-white/10 rounded-lg divide-y divide-white/10">
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-cyan-400 bg-cyan-400/10 px-2 py-0.5 rounded font-medium w-fit">DB_PATH</code>
<div>
<p class="text-white text-sm">Local database file path</p>
<p class="text-[#666] text-sm mt-1">Example: <code class="text-[#888]">/data/website.db</code></p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-cyan-400 bg-cyan-400/10 px-2 py-0.5 rounded font-medium w-fit">DB_URL</code>
<div>
<p class="text-white text-sm">Remote libSQL server URL</p>
<p class="text-[#666] text-sm mt-1">Example: <code class="text-[#888]">libsql://mydb.turso.io</code></p>
</div>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-start gap-2 sm:gap-4">
<code class="text-sm text-cyan-400 bg-cyan-400/10 px-2 py-0.5 rounded font-medium w-fit">DB_TOKEN</code>
<div>
<p class="text-white text-sm">Authentication token for remote server</p>
<p class="text-[#666] text-sm mt-1">Required when DB_URL is set</p>
</div>
</div>
</div>
<div class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm">
<p class="text-white font-medium mb-2">Selection Logic:</p>
<ul class="space-y-1 text-[#888]">
<li><code class="text-cyan-400">DB_URL</code> + <code class="text-cyan-400">DB_TOKEN</code> → Remote replica (syncs with Turso/libSQL)</li>
<li><code class="text-cyan-400">DB_PATH</code> only → Local SQLite file</li>
<li>Neither → In-memory database (data lost on restart)</li>
</ul>
</div>
<!-- Tip callout -->
<div class="flex gap-3 p-4 rounded-lg border border-emerald-400/20 bg-emerald-400/[0.03]">
<svg class="w-5 h-5 text-emerald-400 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>
<div>
<span class="text-emerald-400 font-medium text-sm">Tip</span>
<p class="text-sm text-[#888] mt-1">For quick development, the in-memory database is great — just run the container with no environment variables. Data resets on restart, which keeps things clean during development.</p>
</div>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]"># Production with persistent storage</span>
<span class="text-[#888]">$</span> docker run -p 8080:5000 \
-v /path/to/data:/data \
-e DB_PATH=/data/website.db \
ccutch/readysite</code></pre>
<button onclick="navigator.clipboard.writeText('docker run -p 8080:5000 -v /path/to/data:/data -e DB_PATH=/data/website.db ccutch/readysite'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
</section>
<section class="space-y-6 border-t border-white/10 pt-8 mt-4">
<div>
<h2 class="text-xl font-semibold text-white">Providers</h2>
<p class="text-[#888] mt-1">Recommended third-party services for production deployments:</p>
</div>
<div class="grid sm:grid-cols-2 gap-4">
<a href="https://turso.tech" target="_blank" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="flex items-center gap-3 mb-3">
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none"><path d="M12 2L3 7v10l9 5 9-5V7l-9-5z" stroke="#4FF8D2" stroke-width="2" stroke-linejoin="round"/><path d="M12 22V12" stroke="#4FF8D2" stroke-width="2"/><path d="M3 7l9 5 9-5" stroke="#4FF8D2" stroke-width="2"/></svg>
<span class="text-white font-medium">Turso</span>
<span class="text-xs text-emerald-400 bg-emerald-400/10 px-2 py-0.5 rounded">libSQL</span>
</div>
<p class="text-sm text-[#888] mb-3">Managed libSQL with embedded replicas. Low-latency reads from local SQLite, writes synced to the cloud.</p>
<code class="text-xs text-cyan-400 bg-cyan-400/10 px-2 py-1 rounded">DB_URL=libsql://mydb.turso.io</code>
</a>
</div>
</section>
<section class="space-y-4 border-t border-white/10 pt-8 mt-4">
<h2 class="text-xl font-semibold text-white">Available Images</h2>
<div class="border border-white/10 rounded-lg divide-y divide-white/10">
<div class="p-4 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div class="flex items-center gap-3">
<code class="text-sm text-cyan-400 bg-cyan-400/10 px-2 py-0.5 rounded">ccutch/readysite</code>
<span class="text-[#888] text-sm">Docker Hub</span>
<a href="https://hub.docker.com/r/ccutch/readysite" target="_blank" class="btn btn-ghost btn-xs">Open</a>
</div>
<span class="flex items-center gap-2 text-xs text-emerald-400">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
Available
</span>
</div>
<div class="p-4 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div class="flex items-center gap-3">
<code class="text-sm text-cyan-400 bg-cyan-400/10 px-2 py-0.5 rounded">readysite.org/website</code>
<span class="text-[#888] text-sm">Self-Hosted Registry</span>
</div>
<span class="flex items-center gap-2 text-xs text-emerald-400">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
Available
</span>
</div>
</div>
</section>
<section id="source" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h2 class="text-xl font-semibold text-white">Source</h2>
<p class="text-[#888] mt-1">For development or customization:</p>
</div>
<a href="https://go.dev/dl/" target="_blank" class="text-sm text-violet-400 hover:text-violet-300 transition-colors">
Requires Go 1.24+
</a>
</div>
<div class="space-y-6">
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">1</span>
<span class="text-white font-medium">Clone the repository</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> git clone https://readysite.org/git/readysite.git
<span class="text-[#888]">$</span> cd readysite</code></pre>
<button onclick="navigator.clipboard.writeText('git clone https://readysite.org/git/readysite.git && cd readysite'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
</div>
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">2</span>
<span class="text-white font-medium">Run the website</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> go run ./website</code></pre>
<button onclick="navigator.clipboard.writeText('go run ./website'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<p class="text-sm text-[#888] mt-3">
Your site will be running at <code class="text-emerald-400 bg-emerald-400/10 px-1.5 py-0.5 rounded">http://localhost:5000</code>
</p>
</div>
</div>
</section>
<section id="cloud-deployment" class="space-y-6 border-t border-white/10 pt-8 mt-4">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h2 class="text-xl font-semibold text-white">Cloud Deployment</h2>
<p class="text-[#888] mt-1">Deploy to DigitalOcean with the launch tool:</p>
</div>
<a href="https://cloud.digitalocean.com/account/api/tokens" target="_blank" class="text-sm text-violet-400 hover:text-violet-300 transition-colors">
Get API Token
</a>
</div>
<!-- Warning callout -->
<div class="flex gap-3 p-4 rounded-lg border border-amber-400/20 bg-amber-400/[0.03]">
<svg class="w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4.5c-.77-.833-2.694-.833-3.464 0L3.34 16.5c-.77.833.192 2.5 1.732 2.5z"/></svg>
<div>
<span class="text-amber-400 font-medium text-sm">Warning</span>
<p class="text-sm text-[#888] mt-1">Keep your API tokens secret. Never commit them to source control or share them publicly. Use environment variables or a secrets manager.</p>
</div>
</div>
<div class="space-y-6">
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">1</span>
<span class="text-white font-medium">Set environment variables</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> export DIGITAL_OCEAN_API_KEY=<span class="text-[#888]">your-api-token</span>
<span class="text-[#888]">$</span> export DIGITAL_OCEAN_PROJECT=<span class="text-[#888]">your-project-uuid</span></code></pre>
<button onclick="navigator.clipboard.writeText('export DIGITAL_OCEAN_API_KEY=your-api-token\nexport DIGITAL_OCEAN_PROJECT=your-project-uuid'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
</div>
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">2</span>
<span class="text-white font-medium">Create a new server</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> go run ./cmd/launch --new website</code></pre>
<button onclick="navigator.clipboard.writeText('go run ./cmd/launch --new website'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<p class="text-sm text-[#888] mt-3">
Creates a new droplet, builds the website, and deploys it automatically.
</p>
</div>
<div>
<div class="flex items-center gap-3 mb-3">
<span class="w-6 h-6 rounded-full bg-white/10 text-xs font-medium text-white flex items-center justify-center">3</span>
<span class="text-white font-medium">Deploy updates</span>
</div>
<div class="relative group">
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><span class="text-[#888]">$</span> go run ./cmd/launch</code></pre>
<button onclick="navigator.clipboard.writeText('go run ./cmd/launch'); showCopied(this)" class="absolute top-3 right-3 text-xs text-[#666] hover:text-white transition-colors opacity-0 group-hover:opacity-100">Copy</button>
</div>
<p class="text-sm text-[#888] mt-3">
Rebuilds and redeploys to existing servers defined in <code class="text-violet-400 bg-violet-400/10 px-1.5 py-0.5 rounded">infra.json</code>
</p>
</div>
</div>
</section>
<!-- What's Next -->
<section class="border-t border-white/10 pt-12 space-y-4">
<h2 class="text-xl font-semibold text-white">What's next?</h2>
<div class="grid sm:grid-cols-2 gap-4">
<a href="/docs/quickstart" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-violet-400 font-medium mb-1">Quickstart</div>
<p class="text-sm text-[#888]">Build your first site in under five minutes.</p>
</a>
<a href="/docs/api" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-cyan-400 font-medium mb-1">API Reference</div>
<p class="text-sm text-[#888]">Full REST API documentation for records, auth, and real-time events.</p>
</a>
<a href="/docs/developers" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-emerald-400 font-medium mb-1">Framework</div>
<p class="text-sm text-[#888]">Build custom applications with the ReadySite Go framework.</p>
</a>
</div>
</section>
</article>
<script>
const registries = {
dockerhub: { pull: 'ccutch/readysite:latest', run: 'ccutch/readysite' },
selfhosted: { pull: 'readysite.org/website:latest', run: 'readysite.org/website' }
};
let currentRegistry = 'dockerhub';
function selectRegistry(registry) {
currentRegistry = registry;
// Update button styles
document.getElementById('btn-dockerhub').className = registry === 'dockerhub'
? 'px-4 py-2 text-sm font-medium rounded-md transition-all bg-white/10 text-white'
: 'px-4 py-2 text-sm font-medium rounded-md transition-all text-[#888] hover:text-white';
document.getElementById('btn-selfhosted').className = registry === 'selfhosted'
? 'px-4 py-2 text-sm font-medium rounded-md transition-all bg-white/10 text-white'
: 'px-4 py-2 text-sm font-medium rounded-md transition-all text-[#888] hover:text-white';
// Update commands
document.getElementById('pull-image').textContent = registries[registry].pull;
document.getElementById('run-image').textContent = registries[registry].run;
// Show/hide self-hosted notes
document.getElementById('selfhosted-note').classList.toggle('hidden', registry !== 'selfhosted');
document.getElementById('insecure-registry').classList.toggle('hidden', registry !== 'selfhosted');
}
function copyCommand(type) {
const cmd = type === 'pull'
? 'docker pull ' + registries[currentRegistry].pull
: 'docker run -p 8080:5000 ' + registries[currentRegistry].run;
navigator.clipboard.writeText(cmd);
const btn = document.getElementById('copy-' + type);
showCopied(btn);
}
</script>
{{end}}