deployment fixes. add open graph

This commit is contained in:
Evan Jarrett
2025-12-18 11:19:49 -06:00
parent 4063544cdf
commit 044d408cf8
9 changed files with 141 additions and 21 deletions
+7 -2
View File
@@ -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
# ==============================================================================
+1 -1
View File
@@ -6,7 +6,7 @@ when:
engine: kubernetes
image: golang:1.25-trixie
architecture: arm64
architecture: amd64
steps:
- name: Download and Generate
+23 -1
View File
@@ -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
+10
View File
@@ -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:
+5 -11
View File
@@ -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)
#
+1 -6
View File
@@ -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
+1
View File
@@ -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" />
+54
View File
@@ -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
}