Beta This is a new service — your feedback will help us to improve it.

Getting started

60 seconds

You need an account with billing set up and kubectl mode enabled. Enabling kubectl mode is an owner action and requires TOTP; see kubectl mode if the button is not there yet.

Download your kubeconfig from https://app.dollarbox.dev/kubectl/<your-org-slug>/kubeconfig/. It saves as dollarbox-<your-org-slug>.kubeconfig.

export KUBECONFIG=./dollarbox-your-org.kubeconfig
kubectl get pods

Expected on a fresh org:

No resources found in org-2f1c8a04-... namespace.

That output means the token authenticated, the namespace exists, and your context is already scoped to it. You never pass -n. If you get error: You must be logged in to the server (Unauthorized), the credential was revoked or replaced — download it again.

Prefer not to write manifests? Provision a container does the same thing from the control panel.

IPv6

This is the failure mode that catches most people. DollarBox workloads are reachable over IPv6 only. There is no public IPv4 address for your service.

Your kubeconfig points at the cluster API over IPv4, so kubectl itself works from an IPv4-only network. IPv6 is what you need to reach the service you deploy.

Test your machine:

curl -6 https://test-ipv6.com/

Content back means you have working IPv6. Nothing back means you do not, and the failure you will hit later looks like this:

$ curl -6 https://app.example.com/
curl: (7) Failed to connect to app.example.com port 443: Network is unreachable

Note the shape of it: DNS resolves fine and dig AAAA app.example.com returns your address. Only the connection fails. This is not a DNS problem and not a DollarBox problem.

On an IPv4-only network:

For production traffic from IPv4 clients, see Reaching your service from IPv4 clients below.

What you actually get

One Kubernetes namespace per org, named org-<uuid>. You cannot create namespaces yourself; extra child namespaces (org-<uuid>-<slug>) are provisioned through the control panel or API and carve a slice out of the same paid capacity.

Quota

Quota scales with the number of dollarboxes you subscribe to. For N subscribed dollarboxes at €1/month each excluding VAT, the org-quota ResourceQuota is:

Quota keyLimit
podsN + 1
count/podsN + 5
requests.memory / limits.memoryN Gi
requests.cpuN × 100m
limits.cpuN × 1000m
requests.ephemeral-storage / limits.ephemeral-storageN × 5 Gi
requests.storageN × 10 Gi, plus your pre-paid volume pool
persistentvolumeclaimsN × 2, plus your pre-paid volume count
services.loadbalancersN
count/servicesN × 5
count/secretsN × 10, minimum 5
count/configmapsN × 10
count/deployments.appsN × 2, minimum 10
count/replicasets.apps11 × the deployment limit
count/eventsN × 200, minimum 500

An org-limits LimitRange fills in what you leave out: default request 100m CPU / 256Mi memory / 256Mi ephemeral storage, default limit 1000m CPU / 1Gi memory / 2Gi ephemeral storage, and a hard per-container ceiling of 1000m CPU / 1Gi memory / 5Gi ephemeral storage. A single container cannot exceed one core, one gigabyte of memory or five gigabytes of node-local scratch no matter how many dollarboxes you buy — buy more to run more pods, not bigger ones. Ephemeral storage is the writable image layer, emptyDir volumes and logs; a container that writes past its limit is evicted on its own, so put anything larger on a volume.

Separately from quota, your account has a plan cap. The default tier allows 5 containers and 50 GB of storage; raising it is a quota-increase request in the control panel.

Already in your namespace

Everything labelled dollarbox.io/managed-by=control-panel is read-only from kubectl, and the container- name prefix is reserved.

What your credential can do

ResourcesVerbs
pods, pods/log, pods/exec, pods/portforwardget, list, watch, create, update, patch, delete
services, configmaps, persistentvolumeclaims, eventsget, list, watch, create, update, patch, delete
deployments, deployments/scale, replicasetsget, list, watch, create, update, patch, delete
secretscreate, update, patch, delete — no get, list or watch

You can write a Secret and mount it. You cannot read one back through the API. Deleting one works by name. Keep the source of truth somewhere else.

The credential is namespace-wide, not per-user: anyone with a kubeconfig for your org can exec into any pod in it and consume shared quota.

What you cannot create

