# Install on AWS ECS

A CloudFormation template deploys Sentinel on ECS Fargate with an Application Load Balancer already wired up — a good fit if your infrastructure is already on AWS.

## Prerequisites

- An active AWS account.
- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured.
- A local copy of the template from [altcha-org/altcha-sentinel-deploy-aws](https://github.com/altcha-org/altcha-sentinel-deploy-aws).

## What the stack creates

- An ECS service (Fargate launch type).
- An internet-facing Application Load Balancer (ALB).
- Optional persistent EFS storage volume for Sentinel's `/data`, if `EnablePersistence` is set.
- Optional custom domain configuration.

## Step 1 — Deploy the stack

A minimal deployment:

```bash
aws cloudformation deploy \
--template-file altcha-sentinel-aws-ecs.yml \
--stack-name altcha-sentinel-stack \
--capabilities CAPABILITY_IAM
```

With a custom domain, ACM certificate, and larger task size:

```bash
aws cloudformation deploy \
--template-file altcha-sentinel-aws-ecs.yml \
--stack-name altcha-sentinel-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
  DomainName=sentinel.example.com \
  CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/xxxx-xxxx-xxxx \
  TaskCPU=4096 \
  TaskMemory=8192
```

## Configuring a database

By default the stack runs Sentinel with its own embedded storage — nothing else to configure, but enable `EnablePersistence` so that storage survives task recreation. For an external database instead, set `DatabaseUrl` and `DatabaseUrlVarName`:

```bash
aws cloudformation deploy \
--template-file altcha-sentinel-aws-ecs.yml \
--stack-name altcha-sentinel-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
  DatabaseUrl="postgresql://user:password@your-db-host:5432/altcha_sentinel" \
  DatabaseUrlVarName=POSTGRES_URL
```

`DatabaseUrlVarName` selects which environment variable the connection string is passed as, matching the engine — `POSTGRES_URL` (default), `MYSQL_URL`, `MARIADB_URL`, `MSSQL_URL`, or `LIBSQL_URL`. See [Databases](/docs/sentinel/databases/) for engine details.

<Callout>

Parameters holding secrets (`DatabaseUrl`, `SecretSeed`, `LicenseKey`, `RedisUrl`, `ExtraEnvValue1/2/3`) are declared `NoEcho`, so CloudFormation masks them in the console — but they're still passed to `deploy` as plain CLI arguments. Keep that in mind before running this from a shared shell history or a CI log.

## Other configuration

- **`SecretSeed`** — derives Sentinel's internal secrets (`JWT_SECRET`, `ALTCHA_HMAC_SECRET`, `CODE_CHALLENGE_SECRET`, `EXOTDB_HMAC_SECRET`, `HASHING_SALT`) deterministically from one fixed value. Without it, these are auto-generated randomly on startup, which invalidates sessions on every task restart — set it for anything beyond a quick test.
- **`LicenseKey`** — your Sentinel license key. See [License](/docs/sentinel/security/license/).
- **`RedisUrl`** — connection string for an external Redis/Valkey instance. See [Databases](/docs/sentinel/databases/#enabling-an-external-redisvalkey).
- **`NodeId`** — a unique node identifier.
- **`BaseUrl`** — base URL Sentinel uses for absolute links.
- **`AllowedHosts`** — comma-separated, wildcard-supported list of hostnames Sentinel will accept requests for.
- **`ExtraEnvName1/2/3`** / **`ExtraEnvValue1/2/3`** — three generic slots for any other environment variable the named parameters don't cover:

```bash
--parameter-overrides ExtraEnvName1=SOME_VAR ExtraEnvValue1=some-value
```

Any parameter left at its default (empty string) is simply not passed to the container — Sentinel falls back to its own defaults or auto-generated values.

## All parameters

| Parameter | Default | Description |
|---|---|---|
| `ImageURI` | `public.ecr.aws/n6m6b4n8/altcha-org/sentinel:<version>` | Container image — see [container registries](/docs/sentinel/install/#container-registries). |
| `ServiceName` | `altcha-sentinel` | ECS service name. |
| `DomainName` | *(empty)* | Custom domain. |
| `CertificateArn` | *(empty)* | ACM certificate ARN for HTTPS on the ALB. |
| `TaskCPU` | `2048` | CPU units (1024 = 1 vCPU). |
| `TaskMemory` | `4096` | Memory in MiB. |
| `EnablePersistence` | `false` | Mount an EFS volume at `/data`. |
| `DatabaseUrl` | *(empty)* | External database connection string. |
| `DatabaseUrlVarName` | `POSTGRES_URL` | Env var name the connection string is passed as. |
| `SecretSeed` | *(empty)* | Seed for deterministic secret derivation. |
| `LicenseKey` | *(empty)* | Sentinel license key. |
| `RedisUrl` | *(empty)* | External Redis/Valkey connection string. |
| `NodeId` | *(empty)* | Unique node identifier. |
| `BaseUrl` | *(empty)* | Base URL for absolute links. |
| `AllowedHosts` | *(empty)* | Comma-separated, wildcard-supported hostnames. |
| `ExtraEnvName1/2/3`, `ExtraEnvValue1/2/3` | *(empty)* | Additional environment variables. |

## Step 2 — Access the application

Once the stack is up, Sentinel is reachable through the ALB:

- Web interface: `https://[your-alb-dns].elb.amazonaws.com/`
- API: `https://[your-alb-dns].elb.amazonaws.com/v1`
- API documentation: `https://[your-alb-dns].elb.amazonaws.com/v1/docs`

Or at your custom domain, if you set `DomainName` and `CertificateArn`.

Sign in with the default credentials `root` / `root` and change the password immediately.

## Production configuration

<Callout>

Multi-replica (multi-instance) deployments require a **Professional** or **Enterprise** license. Trial licenses support up to 3 instances for testing; other tiers must run a single replica. See [License](/docs/sentinel/security/license/) and [Pricing](/pricing/).

Production deployments should run multiple replicas for high availability, which needs four parameters set identically across every task:

```bash
aws cloudformation deploy \
--template-file altcha-sentinel-aws-ecs.yml \
--stack-name altcha-sentinel-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
  SecretSeed="<a long random string, identical on every node>" \
  LicenseKey="<license key>" \
  DatabaseUrl="postgresql://user:password@your-db-host:5432/altcha_sentinel" \
  DatabaseUrlVarName=POSTGRES_URL \
  RedisUrl="redis://default@your-redis-host:6379"
```

See [Clustering](/docs/sentinel/operations/clustering/#minimum-production-configuration) for what each variable does, and [ENV Variables](/docs/sentinel/operations/env-variables/) for the full reference.

## Upgrading Sentinel

Redeploy the stack with a pinned `ImageURI`:

```bash
aws cloudformation deploy \
--template-file altcha-sentinel-aws-ecs.yml \
--stack-name altcha-sentinel-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
  ImageURI=public.ecr.aws/n6m6b4n8/altcha-org/sentinel:1.2.3
```

Updates roll out with zero downtime. Prefer pinning an explicit version tag over `latest` so upgrades are deliberate — see [Releases](/docs/sentinel/releases/) for available versions.

## Next steps

- **[Configure](/docs/sentinel/configure/)** — set up your first Security Group and API Key.
- **[Monitoring & Logging](/docs/sentinel/operations/monitoring-logging/)** — track Sentinel's health once it's live.
