# Install on AWS

**Spinbox is experimental: APIs change and data may be lost.** What is built and what proves it is on [Status](https://spin-stack.github.io/website/reference/status.md); what Spinbox does not do is on [Limitations](https://spin-stack.github.io/website/overview/limitations.md).

> What an installation on AWS is made of, what the OpenTofu module creates in your account, and the choices it makes for you.

An installation of Spinbox lives in one AWS account and one region. It is created by one OpenTofu
module, [spin-terraform-aws](https://github.com/spin-stack/spin-terraform-aws):

```hcl
module "spin" {
  source       = "github.com/spin-stack/spin-terraform-aws?ref=<tag>"
  spin_version = "v20261019.02"
  domain       = "spin.example.com"
}
```

*Diagram: What the module creates in your account, and who connects to whom.* Its labels: AWS · Users browser, spin CLI, SSH · Let's Encrypt · Region · spin-stack/ami task release · images.json release → region → AMI · operator tofu apply, or GitHub Actions · VPC - no NAT: every machine has its own way out · Internet gateway · edge subnets the proxy's alone · public subnets, one per zone · S3 gateway endpoint · S3 - only through the endpoint volumes (Object Lock), the database's sealed archive, logs, certificates; a document per role, by the apply · Parameter Store - written by the apply the key, the CA, the first password: the control plane's alone · Route 53 <domain>, which its registrar points at, and spin.internal, whose records the machines write · IAM a role per machine, one permissions boundary · Spin OS AMI the release, read-only root · CloudWatch Logs every boot, the VPC's flows · Session Manager the only shell · OpenTofu state S3, encrypted with KMS · Elastic IP app., tunnel.app., *.ws. · proxy, a group of one · control plane a group of one, replaced beside itself · runners 0 to max_runners spot hosts, sized by the control plane · Caddy TLS and the relay · spin control plane · PostgreSQL · VictoriaMetrics Quickwit, Alloy · Grafana · spin runner nftables per workspace · workspace VMs QEMU/KVM · 8080, dialled out · 443, and 80 for the challenge · 8080 · the relay: the runner dials 443 · nothing listens on a runner · volumes: an hour's minted credential · pull request · 443 · 80 · the network, the machines' groups, their documents and secrets. ([source](https://github.com/spin-stack/spin-terraform-aws/blob/1557e9668c71ef9960433fb1f28d357699f4cd05/docs/diagrams/installation))

## What it creates

- **A VPC** of its own, with public subnets and no NAT gateway. The bucket is reached through the
  free S3 gateway endpoint.
- **The control plane**, on one machine ([`instance_type`](https://spin-stack.github.io/website/reference/terraform/controlplane.md#instance_type)), in an autoscaling group of one. It also
  runs the installation's PostgreSQL 18 and its log and metric stores.
- **The proxy**, on one machine ([`proxy_instance_type`](https://spin-stack.github.io/website/reference/terraform/controlplane.md#proxy_instance_type)) with an elastic IP, in an autoscaling group of one.
- **The runners**, an autoscaling group of large spot machines with local NVMe ([`instance_types`](https://spin-stack.github.io/website/reference/terraform/runners.md#instance_types)), which
  the control plane sizes from zero.
- **S3 buckets, each with one owner**: the volumes, with versioning and Object Lock; the
  database's archive, under Object Lock too; logs, traces and metric backups; the proxy's
  certificates; and what each machine starts from.
- **Two Route 53 zones**: your domain's public zone, and a private zone (`spin.internal`) the
  machines find each other by.
- **The installation's secrets**, in SSM Parameter Store: its CA, its encryption key and the
  first administrator's password.
- **IAM roles** for each machine, all under one permissions boundary.
- **A VPC flow log**, kept in CloudWatch for 30 days.

Every machine boots **Spin OS**, the image published for the release, in the regions [Spin OS images](https://spin-stack.github.io/website/reference/terraform/images.md) lists.

## The choices it makes

These are made for you, and each one has a reason:

| Choice | Why |
|---|---|
| Every machine is replaced to update, never patched | Its root filesystem is read-only and verified; a machine runs exactly what the release signed. |
| The proxy is the only machine the internet reaches | The control plane, the runners and the database take no connection from outside the VPC. |
| No SSH on any machine | A shell is AWS Session Manager, decided by IAM and logged by AWS. |
| No NAT gateway | It would cost more than the machines that run all the time. |
| Runners are spot and start from zero | They are the largest cost, and they only cost while a workspace runs. |
| Runners join by their IAM role | There is no join token to create, store, rotate or leak. |
| No role can grant itself more | A permissions boundary on every role denies IAM writes, parameter writes, and lifting the bucket's lock. |
| Telemetry stays in the installation | Logs, traces and metrics are kept on the control plane's machine, over the logs bucket. |

## Before you begin

Read [Before you start](https://spin-stack.github.io/website/aws/prerequisites.md): you need a domain of the installation's own, room
in your account's spot quota, and a region the release has images in.

## Pages in this section

- [Before you start](https://spin-stack.github.io/website/aws/prerequisites.md): tools, domain, quotas and the image.
- [Install](https://spin-stack.github.io/website/aws/setup.md): the commands, in order.
- [Network](https://spin-stack.github.io/website/aws/network.md): what reaches what, and how to close the installation to your own
  networks.
- [Cost](https://spin-stack.github.io/website/aws/cost.md): what runs all the time, and what runs only while workspaces do.
- [Update](https://spin-stack.github.io/website/aws/update.md): moving to a new release.
- [Remove](https://spin-stack.github.io/website/aws/remove.md): deleting an installation on purpose.
- [Troubleshooting](https://spin-stack.github.io/website/aws/troubleshooting.md): where to look when something does not come up.
