Files
gohoarder/helm/gohoarder
lukaszraczylo 5c8565367c refactor: merge gateway functionality into frontend container
Eliminated duplicate nginx containers by merging gateway reverse proxy
functionality into the frontend container. This simplifies deployment
and reduces resource usage.

Architecture changes:
- Frontend now serves both static files AND reverse proxies to backend
- Single nginx container handles all HTTP routing
- Gateway container removed from builds and Helm chart

Dockerfile.frontend changes:
- Added upstream backend configuration
- Added proxy locations for /api, /health, /metrics, /npm, /pypi, /go, /ws
- Added rate limiting for API and downloads
- Added WebSocket support
- Configurable via BACKEND_HOST and BACKEND_PORT env vars

Helm chart changes:
- Updated frontend deployment to configure backend connection
- Simplified ingress to single route (all traffic → frontend)
- Frontend proxies backend requests internally
- Removed separate frontend/api ingress configurations

GoReleaser changes:
- Removed gohoarder-gateway Docker build
- Now builds: server, scanner, migrate, frontend (4 images)

Benefits:
- Fewer containers to manage
- Reduced complexity in Docker Compose and Kubernetes
- Single point of configuration for routing
- Better resource utilization
2026-01-04 00:30:20 +00:00
..
2026-01-02 23:14:23 +00:00
2026-01-02 23:14:23 +00:00
2026-01-02 23:14:23 +00:00
2026-01-02 23:14:23 +00:00

GoHoarder Helm Chart

A universal package cache proxy supporting npm, PyPI, and Go modules with integrated security scanning.

Features

  • Multi-Registry Support: Proxy for npm, PyPI, and Go modules
  • Security Scanning: Integrated vulnerability scanning with multiple scanners
  • Flexible Storage: Support for filesystem, S3, and SMB storage backends
  • Metadata Storage: SQLite or PostgreSQL for metadata
  • Auto-Configuration: Generates configuration from Helm values
  • Production Ready: Includes health checks, resource limits, and security contexts

Prerequisites

  • Kubernetes 1.19+
  • Helm 3.0+
  • PV provisioner support in the underlying infrastructure (for persistent storage)

Installation

Add Helm Repository

helm repo add gohoarder https://lukaszraczylo.github.io/gohoarder
helm repo update

Install Chart

# Install with default values
helm install gohoarder gohoarder/gohoarder

# Install with custom values
helm install gohoarder gohoarder/gohoarder -f values.yaml

# Install in a specific namespace
helm install gohoarder gohoarder/gohoarder -n gohoarder --create-namespace

Quick Start Examples

Minimal Installation

helm install gohoarder gohoarder/gohoarder \
  --set global.domain=example.com \
  --set ingress.enabled=true

With Security Scanning

helm install gohoarder gohoarder/gohoarder \
  --set security.enabled=true \
  --set security.scanners.trivy.enabled=true \
  --set security.scanners.osv.enabled=true

With S3 Storage

helm install gohoarder gohoarder/gohoarder \
  --set storage.backend=s3 \
  --set storage.s3.bucket=my-bucket \
  --set storage.s3.region=us-east-1 \
  --set storage.s3.accessKeyId=AKIAIOSFODNN7EXAMPLE \
  --set storage.s3.secretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

With Private Container Registry

If using images from a private registry, create an image pull secret and reference it:

# Create a Docker registry secret
kubectl create secret docker-registry ghcr-secret \
  --docker-server=ghcr.io \
  --docker-username=<your-username> \
  --docker-password=<your-token> \
  --docker-email=<your-email> \
  -n gohoarder

# Install with the secret
helm install gohoarder gohoarder/gohoarder \
  --set global.imagePullSecrets[0].name=ghcr-secret \
  -n gohoarder

Or using a values file to reference existing secrets:

global:
  imagePullSecrets:
    - name: ghcr-secret
    - name: dockerhub-secret  # Multiple secrets supported