Not in your RBAC at all: Ingress, StatefulSet, Job, CronJob, DaemonSet, NetworkPolicy, VolumeSnapshot, ServiceAccount, Role, RoleBinding, Namespace, PersistentVolume, HPA.

Rejected by admission control even though the resource type is allowed:

Pods run under PodSecurity restricted. Set runAsNonRoot, drop all capabilities, disable privilege escalation, and use the RuntimeDefault seccomp profile, or the pod is rejected.

Deploy something real

There is no Ingress on DollarBox. Tenants have no Ingress permissions and the platform terminates no TLS for you. A public service is a Deployment plus an IPv6 LoadBalancer Service on one of your reserved addresses, with TLS handled inside your pod or at a proxy you put in front. That is the whole model.

1. Find a reserved address

kubectl get configmap container-reserved-ipv6 -o jsonpath='{.data.addresses}'

Each subscribed dollarbox reserves one address. They are sticky — yours across restarts, deletes, recreates and node failover — and a LoadBalancer Service that does not name one of them is rejected. The same list is on the kubectl page in the control panel.

2. Apply the workload

Save as web.yaml, replacing the annotation value with one of your reserved addresses. This uses traefik/whoami, which runs unprivileged on a high port and is what DollarBox's own smoke test deploys.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: whoami
          image: traefik/whoami:v1.10
          args: ["--port", "8080"]
          ports:
            - containerPort: 8080
          securityContext:
            runAsUser: 65532
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          resources:
            requests:
              memory: 32Mi
              cpu: 10m
            limits:
              memory: 64Mi
              cpu: 100m
---
apiVersion: v1
kind: Service
metadata:
  name: web
  annotations:
    metallb.io/loadBalancerIPs: <one-of-your-reserved-addresses>
spec:
  type: LoadBalancer
  ipFamilies: [IPv6]
  ipFamilyPolicy: SingleStack
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
kubectl apply -f web.yaml

Prove the pod is up:

kubectl rollout status deployment/web --timeout=120s

deployment "web" successfully rolled out. If it hangs, kubectl get pods and kubectl describe pod -l app=web — a restricted violation shows up there as a rejected create, and an over-quota create shows up as a FailedCreate event on the ReplicaSet.

3. Prove the address is assigned

kubectl get svc web -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

That prints the reserved address you asked for. Ingress rules for the port you exposed are reconciled by the platform within a few minutes; there is no cluster-admin step.

4. Prove it serves traffic

From a machine with IPv6:

curl -6 http://[2a01:4f8:fff0:18b:1000::1]:80/

Substitute your own address. Brackets are required.

5. Put a hostname on it

One AAAA record, pointing at that address. No CNAME, no flattening.

dig AAAA app.example.com
curl -6 http://app.example.com/

Full walkthrough: Point a hostname at your dollarbox.

6. TLS

DollarBox does not terminate TLS. Terminate it in your own container or in a reverse proxy you run in your namespace, on port 443 behind a second LoadBalancer port. For certificates, use DNS-01 with Let's Encrypt — HTTP-01 validation is unreliable over IPv6-only paths.

Reaching your service from IPv4 clients

Two directions, and they are not symmetric.

Outbound — your pod calling IPv4-only services. Covered by the cluster NAT64 gateway, with no configuration on your side. Docker Hub, npm, GitHub and ordinary public APIs work from your pods as they would anywhere else. You do not configure NAT64 inside the container.

Inbound — IPv4 clients reaching your service. Not covered. The NAT64 gateway is outbound-only: it translates connections your pod opens, and nothing else. An IPv4-only client cannot open a connection to your IPv6 address, and DollarBox has no shared IPv4 address or IPv4 proxy offering — not on the €1 plan, not as an add-on. If your audience includes IPv4-only networks and you cannot put a proxy in front yourself, DollarBox is the wrong host and we would rather you knew now.

To serve IPv4 clients you bring your own edge: a proxy that speaks IPv4 to the client and IPv6 to your pod. Cloudflare's proxy does this for HTTP and HTTPS on your own Cloudflare account — a proxied AAAA record, Full (strict) TLS mode, and a certificate on your origin. It does not forward arbitrary TCP or UDP; non-web protocols need Cloudflare Spectrum or direct IPv6.

Limits and suspension

Two different things get a namespace stopped.

