Provision infrastructure for your GoLiveKit app - a Next.js AI driven starter kit.
| Tool | Install |
|---|---|
| Node.js ≥ 22 | brew install node |
| Terraform ≥ 1.7 | brew install terraform |
| A cloud provider account & API token | see provider section below |
# Provision a server — prompts guide you through every step
npx @golivekit/provision
# Provision to a custom output directory with a custom cloud-init template
npx @golivekit/provision --out ./infra --cloud-init ./my-init.yaml
# Preview the Terraform plan without applying
npx @golivekit/provision plan --out ./infra
# Tear down the provisioned infrastructure
npx @golivekit/provision destroy --out ./infraapply is the default subcommand and can be omitted. --out defaults to ./provision-out.
The CLI will:
- Ask which cloud provider to use
- Load live provider options for locations, server types, and images
- Ask for token or credentials, SSH key handling, server name, backup mode, and IPv4 or IPv6
- Stage a provider workspace in your chosen output directory
- Generate
terraform.tfvarsautomatically - Run
terraform init, show the plan, ask for confirmation, then apply
- Create an API token at https://cloud.digitalocean.com/account/api/tokens
- Run
npx @golivekit/provisionand paste the token when prompted - Select an existing local public key or let the CLI generate a new one
Useful region slugs: fra1 (Frankfurt), ams3 (Amsterdam), nyc3 (New York), sfo3 (San Francisco), sgp1 (Singapore)
- Create a project & API token at https://console.hetzner.cloud
- Run
npx @golivekit/provisionand paste the token when prompted - Select an existing local public key or let the CLI generate a new one
Useful locations: nbg1 (Nuremberg), fsn1 (Falkenstein), hel1 (Helsinki), ash (Ashburn VA), sin (Singapore)
- Open IAM → Users → Create user at https://console.aws.amazon.com/iam/home#/users/create
- Set a username (e.g.
provision) and click Next - Choose Attach policies directly, then click Create policy
In the policy editor switch to JSON and paste:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PricingReadOnly",
"Effect": "Allow",
"Action": ["pricing:GetProducts"],
"Resource": "*"
},
{
"Sid": "STSValidate",
"Effect": "Allow",
"Action": ["sts:GetCallerIdentity"],
"Resource": "*"
},
{
"Sid": "EC2Describe",
"Effect": "Allow",
"Action": ["ec2:Describe*"],
"Resource": "*"
},
{
"Sid": "EC2Mutate",
"Effect": "Allow",
"Action": [
"ec2:ImportKeyPair",
"ec2:DeleteKeyPair",
"ec2:CreateSecurityGroup",
"ec2:DeleteSecurityGroup",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupIngress",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:RevokeSecurityGroupEgress",
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:StopInstances",
"ec2:StartInstances",
"ec2:ModifyInstanceAttribute",
"ec2:AllocateAddress",
"ec2:ReleaseAddress",
"ec2:AssociateAddress",
"ec2:DisassociateAddress",
"ec2:AssociateVpcCidrBlock",
"ec2:DisassociateVpcCidrBlock",
"ec2:ModifySubnetAttribute",
"ec2:CreateTags"
],
"Resource": "*"
},
{
"Sid": "BackupsOptional",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:GetRole",
"iam:PassRole",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:ListRolePolicies",
"iam:ListAttachedRolePolicies",
"backup:CreateBackupVault",
"backup:DeleteBackupVault",
"backup:DescribeBackupVault",
"backup:CreateBackupPlan",
"backup:DeleteBackupPlan",
"backup:GetBackupPlan",
"backup:CreateBackupSelection",
"backup:DeleteBackupSelection",
"backup:GetBackupSelection"
],
"Resource": "*"
}
]
}The
BackupsOptionalblock is only needed if you enable daily backup snapshots during setup. You can omit it otherwise.
Name the policy (e.g. ProvisionEC2Policy) and click Create policy.
- Back in the user creation flow, refresh the policy list, select
ProvisionEC2Policy, and complete user creation - Open the user → Security credentials → Create access key
- Choose Other, give it a description, and download the key
npx @golivekit/provisionPaste the Access Key ID and Secret Access Key when prompted. No AWS CLI required.
The bundled cloud-init template (terraform/modules/cloud-init/server-init.yaml.tpl) runs on first boot:
- Docker CE + Docker Compose plugin
- UFW firewall — opens ports 22, 80, 443 only
- fail2ban — brute-force SSH protection
- 2 GB swapfile at
/swapfilewith conservative kernel tuning (vm.swappiness=10) deployuser — passwordless sudo, added to thedockergroup/opt/appdirectory — ready for your docker-compose deployment, including a placeholder.compose.env
By default state is stored locally in <out>/<provider>/terraform.tfstate.
For team use, migrate to a remote backend (Terraform Cloud, S3, etc.):
# <out>/<provider>/main.tf
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "golivekit/prod.tfstate"
region = "eu-central-1"
}
}git clone git@github.com:golivekit/provision.git
cd provision
pnpm install
pnpm build
node ./dist/index.jsTerraform source files live in terraform/. Update those files when you need to change the bundled provider defaults or cloud-init template. At runtime the CLI copies the provider defaults into <out>/<provider>/ and runs Terraform there, so terraform.tfvars, state, and plan files stay project-scoped and portable.
.
├── package.json
├── tsconfig.json
├── terraform/ ← Bundled Terraform defaults published with the package
│ ├── modules/
│ │ └── cloud-init/
│ │ └── server-init.yaml.tpl
│ └── providers/
│ ├── aws/
│ ├── digitalocean/
│ └── hetzner/
├── src/
│ ├── index.ts ← entry point (apply / plan / destroy)
│ ├── providers/
│ │ ├── digitalocean.ts
│ │ ├── hetzner.ts
│ │ └── aws.ts
│ └── ... ← ui, prompts, ssh, terraform, tfvars helpers
└── .gitignore ← secrets & state are git-ignored
Releases are fully automated via Semantic Release. Push to main with Conventional Commits and the CI will determine the version, publish to npm, create a GitHub release, and update CHANGELOG.md automatically.
| Commit prefix | Release type |
|---|---|
fix: ... |
patch (1.0.0 → 1.0.1) |
feat: ... |
minor (1.0.0 → 1.1.0) |
feat!: ... / BREAKING CHANGE: |
major (1.0.0 → 2.0.0) |
git commit -m "feat: add support for new provider"
git push origin main