Auto-create secrets (chart will create them for you):

imageCredentials:
  ghcr-secret:
    registry: ghcr.io
    username: myusername
    password: mytoken
    email: myemail@example.com

global:
  imagePullSecrets:
    - name: ghcr-secret

Note

: Storing credentials in values files is less secure than creating secrets manually. Consider using external secret management solutions like Sealed Secrets or External Secrets Operator for production.

Configuration Methods

GoHoarder supports two configuration methods that can be used together:

1. ConfigMap (Default)

The chart automatically generates a config.yaml from Helm values and mounts it as a ConfigMap. This is the default approach and works out of the box.

2. Environment Variables

You can override any configuration using environment variables with the format GOHOARDER_<CONFIG_KEY> where dots are replaced with underscores.

Example using values file:

server:
  env:
    - name: GOHOARDER_STORAGE_BACKEND
      value: "s3"
    - name: GOHOARDER_STORAGE_S3_BUCKET
      value: "my-bucket"
    # Reference secrets for sensitive data
    - name: GOHOARDER_STORAGE_S3_SECRET_ACCESS_KEY
      valueFrom:
        secretKeyRef:
          name: aws-credentials
          key: secret-access-key
    - name: GOHOARDER_METADATA_POSTGRESQL_PASSWORD
      valueFrom:
        secretKeyRef:
          name: postgres-secret
          key: password

Example using command line:

helm install gohoarder gohoarder/gohoarder \
  --set server.env[0].name=GOHOARDER_STORAGE_BACKEND \
  --set server.env[0].value=s3 \
  --set server.env[1].name=GOHOARDER_LOGGING_LEVEL \
  --set server.env[1].value=debug

Benefits of environment variables:

  • Better integration with Kubernetes secrets
  • Override specific values without modifying ConfigMap
  • Support for secret references (no plain-text passwords)
  • Compatible with external secret management (External Secrets Operator, Sealed Secrets)

Common environment variable mappings:

Config Path Environment Variable
storage.backend GOHOARDER_STORAGE_BACKEND
storage.s3.bucket GOHOARDER_STORAGE_S3_BUCKET
storage.s3.region GOHOARDER_STORAGE_S3_REGION
storage.s3.access_key_id GOHOARDER_STORAGE_S3_ACCESS_KEY_ID
storage.s3.secret_access_key GOHOARDER_STORAGE_S3_SECRET_ACCESS_KEY
metadata.backend GOHOARDER_METADATA_BACKEND
metadata.postgresql.host GOHOARDER_METADATA_POSTGRESQL_HOST
metadata.postgresql.password GOHOARDER_METADATA_POSTGRESQL_PASSWORD
security.enabled GOHOARDER_SECURITY_ENABLED
security.scanners.trivy.enabled GOHOARDER_SECURITY_SCANNERS_TRIVY_ENABLED
logging.level GOHOARDER_LOGGING_LEVEL
logging.format GOHOARDER_LOGGING_FORMAT

Configuration Reference

The following table lists the configurable parameters and their default values.

Global Parameters

Parameter Description Default
nameOverride Override the name of the chart ""
fullnameOverride Override the full name of the chart ""
global.domain Base domain for the deployment gohoarder.local
global.imagePullSecrets Image pull secrets (reference existing) []
imageCredentials Auto-create image pull secrets from credentials {}

Replica Count

Parameter Description Default
replicaCount.server Number of server replicas 1
replicaCount.frontend Number of frontend replicas 1
replicaCount.scanner Number of scanner replicas 1

Image Configuration