Not paying. A failed invoice moves the org to past due immediately and schedules suspension one day later. On suspension, control-panel containers are scaled to zero and every kubectl credential for the org is revoked — your kubeconfig stops working, and workloads you created with it keep running but you cannot manage them. Paying the invoice resumes containers and you download a new kubeconfig. Nothing is deleted at this stage.

Breaking the Terms. The acceptable-use list is short and we mean it literally:

Violations end the account immediately and without a refund. Abuse reports go to [email protected].

Beyond that: there is no uptime SLA, at any price. Outages are posted to status.dollarbox.dev. If our infrastructure breaks we fix it. If your container breaks, that is yours.

Backups

The €1 base price includes no backups. That is deliberate, not an oversight. Nothing in your namespace is backed up unless you pay for the add-on and switch it on per volume.

Two things worth being precise about first:

The paid add-on

€0.15 per backed-up GB per month excluding VAT, prorated, charged on the source volume's size — a 10 GB volume is €1.50/month regardless of how many backup copies are retained. This is on top of the €0.10/GB/month you already pay for the volume itself. The control panel shows the exact cost before you enable it.

What is backed up: the contents of the individual longhorn PersistentVolumeClaims you enable it on. Nothing else, and nothing by default.

What is not backed up, ever:

A restore gives you back a volume's bytes. It does not give you back your application.

Frequency: one backup a night, starting at 02:00 UTC plus a per-volume offset of up to two hours to spread load. Plus one manual "back up now" on demand — one live manual backup at a time; delete the old one to take another.

Retention: configurable from 1 to 30 days, meaning that many successful nightly backups are kept. Older ones are pruned automatically.

Where they are stored: on Hetzner Storage Boxes in the same region — separate hardware from the dedicated servers whose disks hold your live Longhorn volume, so losing the cluster does not lose the backups. Transfers are incremental after the first full copy.

Backup data is not encrypted at rest, and neither are your volumes. DollarBox does not encrypt either one. Access to the backup store is restricted to the platform's backup infrastructure, and that is the whole of the protection. If your data needs encryption at rest, encrypt it in your application before it is written to the volume.

How to enable it: per volume, at Volumes → Backups in the control panel, or through the API:

PUT /api/v1/volumes/<volume-id>/backup-policy/
PUT /api/v1/namespaces/<namespace-id>/volumes/<pvc-name>/backup-policy/

You cannot enable backups from kubectl. Tenant credentials have no VolumeSnapshot permissions; the platform takes the snapshots on your behalf.

How to restore: self-service, from the same screen or POST to /api/v1/volumes/<volume-id>/backups/<backup-id>/restore/. You do not open a ticket and you do not wait for us.

A restore always creates a new volume. In-place restore does not exist, by design — your original volume and its data are never touched. The new volume comes out of your pre-paid pool at the backup's original size, so the pool needs that much free space, and restores cannot resize. Once it is bound, attach it like any other volume.

A restore starts the moment you ask for it — it is not waiting on a nightly job or a periodic sweep. How long it then takes scales with how much data the backup holds, because the volume is rebuilt by pulling it back from backup storage. Watch the restore move pending → provisioning → bound rather than assuming a duration. There is no guaranteed turnaround, and the Terms do not offer one.

Billing lifecycle: past-due and suspended accounts keep their existing backups and keep being charged for them, but take no new ones and prune nothing until the account is active again. Closing an account deletes all of its backups. Disabling backups on a volume deletes every retained backup for it, and the charge stops once deletion finishes.

What you should still do yourself

Even with the add-on on:

Full detail: Volume backups. For same-cluster recovery points at €0.10/GB/month, see snapshot protection — those are not off-site and do not survive loss of the cluster.

Refer a developer

Once you are running, there is a referral link on Dashboard → Team & referrals → Referrals. Every developer who signs up through it, stays 30 days and pays €2 of usage earns you €1 of credit — a container-month — on your next invoice. They pay normal prices. Details and the rules are in Referrals.

Getting help

Support is the docs and a community channel. At €1/month there is no support team, and best-effort means what it says.

Restores need no support channel — they are self-service in the control panel and over the API, at any hour. If a restore itself fails, the restore record carries the error; take that to the Discord like any other technical problem. Do not send it to the billing address, which is slower and not monitored for technical issues.