Self-hosting

You can self-host your Keel app in your own AWS account by using the keel deploy CLI.

AWS Setup

You'll need an AWS account for which you have permissions to create resources and you'll need to be authenticated with that account using the AWS CLI (opens in a new tab). You can check that you are authenticated by using the get-caller-identity command on the AWS CLI.

$ aws sts get-caller-identity

Basic Usage

To deploy your app you must have a deploy section in your keelconfig.yaml or env specific keelconfig.<env>.yaml file. The minimal configuration required is a projectName and a region. For more configuration options see Configuration.

deploy:
  # lower-case letter and hyphens only
  projectName: my-project
  # any valid AWS region
  region: eu-west-2

Once you have this set you can run keel deploy up --env <env> to deploy your app. The --env flag is required and the value must contain only letters, numbers, and hyphens. Environments are totally isolated and you can deploy as many as you want. This command will:

  • Validate your schema and config
  • Build your functions
  • Create or update any required resources in AWS
  • Update your database schema if there have been any changes

An initial deployment will take around five minutes and subsequent deploys should be around two minutes. Once the deploy is successful you will see the URL for your Keel app.

To destroy an environment and all AWS resources associated with it you can use keel deploy remove --env <env>.

CLI

All commands live under keel deploy and require an --env flag which indicates which environment to use, for example "staging" or "production". You can deploy as many environments as you want into the same AWS account and they are all completely isolated from each other with their own resources. Environment names must contain only lower-case letters, numbers, and hyphens. To provide environment specific config create a corresponding keelconfig.<env>.yaml file. See Configuration for more info.

up

Deploys your app to your AWS account.

$ keel deploy up --env production

remove

Removes all resources associated with the environment with the exception of the S3 bucket used to store uploaded files, which is preserved. If you want to delete this bucket you can manually remove it using the AWS S3 console.

Note that if you're using an external database, this command will not affect it.

$ keel deploy remove --env production

logs

Flags

  • --since How far back to show logs for, for example "1h" for all logs in the last hour. Cannot be used with --start.
  • --start A date/time for when to start showing logs from e.g. "2024-12-01 10:00:00". Cannot be used with --since.

Shows aggregated Cloudwatch logs for your functions and the Keel runtime. Note that AWS platform logs are currently filtered out as these are very noisy.

$ keel deploy logs --env production --since 10m

secrets

Set of commands for managing secrets for deployed environments. Note that this command is separate from keel secrets which is only for managing secrets locally e.g. when using keel run or keel test.

set

Args

  • name The name of the secret. This must correspond to a secret defined in your config file
  • value The value of the secret.

Sets a secret in your AWS account for the given environment. Secrets are stored in SSM as secure parameters.

$ keel deploy secrets set --env production MY_SECRET

get

Args

  • name The name of the secret. This must correspond to a secret defined in your config file

Retrieves and decrypts a secret set in your AWS account and prints it to the console.

$ keel deploy secrets get --env production MY_SECRET

remove

Args

  • name The name of the secret. This must correspond to a secret defined in your config file

Removes a secret that has been previously set.

$ keel deploy secrets remove --env production MY_SECRET

Configuration

All configuration is provided via your config file under a deploy section. This section is required with the minimal configuration being a projectName and a region.

deploy:
  projectName: my-project
  region: us-east-2

Environment-specific configuration

You can create different config files for each environment by creating a keelconfig.<env>.yaml file for each environment. For example if you deploy using --env staging and a keelconfig.staging.yaml file exists it will be used.

Just remember config files are not merged, so you must include the deploy section with the projectName and region in each config file as well as any environment variables, secrets, and other configuration you need.

projectName

  • Type: string

This value, along with the environment name, is used to uniquely identity the set of resources created in your AWS account. It must contain only lower-case letters, numbers, and hyphens.

region

  • Type: string

The AWS region to deploy to, for example eu-west-2.

database.provider

  • Type: rds | external
  • Default: rds

The default database setup uses an AWS RDS Postgres database with the db.t4g.micro instance type (2 vCVU's, 1GB RAM), in a single availability zone, with 20GB allocated storage. This costs around $16 a month but with the VPC and Internet Gateway costs factored in the total is around $25 a month.

deploy:
  database:
    provider: rds

You can also use any publicly available Postgres database by setting deploy.database.provider to external and providing a DATABASE_URL secret. For example.

deploy:
  database:
    provider: external
secrets:
  - name: DATABASE_URL

You can set this secret using keel deploy secrets set --env <env> DATABASE_URL <>.

There are many providers that offer publicly available Postgres, for example Supabase (opens in a new tab), Neon (opens in a new tab), and Render (opens in a new tab) are all good options.

When database.provider is set to external no VPC is required and so it's not created, which results in a lower AWS bill and faster deploys.

database.rds

If using RDS you can configure the instance type, multi-az mode, and storage by adding a database.rds section to your config.

deploy:
  database:
    provider: rds
    rds:
      # You can see all instance types here - https://aws.amazon.com/rds/instance-types/ 
      instance: db.t4g.large
      # This is in GiB and cannot be smaller than 20
      storage: 50
      # Setting this to true basically doubled the cost of the database.
      multiAz: true

The above configuration will give you 2 vCPU's, 8GB memory, 50GB allocated storage, two availability zones, and will cost around $115 a month.

telemetry.collector

You can configure your Keel app to send tracing data using Open Telemetry to any service that supports it by providing an OpenTelemetry collector config file.

deploy:
  telemetry:
    collector: ./collector.yaml

Below is an example OTEL collector config file that defines a single exporter. Note that a number of sections are required and must be included as shown below or your app will either not send tracing data correctly or crash on boot.

collector.yaml
# This section is required
receivers:
  otlp:
    protocols:
      grpc:
      http:
 
# Define your exporters
exporters:
  # This defines a single exporter that sends tracing data to Axiom using HTTP
  otlphttp:
    compression: gzip
    endpoint: https://api.axiom.co
    headers:
      # You can use any of your apps secrets in this file by using {{ .secrets.SECRET_NAME }}
      # This is a Keel-specific feature to make the usage of things like API keys more secure
      authorization: Bearer {{ .secrets.AXIOM_TOKEN }}
 
      # You can also env var substitution - note the syntax here is different
      # See https://opentelemetry.io/docs/collector/configuration/#environment-variables for more info
      x-axiom-dataset: ${env:AXIOM_DATASET}
 
# This section is required
processors:
  batch:
 
# This section is required - just remember to include any exporters 
# in service.pipelines.exports or they won't be used
service:
  pipelines:
    traces:
      receivers:
        - otlp
      processors:
        - batch
      # If you have multiple exporters make sure they are all added here too
      exporters:
        - otlphttp

Using environment variables and secrets

The OpenTelemetry collector supports environment variable substitutation in the config file using the syntax ${env:MY_ENV_VAR}. This is fine for non-sensitive values but isn't ideal for API keys as you don't want to check those into version control.

To provide a secure way to use API keys in your collector config Keel also adds the ability to use secrets via the syntax {{ .secrets.MY_SECRET }}. These values are substituted at deploy time and managed using the keel deploy secrets set command.

OpenTelemetry services

There are a number of services that support tracing data being sent in OpenTelemetry format. A few are Axiom (opens in a new tab), Honeycomb (opens in a new tab), Grafana (opens in a new tab), and Baselime (opens in a new tab).