Isomux docs Set up Isomux on Kubernetes (EKS)

Set up Isomux on Kubernetes (EKS)#

This is the Kubernetes (EKS) guide. To check if this is the right hosting setup for you, check the decision diagram.

This guide runs an Isomux office in an Amazon EKS cluster from the published container image. You will open it at a web address such as https://office.example.com.

The office is one pod with one persistent disk. It runs one replica only.

Before you start#

You need:

  • An EKS cluster on Kubernetes 1.29 or later, with IPv4 addressing.
  • A node group of Amazon Linux 2023 nodes, x86_64 or arm64 (Graviton), each with at least 2 CPUs and 8 GiB of memory.
    • Add the Kubernetes label isomux.com/office-node=true to these nodes. The office and its seccomp installer run only on labeled nodes.
    • In the launch template (or Karpenter EC2NodeClass), set instance metadata to IMDSv2 required with hop limit 1. Agents run commands in the office pod; this setting keeps them from the node's AWS role.
  • The Amazon EBS CSI driver add-on.
  • The AWS Load Balancer Controller.
  • An ACM certificate that covers both office.example.com and *.office.example.com. Apps that agents build get their own addresses under the office address, such as notes.office.example.com.
  • kubectl with Git available, configured for the cluster.

Fargate cannot run the office: it has no EBS volumes and no custom seccomp profiles.

1. Create the setup key#

The setup key lets you claim the office as its first owner. It must have at least 32 characters.

kubectl create namespace isomux --save-config
kubectl -n isomux create secret generic isomux-setup \
  --from-literal=ISOMUX_SETUP_KEY="$(openssl rand -hex 32)"

You can also create the Secret isomux-setup with key ISOMUX_SETUP_KEY from your own secret manager.

2. Write your deployment settings#

On the Isomux container images page, choose a release tag, which starts with v, and copy its image digest (sha256:…). One digest covers x86_64 and arm64 nodes; releases before arm64 support are for x86_64 only. You can also read the digest with docker buildx imagetools inspect ghcr.io/nmamano/isomux:REPLACE_WITH_RELEASE_TAG.

Create a directory for your office and save this file in it as kustomization.yaml. Replace the release tag, the digest, the certificate ARN, and office.example.com in all four places.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - https://github.com/nmamano/isomux//deploy/kubernetes?ref=REPLACE_WITH_RELEASE_TAG
images:
  - name: ghcr.io/nmamano/isomux
    digest: sha256:REPLACE_WITH_IMAGE_DIGEST
configMapGenerator:
  - name: isomux-config
    namespace: isomux
    behavior: replace
    literals:
      - ISOMUX_PUBLIC_URL=https://office.example.com
patches:
  - target:
      kind: Ingress
      name: isomux
    patch: |-
      - op: replace
        path: /spec/rules/0/host
        value: office.example.com
      - op: replace
        path: /spec/rules/1/host
        value: "*.office.example.com"
      - op: replace
        path: /metadata/annotations/alb.ingress.kubernetes.io~1certificate-arn
        value: arn:aws:acm:REGION:ACCOUNT:certificate/REPLACE_WITH_CERTIFICATE_ID

Use the same release tag for the manifests and the image. The reference manifests create:

  • A 30 GiB encrypted gp3 volume that is kept when you delete the claim.
  • One office pod that runs as a non-root user with no added privileges, under the restricted Pod Security Standard.
  • An internet-facing Application Load Balancer. For an office reachable only from your network, patch alb.ingress.kubernetes.io/scheme to internal.
  • A network policy that blocks the instance metadata address. It works only when the VPC CNI enforces network policies; the node setting above is the required protection. To also keep agents out of your VPC, add its private ranges to that policy.
  • A DaemonSet that writes the office's seccomp profile to each labeled node. The browser and Codex agents need this profile for their sandboxes. If your cluster does not allow hostPath volumes, write the file for the node's architecture (deploy/kubernetes/seccomp/amd64/ or arm64/) from node user data instead, to /var/lib/kubelet/seccomp/isomux/isomux-chromium-v1.json, and remove the DaemonSet with a patch. Copy the file again on each update; it now also covers the Codex agents' sandbox.

3. Start the office#

From the directory with your kustomization.yaml:

kubectl apply -k .
kubectl -n isomux rollout status deployment/isomux --timeout=10m

If the pod shows CreateContainerError, the seccomp profile is not yet on its node. It starts when the installer has written the file:

kubectl -n isomux-node-setup get pods -o wide

4. Point your domain at the office#

Find the load balancer's address:

kubectl -n isomux get ingress isomux

In your DNS, point both office.example.com and *.office.example.com to that address. In Route 53, use alias records to the load balancer.

5. Claim the office#

Display the setup key:

kubectl -n isomux get secret isomux-setup \
  -o jsonpath='{.data.ISOMUX_SETUP_KEY}' | base64 -d; echo

Open your office address in a browser. Paste the key into Setup key, enter your name, and select Continue.

The key cannot claim the office again after an owner exists. To remove it:

kubectl -n isomux delete secret isomux-setup
kubectl -n isomux rollout restart deployment/isomux

