thin-controller is a FastAPI web app for viewing and starting or stopping AWS EC2 instances tagged with thin_controller_managed=true.
It can run locally with uvicorn, behind AWS Lambda via Mangum, or as a container in Fargate. The UI is a small server-rendered page backed by a handful of API endpoints.
- FastAPI app: thin_controller/init.py
- Local CLI: thin_controller/main.py
- Lambda handler: thin_controller/handler.py
- Models and config: thin_controller/models.py
- Terraform deployment code: terraform/
- Python 3.12 or newer
uvfor dependency management and running commands- AWS credentials available to the app when listing or changing EC2 instances
Install dependencies:
uv syncRun the development server with reload:
uv run thin-controller --reloadRun without reload:
uv run thin-controllerUseful development commands:
just check
just test
just lint
just types
just coverage
just build_containerThe application reads configuration from environment variables using the THIN_CONTROLLER_ prefix.
THIN_CONTROLLER_REGIONS
- Comma-delimited list of AWS regions to scan and control.
- If unset, the app defaults to all EC2 regions returned by boto3.
Operational rules:
- Only instances tagged with
thin_controller_managed=trueare shown and controlled. - The UI only allows
stopped -> startandrunning -> stop. - Other instance states are visible but not actionable.
The repository can optionally deploy a separate scheduler Lambda that runs from EventBridge every hour and enforces EC2 power state from instance tags. This scheduler is independent of the UI hosting mode, so it can run whether the app itself is deployed on Lambda or Fargate.
Terraform settings:
enable_scheduled_power_control: enable or disable the scheduler module. Defaultfalse.scheduled_power_control_expression: EventBridge schedule expression. Defaultrate(1 hour).
Required tags for scheduler participation:
thin_controller_managed=truethin-controller-timezone: IANA timezone such asAustralia/Brisbanethin-controller-on-hours: dailyHH-HH24-hour window such as09-17or22-06
Optional scheduler override:
thin-controller-always-on=truethin-controller-always-on=1
Schedule rules:
- The scheduler starts
stoppedinstances when the instance's local time is inside the configured window. - The scheduler stops
runninginstances when the local time is outside the configured window. - Start hour is inclusive and end hour is exclusive.
- Overnight windows are supported, for example
22-06. - Instances missing either scheduling tag are ignored.
- Invalid tag values are logged and skipped.
Terraform example:
use_fargate = true
enable_scheduled_power_control = true
scheduled_power_control_expression = "rate(1 hour)"
thin_controller_regions = "ap-southeast-2,us-east-1"Tag examples:
Business hours in Brisbane:
thin_controller_managed=true
thin-controller-timezone=Australia/Brisbane
thin-controller-on-hours=09-17
Overnight window in New York:
thin_controller_managed=true
thin-controller-timezone=America/New_York
thin-controller-on-hours=22-06
Temporary always-on override:
thin_controller_managed=true
thin-controller-timezone=Australia/Brisbane
thin-controller-on-hours=09-17
thin-controller-always-on=true
GET /: main HTML UIGET /api/instances: list managed instances across configured regionsPOST /api/instance: start or stop a managed instanceGET /api/config: return the resolved region configurationGET /up: simple health check
The POST /api/instance route expects form fields for instance_id, region, and new_state.
Infrastructure lives in terraform/. Start with terraform/terraform.tfvars.example.
Terraform supports two deployment modes:
- Lambda, using the Mangum handler in thin_controller/handler.py
- Fargate, using the container built from Dockerfile
The Lambda packaging flow currently installs dependencies with local python3.13 in Terraform while targeting the AWS Lambda python3.12 runtime.