Environment Variables
Using .env file to load required environment variables
Kamal uses dotenv to automatically load environment variables set in the .env
file present in the application root. This file can be used to set variables like KAMAL_REGISTRY_PASSWORD
or database passwords. But for this reason you must ensure that .env files are not checked into Git or included in your Dockerfile! The format is just key-value like:
KAMAL_REGISTRY_PASSWORD=pw
DB_PASSWORD=secret123
Using a generated .env file
1Password as a secret store
If you’re using a centralized secret store, like 1Password, you can create .env.erb
as a template which looks up the secrets. Example of a .env.erb file:
<% if (session_token = `op signin --account my-one-password-account --raw`.strip) != "" %># Generated by kamal envify
GITHUB_TOKEN=<%= `gh config get -h github.com oauth_token`.strip %>
KAMAL_REGISTRY_PASSWORD=<%= `op read "op://Vault/Docker Hub/password" -n --session #{session_token}` %>
RAILS_MASTER_KEY=<%= `op read "op://Vault/My App/RAILS_MASTER_SECRET" -n --session #{session_token}` %>
MYSQL_ROOT_PASSWORD=<%= `op read "op://Vault/My App/MYSQL_ROOT_PASSWORD" -n --session #{session_token}` %>
<% else raise ArgumentError, "Session token missing" end %>
This template can safely be checked into git. Then everyone deploying the app can run kamal envify
when they setup the app for the first time or passwords change to get the correct .env
file.
If you need separate env variables for different destinations, you can set them with .env.destination.erb
for the template, which will generate .env.staging
when run with kamal envify -d staging
.
Note: If you utilize biometrics with 1Password you can remove the session_token
related parts in the example and just call op read op://Vault/Docker Hub/password -n
.
Bitwarden as a secret store
If you are using open source secret store like bitwarden, you can create .env.erb
as a template which looks up the secrets.
You can store SOME_SECRET
in a secure note in bitwarden vault:
$ bw list items --search SOME_SECRET | jq
? Master password: [hidden]
[
{
"object": "item",
"id": "123123123-1232-4224-222f-234234234234",
"organizationId": null,
"folderId": null,
"type": 2,
"reprompt": 0,
"name": "SOME_SECRET",
"notes": "yyy",
"favorite": false,
"secureNote": {
"type": 0
},
"collectionIds": [],
"revisionDate": "2023-02-28T23:54:47.868Z",
"creationDate": "2022-11-07T03:16:05.828Z",
"deletedDate": null
}
]
… and extract the id
of SOME_SECRET
from the json
above and use in the erb
below.
Example .env.erb
file:
<% if (session_token=`bw unlock --raw`.strip) != "" %># Generated by kamal envify
SOME_SECRET=<%= `bw get notes 123123123-1232-4224-222f-234234234234 --session #{session_token}` %>
<% else raise ArgumentError, "session_token token missing" end %>
Then everyone deploying the app can run kamal envify
and kamal will generate .env
Using env variables
You can inject env variables into the app containers using env
:
env:
DATABASE_URL: mysql2://db1/hey_production/
REDIS_URL: redis://redis1:6379/1
Note: Before you can start the containers you need to push the env variables up to the servers.
Using secret env variables
If you have env variables that are secret, you can divide the env
block into clear
and secret
:
env:
clear:
DATABASE_URL: mysql2://db1/hey_production/
REDIS_URL: redis://redis1:6379/1
secret:
- DATABASE_PASSWORD
- REDIS_PASSWORD
The list of secret env variables will be expanded at run time from your local machine. So a reference to a secret DATABASE_PASSWORD
will look for ENV["DATABASE_PASSWORD"]
on the machine running Kamal. Just like with build secrets.
If the referenced secret ENVs are missing, the configuration will be halted with a KeyError
exception.
Note: Marking an ENV as secret currently only redacts its value in the output for Kamal. The ENV is still injected in the clear into the container at runtime.
Injecting env variables from the host
You can inject variables from the deploy host with the ${} syntax:
env:
DATACENTER: "${DATACENTER}"
Using Kamal env variables
The following env variables are set when your container runs:
KAMAL_CONTAINER_NAME
: this contains the current container name and version