Skip to main content
Working with an agent? Give them a link to this page as markdown.

AWS infrastructure

The self-host bundle includes Terraform modules for the EC2 host and an optional ACM certificate. The host module also creates its IAM role, security groups, CloudWatch Logs integration, and an optional RDS Postgres instance. You provide the VPC and subnets.

The infrastructure prerequisites prompt covers the network and certificate decisions before provisioning.

Prepare registry access

The default image registry uses cross-account IAM. Complete registry access for the host role before applying the module. If you use an internal registry, grant access through your own IAM policy and set configure_apollo_ecr = false; that page also covers the registry login you provide instead.

Use the module

Copy modules/ from the release bundle into your Terraform repository, then add a module call:

module "watcher" {
source = "./modules/watcher-self-host"

vpc_id = "vpc-xxxxxxxx"
instance_subnet_id = "subnet-xxxxxxxx"
ami_id = "ami-xxxxxxxx"

# configure_apollo_ecr = false # Internal registry only.

analyzer_ingress_security_group_ids = ["sg-xxxxxxxx"]

# Optional: managed RDS instead of bundled Postgres.
# create_rds = true
# rds_subnet_ids = ["subnet-aaaa", "subnet-bbbb"]

tags = {
environment = "production"
}
}

output "watcher_instance_id" {
value = module.watcher.instance_id
}

output "watcher_rds_endpoint" {
value = module.watcher.rds_endpoint
}

output "watcher_rds_database_name" {
value = module.watcher.rds_database_name
}

output "watcher_rds_master_username" {
value = module.watcher.rds_master_username
}

output "watcher_rds_master_password" {
value = module.watcher.rds_master_password
sensitive = true
}

Terraform does not surface a module's outputs at the root, so declare a root output for every value you need later. The four RDS outputs are null when create_rds is false.

Use bundled Postgres for the smallest infrastructure surface. Use RDS when you want managed backups and restore testing. The setup prompt explains the operational ownership of both choices.

The host must reach the image registry, LLM endpoints, and SSM unless you provide private endpoints. The module expects an Ubuntu 24.04 LTS AMI for the deployment region. See modules/watcher-self-host/variables.tf in the bundle for the full input and output reference.

Connect after provisioning

Connect through SSM, then continue with Setup:

aws ssm start-session --target $(terraform output -raw watcher_instance_id)

With create_rds = true, read the connection values first. Setup asks for a DATABASE_URL of the form postgresql+asyncpg://<username>:<password>@<endpoint>/<database name>, and the endpoint output already carries host:port:

terraform output -raw watcher_rds_endpoint
terraform output -raw watcher_rds_master_username
terraform output -raw watcher_rds_database_name
terraform output -raw watcher_rds_master_password

Store the password in your secret manager before closing the session.

Replace the instance

Changing ami_id, or changing module input that affects instance user data, replaces the EC2 instance and destroys its root volume. This removes:

  • files under /opt/watcher-self-host, including deployment configuration;
  • the admin audit log volume;
  • the bundled Postgres volume when create_rds is false.

RDS and resources outside the instance survive. Back up every applicable item under Backups before applying a replacement. Restore the saved configuration and data on the new host.