Install Pagifier
Two paths:
- Local quickstart — a complete platform on your laptop with kind, building the images from source. ~15 minutes, nothing needed but Docker. Best way to evaluate or hack on Pagifier.
- Production — a real cluster with S3, RDS, and a proper registry.
Local quickstart (laptop)
Prerequisites: Docker, kind, kubectl, Helm, and the AWS CLI (only used to talk to local MinIO). Clone the repo first:
git clone https://github.com/kcloudev/pagifier-dev.git && cd pagifier-dev
1. Cluster + local registry
./hack/quickstart/kind-with-registry.sh
This creates a kind cluster named pagifier and a local Docker
registry at localhost:5001 that's reachable from inside the cluster
too — that's where your built platform images and the app images
built by Pagifier will live.
Install an ingress controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl -n ingress-nginx wait --for=condition=Ready pod -l app.kubernetes.io/component=controller --timeout=180s
2. Dependencies: MinIO + PostgreSQL
kubectl apply -f hack/quickstart/minio.yaml -f hack/quickstart/postgres.yaml
kubectl -n pagifier-deps wait --for=condition=Available deploy --all --timeout=180s
MinIO gives you both S3 buckets (pagifier-artifacts,
pagifier-platform — a Job creates them); Postgres holds deploy
history. Both are throwaway dev instances.
Seed the platform configuration (templates, profiles, runtime images) and the database schema:
# platform config → MinIO
kubectl -n pagifier-deps port-forward svc/minio 9000:9000 >/dev/null 2>&1 &
AWS_ACCESS_KEY_ID=pagifier AWS_SECRET_ACCESS_KEY=pagifier-dev-secret \
aws --endpoint-url http://localhost:9000 s3 sync examples/platform-config/ s3://pagifier-platform/
# schema → Postgres
kubectl -n pagifier-deps exec deploy/postgres -- psql -U pagifier -d pagifier \
< docs/db/schema.sql
3. Build your own images
make images REGISTRY=localhost:5001/pagifier VERSION=dev
docker push localhost:5001/pagifier/api:dev
docker push localhost:5001/pagifier/operator:dev
docker push localhost:5001/pagifier/builder:dev
Three images from source: the API server, the operator, and the builder
(which carries buildctl and cosign into build pods).
4. Install Pagifier
kubectl create namespace pagifier-system
kubectl -n pagifier-system create secret generic pagifier-api-tokens \
--from-literal=tokens='dev-token:acme'
helm install pagifier charts/pagifier -n pagifier-system \
--set image.api=localhost:5001/pagifier/api:dev \
--set image.operator=localhost:5001/pagifier/operator:dev \
--set image.builder=localhost:5001/pagifier/builder:dev \
--set registry.url=pagifier-registry:5000/apps \
--set registry.insecure=true \
--set storage.endpoint=http://minio.pagifier-deps.svc:9000 \
--set storage.artifactBucket=pagifier-artifacts \
--set storage.configBucket=pagifier-platform \
--set api.databaseURL=postgres://pagifier:pagifier-dev-secret@postgres.pagifier-deps.svc:5432/pagifier
kubectl -n pagifier-system set env deploy/pagifier-api deploy/pagifier-operator \
AWS_ACCESS_KEY_ID=pagifier AWS_SECRET_ACCESS_KEY=pagifier-dev-secret
kubectl -n pagifier-system wait --for=condition=Available deploy --all --timeout=180s
Two values matter for local: registry.url points app-image pushes at
the in-cluster name of your local registry, and registry.insecure=true
lets BuildKit push over plain HTTP (never use it beyond a laptop).
5. Deploy something
kubectl -n pagifier-system port-forward svc/pagifier-api 8443:80 >/dev/null 2>&1 &
cd examples/minimal
sed -i '' 's/environment = "prod"/environment = "dev"/; s/my-app.company.com/my-app.localtest.me:8080/' pagifier.toml
zip -q app.zip pagifier.toml # any static content works; the template builds real apps
curl -H "Authorization: Bearer dev-token" \
-F config=@pagifier.toml -F archive=@app.zip \
"http://localhost:8443/v1/applications/my-app/environments/dev/deployments?wait=true"
Watch the build stream, then open http://my-app.localtest.me:8080
(localtest.me resolves to 127.0.0.1; port 8080 is the kind ingress
mapping). The console is at http://localhost:8443/console — paste
dev-token.
Tear it all down with kind delete cluster --name pagifier.
Production install
You provide: Kubernetes ≥ 1.29 with an nginx ingress controller, object storage, PostgreSQL, and an OCI registry. Optional integrations — External Secrets Operator, KEDA, Prometheus, external-dns, a Gateway — each enables the matching feature.
Pick your cloud
Ready-made values presets live in examples/values/; each file
documents the exact identity bindings it needs:
| Cluster | Storage | Registry | Identity | Preset |
|---|---|---|---|---|
| EKS | S3 (storage.provider: s3) | ECR | IRSA role annotation | values-eks.yaml |
| GKE | GCS (storage.provider: gcs) | Artifact Registry | Workload Identity annotation | values-gke.yaml |
| AKS | Azure Blob (storage.provider: azure + azureAccountURL) | ACR | Azure Workload Identity annotation | values-aks.yaml |
| Anywhere else | MinIO / any S3-compatible (storage.endpoint) | Harbor/GHCR + registry.pushSecret | mounted credentials | the quickstart flow above |
Credentials are always ambient — Pagifier never stores cloud keys. The per-component access matrix (API reads config + writes artifacts; build jobs read artifacts only; the operator touches no storage) is identical on every cloud; see S3 configuration.
DNS on every cloud works through
external-dns: install
it with a service-account identity scoped to your zone (Route53 /
Cloud DNS / Azure DNS per the preset comments) and records for every
ingress host appear and disappear automatically. Projects tune records
with the dns block (ttl, target).
CDN per cloud is a platform document: publish
cdn/<provider>.yaml (seed examples for CloudFront, Cloud CDN, Front
Door, and Cloudflare ship in examples/platform-config/cdn/) and
projects opt in with one line — cdn = "cloudfront". The definitions
pair with dns.target so the hostname resolves to the edge, and with
origin-protection headers so only the CDN reaches the cluster.
1. Images
Use published images, or build and push your own:
make push REGISTRY=ghcr.io/yourorg/pagifier VERSION=1.0.0
2. Storage and database
aws s3 mb s3://pagifier-artifacts && aws s3 mb s3://pagifier-platform
make sync-platform-config CONFIG_BUCKET=pagifier-platform # then customize!
psql "$DATABASE_URL" -f docs/db/schema.sql
Review examples/platform-config/ before syncing — the environment
profiles and templates in it become your platform's behavior. See
S3 configuration for what every document
does.
3. Install
kubectl create namespace pagifier-system
kubectl -n pagifier-system create secret generic pagifier-api-tokens \
--from-literal=tokens='TEAM_A_TOKEN:team-a,TEAM_B_TOKEN:team-b'
helm install pagifier charts/pagifier -n pagifier-system \
--set image.api=ghcr.io/yourorg/pagifier/api:1.0.0 \
--set image.operator=ghcr.io/yourorg/pagifier/operator:1.0.0 \
--set image.builder=ghcr.io/yourorg/pagifier/builder:1.0.0 \
--set registry.url=123456789.dkr.ecr.us-east-1.amazonaws.com/pagifier \
--set storage.artifactBucket=pagifier-artifacts \
--set storage.configBucket=pagifier-platform \
--set storage.region=us-east-1 \
--set api.databaseURL="$DATABASE_URL" \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789:role/pagifier
On EKS, grant S3/ECR through IRSA (the annotation above); elsewhere use
registry.pushSecret and mounted credentials. The exact IAM policies
per component are in
S3 configuration.
4. Recommended production values
| Value | Recommendation |
|---|---|
buildkitPool.enabled=true | Shared layer cache — dramatically faster builds |
operator.maxConcurrentBuilds=10 | Protects the pool and registry from herds |
prometheusURL=… | Enables metric-gated canaries |
notifyWebhook=… | Slack/Teams deploy notifications |
preview.domain=preview.company.com | Per-PR preview URLs (wildcard DNS + TLS) |
signingSecret=pagifier-cosign | Image signing + SLSA provenance |
api.tokensSecret | Rotate tokens by updating the secret |
5. Verify
kubectl -n pagifier-system get pods
curl https://pagifier.company.com/healthz # ok
curl -H "Authorization: Bearer $TOKEN" --data-binary @pagifier.toml \
https://pagifier.company.com/v1/validate
Then hand your developers the getting started page and a token.
Upgrades and rollback (of Pagifier itself)
The API and operator are stateless: helm upgrade / helm rollback.
Leader election keeps operator upgrades non-disruptive; in-flight
builds survive restarts (Jobs are owned by Releases). Because releases
embed their resolved configuration, upgrading Pagifier never changes
running applications.