How homa works
Drawn, not explained. Nine pictures and you know what you are buying.
1 · One building, many tenants
A Roman insula — the original apartment block. You rent one flat, not the building.
You get walls, a door and a meter — not the building's boiler room.
2 · Sixty seconds to your keys
Four steps. The only one that needs you is the card.
export KUBECONFIG=~/Downloads/homa-kubeconfig.yaml
kubectl get all
kubectl apply -f https://homa.li/en/hello.yaml
A real API. Your CRDs, your operators, your manifests — no proprietary console.
3 · Inside your flat
Zooming into that yellow window.
Isolation is policy-level: RBAC, quotas, Pod Security, egress firewalled from other tenants. Not a private kernel — see picture 5.
4 · The meter only runs when you do
Two flats, same size. One is asleep, one is working.
Sampled every minute: €0.010/vCPU·h · €0.004/GiB·h · €0.0002/GiB storage·h · €0.002/h for the flat itself. Charged Mondays; under €0.50 rolls over.
5 · Where the line is
The honest half of the page. Read it before the card, not after.
✗ no privileged pods has a shape. Every namespace enforces
PodSecurity restricted: a container must declare
runAsNonRoot, seccompProfile: RuntimeDefault,
allowPrivilegeEscalation: false and
capabilities.drop: [ALL], and run as a non-root user — so a
stock nginx image will not do. Miss one and Kubernetes still
creates your Deployment, then refuses every Pod it tries to make.
hello.yaml carries all four.
Need hardware isolation, or a contractual SLA? homa is not the right answer yet. Better you know now.
6 · The door opens outward too
Weekly billing, no commitment. Leaving takes one command.
No proprietary format to escape: it is Kubernetes. Delete the flat, the meter stops.
7 · Your own front door
A real domain, a real certificate. One tool call, one DNS record, two lines of YAML.
1. Put the name on your list. Do this first — each tenant serves an exact list of
hostnames, shown on your tenant page. Any other name — including your
own domain — is rejected until it is on the list. Adding yours is
self-service, from your agent: call the MCP tool
connect_domain. It returns a DNS TXT record
(_homa-verify.<your domain>) — set it, wait a minute,
call again. The name is proven yours and allowed. Rather write a human?
contact@homa.li
still does it.
2. Point your domain at us. An A record to the
cluster entry point, shown on your tenant page in the console — so it
stays right even if the address changes. Works for a subdomain
(app.you.com) and for the apex (you.com) alike —
it is an A record, not a CNAME. Do this first:
Let's Encrypt checks the name resolves before it issues anything.
3. Nothing to create. An Issuer named
letsencrypt is already in your namespace. It is yours: your
ACME account, your rate limits, nobody else's. If you ever delete it,
recreate it like this:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef: { name: le-acme-account }
solvers:
- http01: { ingress: { class: traefik, serviceType: ClusterIP } }
4. Add two things to your Ingress. One annotation, one
tls block. That is the whole configuration.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: site
annotations:
cert-manager.io/issuer: letsencrypt # ← this line
spec:
ingressClassName: traefik
tls: # ← and this block
- hosts: [app.you.com]
secretName: site-tls
rules:
- host: app.you.com
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: site, port: { number: 80 } }
Not cluster-issuer. The platform refuses a
ClusterIssuer reference inside a tenant namespace, and it is
not arbitrary: its ACME account has already proven our own domains, so
Let's Encrypt would issue for them without a challenge. A tenant once got
a real certificate for console.homa.li that way. Your own
Issuer has none of that history — and none of that risk.
Exact names only — no wildcards. There is no
*.example.com, and no free subdomain under a name you
already have: www.you.com and you.com are two
declarations, two calls. The apex is fine — it is an A
record. Each name your tenant may serve is on that list and nowhere
else, which is also what stops a neighbour from claiming yours.
No Certificate object to write. The annotation is enough.
Let's Encrypt issues, we write the secret you named — about
thirty seconds. Renewal is automatic. Nothing on your side expires.
Plain HTTP always redirects to HTTPS. Every site, including yours. Nothing to configure, nothing to forget.
Ingress is the only way in. NodePort and
LoadBalancer are refused by your quota — they would open ports
on the machines themselves. And *.sslip.io names share one
certificate rate limit with the whole world: for anything you keep, use
a domain you own.
8 · Your agent has the keys too
An MCP server, not a chatbot. Your agent runs kubectl on our machines, as your tenant.
Add https://console.homa.li/mcp as a connector, sign in,
and read the list before you click. It names everything the app will be
able to do — including creating and deleting Kubernetes objects in
your namespaces. Revoke it any time from My account.
It can see why something is broken, not just that it is.
kubectl_logs returns what a container wrote — and with
previous set, what the crashed instance wrote,
which is the only thing that ever explains a
CrashLoopBackOff. kubectl_describe returns the
events attached to one object (image that will not pull, pod that will
not schedule, quota reached). kubectl_rollout restarts a
Deployment — the way to pick up a changed Secret without a new
image — or waits for one, with a time limit so it reports instead
of hanging.
And how much room is left. kubectl_get on
resourcequota returns what you have used and your
ceiling, on every dimension, in one call — read it
before you size a workload, not after it is refused.
get_usage answers a different question: it returns
money over a window, not headroom.
All of it runs under your tenant's identity, in your namespace only. Before every command the server asks the Kubernetes API which account it would run as; if the answer is not yours, nothing runs. We do not read your containers — you do, through us.
Already connected? New tools do not arrive on their own. Turn the connector off and on again (Settings → Connectors), then start a new conversation. Your token stays valid — do not delete it. The list your client shows after reconnecting is the reference; the per-client setup snippets are on your My account page.
9 · From a repository to a running app
No pipeline to build, no runner to host. Your agent asks; we clone and apply.
Point us at a repository. The MCP tool
deploy_from_git clones it at a branch or a tag and applies
the Kubernetes manifests it finds at the path you give — one file,
or the .yaml files sitting directly in one directory.
Re-deploying the same repository and path replaces cleanly instead of
leaving orphaned fields behind on every commit.
Nothing from the repository is built or executed. Only object definitions are read. This is not a CI runner: you publish your image to a registry, we run what your manifests declare.
Private GitHub repositories work, and never take a token. Install
the homa-deploy GitHub App on the repository — it asks for
read access to contents, nothing else — then commit a
.homa-deployers file at the repository root, on the default
branch, holding the e-mail of your homa account, one per line. Installing
the App alone is not enough: the file in the repository is what
authorises, so nobody can deploy a repository by installing an App on it.
GitLab: public repositories for now.
Private images. A private repository is not a private image —
they are two different credentials. Upload a registry pull secret with
put_file (it takes a short-lived signed URL, so the token
never travels through your conversation), then reference it from your
Deployment. The GitHub App does not help here; it reads manifests, not
registries.
Files too: put_file puts one file into a ConfigMap or a
Secret without pasting it through a chat window — or hands us a URL
and we fetch it ourselves, which is the way out when your side has no
route to the internet.
Run by humans, in Europe
homa is operated by Ephais SAS, a French company, on servers in Falkenstein, Germany. No third-party trackers, no external fonts, first-party analytics only. Company details · Terms of sale · Ask a question — a human answers.