Parameter Description Default
image.server.repository Server image repository ghcr.io/lukaszraczylo/gohoarder-server
image.server.tag Server image tag latest
image.server.pullPolicy Server image pull policy IfNotPresent
image.frontend.repository Frontend image repository ghcr.io/lukaszraczylo/gohoarder-frontend
image.frontend.tag Frontend image tag latest
image.frontend.pullPolicy Frontend image pull policy IfNotPresent
image.scanner.repository Scanner image repository ghcr.io/lukaszraczylo/gohoarder-scanner
image.scanner.tag Scanner image tag latest
image.scanner.pullPolicy Scanner image pull policy IfNotPresent

Environment Variables

Parameter Description Default
server.env Additional environment variables for server []
frontend.env Additional environment variables for frontend []
scanner.env Additional environment variables for scanner []

Storage Configuration

Parameter Description Default
storage.backend Storage backend (filesystem, s3, smb) filesystem
storage.filesystem.storageClass Storage class for PVC ""
storage.filesystem.size Storage size 100Gi
storage.filesystem.useHostPath Use hostPath instead of PVC false
storage.filesystem.hostPath Host path for storage /var/lib/gohoarder
storage.s3.endpoint S3 endpoint s3.amazonaws.com
storage.s3.bucket S3 bucket name gohoarder-cache
storage.s3.region S3 region us-east-1

Metadata Configuration

Parameter Description Default
metadata.backend Metadata backend (sqlite, postgresql) sqlite
metadata.sqlite.persistence.enabled Enable persistence for SQLite true
metadata.sqlite.persistence.size SQLite storage size 10Gi
metadata.postgresql.host PostgreSQL host localhost
metadata.postgresql.database PostgreSQL database gohoarder

Security Configuration

Parameter Description Default
security.enabled Enable security scanning false
security.blockOnSeverity Block packages on severity high
security.scanners.trivy.enabled Enable Trivy scanner false
security.scanners.osv.enabled Enable OSV scanner false
security.scanners.grype.enabled Enable Grype scanner false

Authentication

Parameter Description Default
auth.enabled Enable authentication true
auth.adminApiKey Admin API key (auto-generated if empty) ""
auth.existingSecret Use existing secret for admin key ""

Ingress

Parameter Description Default
ingress.enabled Enable ingress false
ingress.className Ingress class name nginx
ingress.frontend.enabled Enable frontend ingress true
ingress.frontend.host Frontend hostname gohoarder.local
ingress.frontend.tls.enabled Enable TLS for frontend false

High Availability & Scaling

Running Multiple Server Replicas

GoHoarder can run with multiple server replicas for high availability and load distribution, but the configuration must be set correctly to avoid data inconsistency.

Compatible Configurations (Safe for Multiple Replicas)

Storage:

  • S3 - Fully compatible, recommended for production HA setups
  • SMB - Compatible, shared network storage
  • Filesystem with RWX - Compatible when using ReadWriteMany storage classes
    • Examples: Longhorn RWX, NFS, CephFS, GlusterFS, Azure Files
    • Uses atomic rename operations for safe concurrent writes
    • Packages are static/immutable - perfect for shared storage
    • Not compatible with local storage or ReadWriteOnce (RWO) PVCs

Metadata:

  • PostgreSQL - Fully compatible, handles concurrent writes, recommended for HA
  • ⚠️ SQLite - Limited compatibility:
    • Uses WAL mode which supports concurrent reads
    • Multiple writers can cause lock contention
    • Works but may have performance issues under high concurrency
    • Only if using shared storage (NFS, etc.)

Option 1: Cloud Storage (S3)

Best for cloud deployments, object storage:

replicaCount:
  server: 3

storage:
  backend: s3
  s3:
    endpoint: s3.amazonaws.com
    region: us-east-1
    bucket: gohoarder-cache

metadata:
  backend: postgresql
  postgresql:
    host: postgres.database.svc.cluster.local
    database: gohoarder

podDisruptionBudget:
  enabled: true
  minAvailable: 1

Option 2: Shared Filesystem (Longhorn/NFS)

Best for on-premises or self-hosted Kubernetes:

replicaCount:
  server: 3

