Files

142 lines
5.7 KiB
HTML

{{ define "install" }}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Install ATCR Credential Helper - ATCR</title>
{{ template "head" . }}
</head>
<body>
{{ template "nav" . }}
<main class="container">
<div class="install-page">
<h1>Install ATCR Credential Helper</h1>
<p>The ATCR credential helper enables Docker to authenticate with ATCR registries using your ATProto identity.</p>
<div class="install-section">
<h2>Quick Install</h2>
<div class="platform-tabs">
<button class="platform-tab active" onclick="showPlatform('linux')">Linux / macOS</button>
<button class="platform-tab" onclick="showPlatform('windows')">Windows</button>
</div>
<div class="platform-content active" id="linux-content">
<h3>Using install script</h3>
<div class="code-block"><code>curl -fsSL {{ .RegistryURL }}/static/install.sh | bash</code></div>
<h3>Manual download</h3>
<div class="code-block"><code>curl -fsSLO {{ .RegistryURL }}/static/install.sh
chmod +x install.sh
./install.sh</code></div>
</div>
<div class="platform-content" id="windows-content">
<h3>Using PowerShell (Run as Administrator)</h3>
<div class="code-block"><code>iwr -useb {{ .RegistryURL }}/static/install.ps1 | iex</code></div>
<h3>Manual download</h3>
<div class="code-block"><code>Invoke-WebRequest -Uri {{ .RegistryURL }}/static/install.ps1 -OutFile install.ps1
.\install.ps1</code></div>
</div>
</div>
<div class="install-section">
<h2>Configure Docker</h2>
<p>After installation, configure Docker to use the credential helper:</p>
<h3>Create or edit <code>~/.docker/config.json</code></h3>
<div class="code-block"><code>{
"credHelpers": {
"{{ .RegistryURL }}": "atcr"
}
}</code></div>
<div class="note">
<strong>Note:</strong> If you have an existing <code>config.json</code>, add the <code>credHelpers</code> entry to your existing configuration.
</div>
</div>
<div class="install-section">
<h2>Authentication</h2>
<p>The credential helper will automatically prompt for authentication when you push or pull:</p>
<div class="code-block"><code>docker push {{ .RegistryURL }}/yourhandle/myapp:latest</code></div>
<p>This will:</p>
<ol>
<li>Open your browser for device authorization</li>
<li>Display a code to confirm</li>
<li>Store credentials securely</li>
<li>Proceed with your push/pull operation</li>
</ol>
<div class="success">
<strong>Success!</strong> Once authenticated, Docker commands work normally without any additional steps.
</div>
</div>
<div class="install-section">
<h2>Alternative: Use docker login</h2>
<p>You can also use <code>docker login</code> with your ATProto app password:</p>
<ol>
<li>Generate an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank">bsky.app/settings/app-passwords</a></li>
<li>Run: <code>docker login {{ .RegistryURL }}</code></li>
<li>Enter your handle as username</li>
<li>Enter your app password</li>
</ol>
<div class="note">
<strong>Note:</strong> Create an app password at <a href="https://bsky.app/settings/app-passwords" target="_blank">bsky.app/settings/app-passwords</a>.
</div>
</div>
<div class="install-section">
<h2>Troubleshooting</h2>
<h3>Command not found</h3>
<p>Ensure the credential helper is in your PATH:</p>
<div class="code-block"><code># Check if installed
which docker-credential-atcr
# Add to PATH if needed
export PATH="/usr/local/bin:$PATH"</code></div>
<h3>Still having issues?</h3>
<p>Check the <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/INSTALLATION.md">full documentation</a> or <a href="https://tangled.org/@evan.jarrett.net/at-container-registry/issues">open an issue</a>.</p>
</div>
<div class="install-section">
<h2>Security</h2>
<ul>
<li>Credentials are stored in <code>~/.atcr/device.json</code> with secure permissions (0600)</li>
<li>Device secrets are issued per-device and can be revoked anytime</li>
<li>No passwords are stored locally</li>
<li>Uses ATProto OAuth with device authorization flow</li>
</ul>
</div>
</div>
</main>
<script>
function showPlatform(platform) {
// Update tabs
document.querySelectorAll('.platform-tab').forEach(tab => {
tab.classList.remove('active');
});
event.target.classList.add('active');
// Update content
document.querySelectorAll('.platform-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(platform + '-content').classList.add('active');
}
</script>
<div id="modal"></div>
</body>
</html>
{{ end }}