mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-29 04:06:58 +00:00
deployment fixes. add open graph
This commit is contained in:
+7
-2
@@ -29,8 +29,8 @@ AWS_ACCESS_KEY_ID=your_access_key
|
||||
AWS_SECRET_ACCESS_KEY=your_secret_key
|
||||
|
||||
# S3 Region
|
||||
# Examples: us-east-1, us-west-2, eu-west-1
|
||||
# For UpCloud: us-chi1, us-nyc1, de-fra1, uk-lon1, sg-sin1
|
||||
# For third-party S3 providers, this is ignored when S3_ENDPOINT is set,
|
||||
# but must be a valid AWS region (e.g., us-east-1) to pass validation.
|
||||
# Default: us-east-1
|
||||
AWS_REGION=us-east-1
|
||||
|
||||
@@ -61,6 +61,11 @@ S3_BUCKET=atcr-blobs
|
||||
# Default: false
|
||||
HOLD_PUBLIC=false
|
||||
|
||||
# ATProto relay endpoint for requesting crawl on startup
|
||||
# This makes the hold's embedded PDS discoverable by the relay network
|
||||
# Default: https://bsky.network (set to empty string to disable)
|
||||
# HOLD_RELAY_ENDPOINT=https://bsky.network
|
||||
|
||||
# ==============================================================================
|
||||
# Embedded PDS Configuration
|
||||
# ==============================================================================
|
||||
|
||||
@@ -6,7 +6,7 @@ when:
|
||||
|
||||
engine: kubernetes
|
||||
image: golang:1.25-trixie
|
||||
architecture: arm64
|
||||
architecture: amd64
|
||||
|
||||
steps:
|
||||
- name: Download and Generate
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# Build targets for the ATProto Container Registry
|
||||
|
||||
.PHONY: all build build-appview build-hold build-credential-helper build-oauth-helper \
|
||||
generate test test-race test-verbose lint clean help install-credential-helper
|
||||
generate test test-race test-verbose lint clean help install-credential-helper \
|
||||
develop develop-detached develop-down
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
@@ -80,6 +81,27 @@ install-credential-helper: build-credential-helper ## Install credential helper
|
||||
install -m 755 bin/docker-credential-atcr /usr/local/sbin/docker-credential-atcr
|
||||
@echo "✓ Installed docker-credential-atcr to /usr/local/sbin/"
|
||||
|
||||
##@ Docker Targets
|
||||
|
||||
develop: ## Build Docker images and start docker-compose for development
|
||||
@echo "→ Building Docker images..."
|
||||
docker-compose build
|
||||
@echo "→ Starting docker-compose..."
|
||||
docker-compose up
|
||||
|
||||
develop-detached: ## Build and start docker-compose in detached mode
|
||||
@echo "→ Building Docker images..."
|
||||
docker-compose build
|
||||
@echo "→ Starting docker-compose (detached)..."
|
||||
docker-compose up -d
|
||||
@echo "✓ Services started in background"
|
||||
@echo " AppView: http://localhost:5000"
|
||||
@echo " Hold: http://localhost:8080"
|
||||
|
||||
develop-down: ## Stop docker-compose services
|
||||
@echo "→ Stopping docker-compose..."
|
||||
docker-compose down
|
||||
|
||||
##@ Utility Targets
|
||||
|
||||
clean: ## Remove built binaries and generated assets
|
||||
|
||||
@@ -179,6 +179,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Request crawl from relay to make PDS discoverable
|
||||
if cfg.Server.RelayEndpoint != "" {
|
||||
slog.Info("Requesting crawl from relay", "relay", cfg.Server.RelayEndpoint)
|
||||
if err := hold.RequestCrawl(cfg.Server.RelayEndpoint, cfg.Server.PublicURL); err != nil {
|
||||
slog.Warn("Failed to request crawl from relay", "error", err)
|
||||
} else {
|
||||
slog.Info("Crawl requested successfully")
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for signal or server error
|
||||
select {
|
||||
case err := <-serverErr:
|
||||
|
||||
@@ -115,10 +115,10 @@ AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
|
||||
# S3 Region (for distribution S3 driver)
|
||||
# UpCloud regions: us-chi1, us-nyc1, de-fra1, uk-lon1, sg-sin1, etc.
|
||||
# Note: Use AWS_REGION (not S3_REGION) - this is what the hold service expects
|
||||
# For third-party S3 providers (UpCloud, Storj, Minio), this value is ignored
|
||||
# when S3_ENDPOINT is set, but must be a valid AWS region to pass validation.
|
||||
# Default: us-east-1
|
||||
AWS_REGION=us-chi1
|
||||
AWS_REGION=us-east-1
|
||||
|
||||
# S3 Bucket Name
|
||||
# Create this bucket in UpCloud Object Storage
|
||||
@@ -134,11 +134,6 @@ S3_BUCKET=atcr
|
||||
# Custom domains break presigned URL generation
|
||||
S3_ENDPOINT=https://6vmss.upcloudobjects.com
|
||||
|
||||
# S3 Region Endpoint (alternative to S3_ENDPOINT)
|
||||
# Use this if your S3 driver requires region-specific endpoint format
|
||||
# Example: s3.us-chi1.upcloudobjects.com
|
||||
# S3_REGION_ENDPOINT=
|
||||
|
||||
# ==============================================================================
|
||||
# AppView Configuration
|
||||
# ==============================================================================
|
||||
@@ -231,13 +226,12 @@ ATCR_BACKFILL_INTERVAL=1h
|
||||
# ☐ Set HOLD_OWNER (your ATProto DID)
|
||||
# ☐ Set HOLD_DATABASE_DIR (default: /var/lib/atcr-hold) - enables embedded PDS
|
||||
# ☐ Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
||||
# ☐ Set AWS_REGION (e.g., us-chi1)
|
||||
# ☐ Set S3_BUCKET (created in UpCloud Object Storage)
|
||||
# ☐ Set S3_ENDPOINT (UpCloud endpoint or custom domain)
|
||||
# ☐ Set S3_ENDPOINT (UpCloud bucket endpoint, e.g., https://6vmss.upcloudobjects.com)
|
||||
# ☐ Configured DNS records:
|
||||
# - A record: atcr.io → server IP
|
||||
# - A record: hold01.atcr.io → server IP
|
||||
# - CNAME: blobs.atcr.io → [bucket].us-chi1.upcloudobjects.com
|
||||
# - CNAME: blobs.atcr.io → [bucket].upcloudobjects.com
|
||||
# ☐ Disabled Cloudflare proxy (gray cloud, not orange)
|
||||
# ☐ Waited for DNS propagation (check with: dig atcr.io)
|
||||
#
|
||||
|
||||
@@ -109,10 +109,9 @@ services:
|
||||
# S3/UpCloud Object Storage configuration
|
||||
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-}
|
||||
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-}
|
||||
AWS_REGION: ${AWS_REGION:-us-chi1}
|
||||
AWS_REGION: ${AWS_REGION:-us-east-1}
|
||||
S3_BUCKET: ${S3_BUCKET:-atcr-blobs}
|
||||
S3_ENDPOINT: ${S3_ENDPOINT:-}
|
||||
S3_REGION_ENDPOINT: ${S3_REGION_ENDPOINT:-}
|
||||
|
||||
# Logging
|
||||
ATCR_LOG_LEVEL: ${ATCR_LOG_LEVEL:-debug}
|
||||
@@ -160,8 +159,6 @@ configs:
|
||||
# Preserve original host header
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
}
|
||||
|
||||
# Enable compression
|
||||
@@ -183,8 +180,6 @@ configs:
|
||||
# Preserve original host header
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
}
|
||||
|
||||
# Enable compression
|
||||
|
||||
@@ -70,6 +70,7 @@ func setupTestDB(t *testing.T) *sql.DB {
|
||||
platform_os TEXT,
|
||||
platform_variant TEXT,
|
||||
platform_os_version TEXT,
|
||||
is_attestation BOOLEAN DEFAULT FALSE,
|
||||
reference_index INTEGER NOT NULL,
|
||||
PRIMARY KEY(manifest_id, reference_index)
|
||||
);
|
||||
|
||||
@@ -2,6 +2,45 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
{{ if .ViewedUser }}
|
||||
<!-- User Profile Page -->
|
||||
<meta property="og:title" content="{{ .ViewedUser.Handle }} - ATCR">
|
||||
<meta property="og:description" content="Container images by {{ .ViewedUser.Handle }} on ATCR">
|
||||
{{ if .ViewedUser.Avatar }}
|
||||
<meta property="og:image" content="{{ .ViewedUser.Avatar }}">
|
||||
{{ else }}
|
||||
<meta property="og:image" content="{{ .RegistryURL }}/web-app-manifest-512x512.png">
|
||||
{{ end }}
|
||||
<meta property="og:type" content="profile">
|
||||
<meta property="og:url" content="{{ .RegistryURL }}/u/{{ .ViewedUser.Handle }}">
|
||||
{{ else if .Repository }}
|
||||
<!-- Repository Page -->
|
||||
<meta property="og:title" content="{{ .Owner.Handle }}/{{ .Repository.Name }} - ATCR">
|
||||
{{ if .Repository.Description }}
|
||||
<meta property="og:description" content="{{ .Repository.Description }}">
|
||||
{{ else }}
|
||||
<meta property="og:description" content="Container image on ATCR">
|
||||
{{ end }}
|
||||
{{ if .Repository.IconURL }}
|
||||
<meta property="og:image" content="{{ .Repository.IconURL }}">
|
||||
{{ else if .Owner.Avatar }}
|
||||
<meta property="og:image" content="{{ .Owner.Avatar }}">
|
||||
{{ else }}
|
||||
<meta property="og:image" content="{{ .RegistryURL }}/web-app-manifest-512x512.png">
|
||||
{{ end }}
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ .RegistryURL }}/r/{{ .Owner.Handle }}/{{ .Repository.Name }}">
|
||||
{{ else }}
|
||||
<!-- Home Page / Default -->
|
||||
<meta property="og:title" content="ATCR - Distributed Container Registry">
|
||||
<meta property="og:description" content="Push and pull Docker images on the AT Protocol">
|
||||
<meta property="og:image" content="{{ .RegistryURL }}/web-app-manifest-512x512.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ .RegistryURL }}">
|
||||
{{ end }}
|
||||
<meta property="og:site_name" content="ATCR">
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
package hold
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -67,6 +71,10 @@ type ServerConfig struct {
|
||||
// DisablePresignedURLs forces proxy mode even with S3 configured (for testing) (from env: DISABLE_PRESIGNED_URLS)
|
||||
DisablePresignedURLs bool `yaml:"disable_presigned_urls"`
|
||||
|
||||
// RelayEndpoint is the ATProto relay URL to request crawl from on startup (from env: HOLD_RELAY_ENDPOINT)
|
||||
// If empty, no crawl request is made. Default: https://bsky.network
|
||||
RelayEndpoint string `yaml:"relay_endpoint"`
|
||||
|
||||
// ReadTimeout for HTTP requests
|
||||
ReadTimeout time.Duration `yaml:"read_timeout"`
|
||||
|
||||
@@ -103,6 +111,7 @@ func LoadConfigFromEnv() (*Config, error) {
|
||||
cfg.Server.Public = os.Getenv("HOLD_PUBLIC") == "true"
|
||||
cfg.Server.TestMode = os.Getenv("TEST_MODE") == "true"
|
||||
cfg.Server.DisablePresignedURLs = os.Getenv("DISABLE_PRESIGNED_URLS") == "true"
|
||||
cfg.Server.RelayEndpoint = getEnvOrDefault("HOLD_RELAY_ENDPOINT", "https://bsky.network")
|
||||
cfg.Server.ReadTimeout = 5 * time.Minute // Increased for large blob uploads
|
||||
cfg.Server.WriteTimeout = 5 * time.Minute // Increased for large blob uploads
|
||||
|
||||
@@ -180,3 +189,48 @@ func getEnvOrDefault(key, defaultValue string) string {
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// RequestCrawl sends a crawl request to the ATProto relay for the given hostname.
|
||||
// This makes the hold's PDS discoverable by the relay network.
|
||||
func RequestCrawl(relayEndpoint, publicURL string) error {
|
||||
if relayEndpoint == "" {
|
||||
return nil // No relay configured, skip
|
||||
}
|
||||
|
||||
// Extract hostname from public URL
|
||||
parsed, err := url.Parse(publicURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse public URL: %w", err)
|
||||
}
|
||||
hostname := parsed.Host
|
||||
|
||||
// Build the request URL
|
||||
requestURL := relayEndpoint + "/xrpc/com.atproto.sync.requestCrawl"
|
||||
|
||||
// Create request body
|
||||
body := map[string]string{"hostname": hostname}
|
||||
bodyJSON, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal request body: %w", err)
|
||||
}
|
||||
|
||||
// Make the request
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
req, err := http.NewRequest("POST", requestURL, bytes.NewReader(bodyJSON))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("relay returned status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user