storage:
  backend: filesystem
  filesystem:
    # Use RWX storage class (Longhorn, NFS, CephFS, etc.)
    storageClass: "longhorn"  # or "nfs-client", "cephfs", etc.
    size: "500Gi"
    accessMode: "ReadWriteMany"  # RWX - Critical for multiple replicas!

metadata:
  backend: postgresql  # Or SQLite with RWX storage
  postgresql:
    host: postgres.database.svc.cluster.local
    database: gohoarder

podDisruptionBudget:
  enabled: true
  minAvailable: 1

Why Filesystem with RWX Works:

  • Packages are immutable once cached (static files)
  • Filesystem backend uses atomic rename() operations
  • Race condition safe: If two replicas cache same package, one wins
  • Performance: Local filesystem often faster than object storage for reads

⚠️ What Won't Work with Multiple Replicas

Filesystem storage with local volumes:

# ❌ DON'T DO THIS with multiple replicas
storage:
  backend: filesystem
  filesystem:
    useHostPath: true  # Each replica gets different storage

SQLite with local storage:

# ⚠️ AVOID with multiple replicas
metadata:
  backend: sqlite
  sqlite:
    persistence:
      enabled: true  # Each replica gets its own database

🔄 How It Works

Request Deduplication:

  • Single replica: Uses singleflight to prevent duplicate upstream fetches
  • Multiple replicas: Each replica may fetch the same package independently
  • Mitigation: Package metadata in shared database prevents duplicate downloads once one replica completes

Cache Consistency:

  • Storage backend (S3/SMB) ensures all replicas see the same cached packages
  • Metadata database ensures consistent package information across replicas
  • First replica to cache a package wins, others will use the cached version

Session Affinity:

  • Not required - GoHoarder is stateless
  • Load balancer can distribute requests randomly

Scanner Replicas:

  • Scanner can run as a single replica or multiple
  • If multiple scanners enabled, they share work through the metadata database
  • Package scans are deduplicated via database state

🔬 Technical Details: Concurrent Write Safety

Filesystem Backend with RWX Storage:

The filesystem storage backend uses a temp-file + atomic rename pattern:

1. Write package to: /cache/npm/package@1.0.0.tmp
2. Calculate checksums (MD5, SHA256)
3. Atomic rename: .tmp  /cache/npm/package@1.0.0

Why this is safe for concurrent writes:

  • os.Rename() is atomic on POSIX filesystems
  • If two replicas cache the same package simultaneously:
    • Both write to separate .tmp files
    • Both attempt atomic rename
    • One succeeds, one gets "file exists" error
    • Result: Same file content, no corruption

Package immutability:

  • Packages are versioned and immutable (npm/pypi/go semantics)
  • Same package@version always has identical content
  • Concurrent writes produce identical results
  • No risk of partial/corrupted files

Quota tracking:

  • Per-process mutex (minor inaccuracy across replicas)
  • Conservative: May undercount slightly
  • Not critical for operation

Uninstallation

helm uninstall gohoarder -n gohoarder

Upgrading

helm upgrade gohoarder gohoarder/gohoarder -f values.yaml

Package Manager Configuration

After installation, configure your package managers to use GoHoarder:

NPM

npm config set registry http://<gohoarder-url>/npm/

Go

export GOPROXY=http://<gohoarder-url>/go,direct

PyPI

pip config set global.index-url http://<gohoarder-url>/pypi/simple

Troubleshooting

Check Pod Status

kubectl get pods -n gohoarder
kubectl logs -n gohoarder <pod-name>

Verify Configuration

kubectl get configmap -n gohoarder <release-name>-gohoarder-config -o yaml

Get Admin API Key

kubectl get secret -n gohoarder <release-name>-gohoarder-auth -o jsonpath='{.data.admin-api-key}' | base64 -d

Contributing

Contributions are welcome! Please visit GitHub for more information.

License

See the LICENSE file.