# Deploying Layover

Terraform config to deploy the Layover relay server to AWS with DNS via Gandi. State is stored in S3 with DynamoDB locking.

## Prerequisites

- [Terraform](https://developer.hashicorp.com/terraform/install) >= 1.5
- [Rust](https://rustup.rs) with musl cross-compilation target
- An SSH key pair (defaults to `~/.ssh/layover-sh.pem`)

### Install cross-compilation tools (macOS)

```bash
rustup target add x86_64-unknown-linux-musl
brew install zig
cargo install cargo-zigbuild
```

### AWS credentials

1. [Create an AWS account](https://aws.amazon.com) if you don't have one
2. Create an IAM user with `AmazonEC2FullAccess`, `AmazonVPCFullAccess`, `AmazonS3FullAccess`, and `AmazonDynamoDBFullAccess`
3. Create an access key (Security credentials → Create access key → CLI)
4. Configure: `aws configure`

### Gandi API key

1. Go to [admin.gandi.net](https://admin.gandi.net)
2. Organization → Users → your user → Security
3. Create a Personal Access Token with DNS management permission

## First-Time Setup

### 1. Bootstrap state backend

The S3 bucket and DynamoDB lock table must exist before the main Terraform config can use them. A separate `bootstrap/` config handles this:

```bash
cd deploy/bootstrap
terraform init
terraform apply
```

This creates:
- S3 bucket `layover-sh-terraform-state` (versioned, encrypted, no public access)
- DynamoDB table `layover-sh-terraform-lock` (for state locking)

Both have `prevent_destroy = true` so they can't be accidentally deleted.

### 2. Deploy the relay

```bash
# Build the binary
cd ../..  # project root
cargo zigbuild --release --target x86_64-unknown-linux-musl

# Configure
cd deploy
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values

# Deploy
terraform init
terraform plan
terraform apply
```

## CI / GitHub Actions

CI runs automatically on every push and PR (`.github/workflows/ci.yml`):

- **Every PR**: cargo build + test, terraform fmt/validate/plan (plan posted as PR comment)
- **Push to main**: cargo build + test, terraform apply, build release binary artifact

Required GitHub secrets:
- `AWS_ACCESS_KEY_ID`
- `AWS_SECRET_ACCESS_KEY`
- `GANDI_API_KEY`
- `CERTBOT_EMAIL`

## Verify

```bash
curl https://layover.sh
ssh -o ProxyCommand="layover connect %h:%p" user@yourserver.com
```

## Update the binary

```bash
cargo zigbuild --release --target x86_64-unknown-linux-musl
scp -i ~/.ssh/layover-sh.pem \
  target/x86_64-unknown-linux-musl/release/layover ubuntu@<EIP>:/tmp/layover
ssh -i ~/.ssh/layover-sh.pem ubuntu@<EIP> \
  'sudo install -m 755 /tmp/layover /usr/local/bin/layover && sudo systemctl restart layover'
```

## Tear down

```bash
cd deploy
terraform destroy

# The state backend (S3/DynamoDB) is NOT destroyed — run separately if needed:
cd bootstrap
terraform destroy
```

## Variables

| Variable | Default | Description |
|---|---|---|
| `aws_region` | `us-east-1` | AWS region |
| `hostname` | `layover.sh` | Domain name for the relay |
| `gandi_api_key` | — | Gandi Personal Access Token |
| `certbot_email` | — | Email for Let's Encrypt |
| `instance_type` | `t3.micro` | EC2 instance type |
| `ssh_allowed_cidrs` | `["0.0.0.0/0"]` | CIDRs allowed to SSH in |
| `ssh_public_key_path` | `~/.ssh/layover-sh.pub` | SSH public key |
| `ssh_private_key_path` | `~/.ssh/layover-sh.pem` | SSH private key |
| `binary_path` | `../target/x86_64-unknown-linux-musl/release/layover` | Path to layover binary |