If you lose your owner session later, mint a sign-in link through the recovery container: see Locked out as owner.

Connect a provider and send a message#

In the office, open Integrations → Model providers.

  • For Claude or Codex, select the provider's sign-in control and follow the steps. Both ship bundled with Isomux.
  • For OpenCode, open or create an OpenCode agent and choose a model. Its model picker offers Free, Pay-as-you-go, and Subscription options. Free models need no paid account.
  • For a provider API key, add its environment variable on the Variables tab: ANTHROPIC_API_KEY, OPENAI_API_KEY, or OPENCODE_API_KEY, as applicable.

Open an agent that uses the connected provider and send a short message. A reply confirms that the office can use your provider account. Provider charges and subscription limits are separate from hosting.

For Claude through Amazon Bedrock or another connection method, use the provider reference.

Claude on Amazon Bedrock with an IAM role#

On EKS, the office can use an IAM role instead of static keys. Isomux has not verified this setup end to end.

Every process in the office pod can use the role, including the agents of every member. Allow the role only bedrock:InvokeModel* on the models that the office uses:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "bedrock:InvokeModel*",
      "Resource": "arn:aws:bedrock:REGION:ACCOUNT:inference-profile/PROFILE_ID"
    },
    {
      "Effect": "Allow",
      "Action": "bedrock:InvokeModel*",
      "Resource": "arn:aws:bedrock:*::foundation-model/MODEL_ID",
      "Condition": {
        "StringLike": {
          "bedrock:InferenceProfileArn": "arn:aws:bedrock:REGION:ACCOUNT:inference-profile/PROFILE_ID"
        }
      }
    }
  ]
}

PROFILE_ID is an inference profile, such as us.anthropic.claude-sonnet-4-6; MODEL_ID is the same ID without its prefix. Add both ARNs for each model that agents use: the pinned models, or the Bedrock defaults when nothing is pinned.

Attach the role to the service account isomux in namespace isomux with one of these:

  • EKS Pod Identity: install the eks-pod-identity-agent add-on. The role trusts the service pods.eks.amazonaws.com for sts:AssumeRole and sts:TagSession. Then:

    aws eks create-pod-identity-association --cluster-name CLUSTER \
      --namespace isomux --service-account isomux \
      --role-arn arn:aws:iam::ACCOUNT:role/ROLE
    
  • IAM roles for service accounts (IRSA): the cluster needs an IAM OIDC provider. The role trusts that provider for sts:AssumeRoleWithWebIdentity, with sub set to system:serviceaccount:isomux:isomux and aud set to sts.amazonaws.com. Add this patch to kustomization.yaml and apply it:

    - target:
        kind: ServiceAccount
        name: isomux
        namespace: isomux
      patch: |-
        - op: add
          path: /metadata/annotations
          value:
            eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/ROLE
    

The pod gets the role when it starts, so restart it:

kubectl -n isomux rollout restart deployment/isomux

In Integrations → Variables, on the Office-wide card, add only these, with no keys, and then /clear Claude agents:

CLAUDE_CODE_USE_BEDROCK=1
AWS_REGION=REGION

Add people and devices#

For another device of your own, open Settings → You → Sign-in links and create a device link. Open it on that device.

To invite another person, first create them: in Settings, select New member at the end of the Members list, fill in the form and select Create member. Then open Settings → Office → Invites, select them and create a sign-in link. Send the link privately. Only invite people you trust: members and their agents can run commands on the server with the office's operating-system permissions.

On iPhone, open the office in Safari and select Share → Add to Home Screen. On Android, open the HTTPS office address in Chrome and use its install option.

Update the office#

The office's Updates pane shows when a new release is out and links here; it has no Update now button on Kubernetes. Releases are on the Isomux container images page and in the release notes.

  1. Finish active agent work. The update restarts the office and its apps.

  2. Take a snapshot of the office's EBS volume. An update can change stored data, so going back to an older image needs this snapshot.

  3. In your kustomization.yaml, change the release tag and the image digest to the new release.

  4. Apply it:

    kubectl apply -k .
    kubectl -n isomux rollout status deployment/isomux --timeout=10m
    

The old pod stops before the new pod starts, so the office is unavailable for about a minute.

Never force-delete the office pod or force-detach its volume while its old node may still run. The volume must have only one writer.

Backups#

Isomux stores seven daily backups of ~/.isomux/ in the server's backup directory on the same disk as the office, so copy them elsewhere if you need protection from server loss. Current backup health and the exact directory are at GET /api/backup/status.

Keep separate snapshots of the complete EBS volume for recovery from disk loss, for example with AWS Backup.

Office logs#

The office writes its output to the container log, so your cluster's log collector receives it. This output can contain parts of agent errors, so the log pipeline must meet the same data rules as the office volume:

kubectl -n isomux logs deployment/isomux

The volume also keeps the latest office output across pod replacements:

kubectl -n isomux exec deployment/isomux -- \
  tail -n 50 /var/data/home/.isomux/container-runtime/office.log

Only /var/data survives a pod replacement. Keep projects and dependency installs under /var/data/home or /var/data/workspaces. See the container reference for runtime details.