v2.31.0-dev19 35467d7

env.md RawHistoryFolder

Environment Variables

Configure per-application environment variables using domain-based files.

Configuration

[env]
dir = "~/.gordon/env"  # Default location

Options

Option Type Default Description
dir string ~/.gordon/env Directory containing .env files

How It Works

Gordon loads environment variables from files named after the domain:

~/.gordon/env/
├── app_mydomain_com.env      # For app.mydomain.com
├── api_mydomain_com.env      # For api.mydomain.com
└── admin_mydomain_com.env    # For admin.mydomain.com

Naming convention: Replace dots with underscores, add .env extension.

Domain File Name
app.mydomain.com app_mydomain_com.env
api.company.io api_company_io.env
staging.app.dev staging_app_dev.env

Backend Behavior

The auth.secrets_backend setting changes where route secrets live:

Pass Backend

  • Env files are not used for route secrets.
  • Use gordon secrets set to store per-domain secrets in pass.
  • Existing .env files are migrated on startup and renamed to .env.migrated.

SOPS or Unsafe Backend

  • Env files remain the source of truth.
  • Use ${sops:...} syntax for encrypted values when secrets_backend = "sops".

File Format

Standard .env file format:

# app_mydomain_com.env
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://db:5432/myapp
API_KEY=sk-1234567890
DEBUG=false

Variable Merging

Variables are merged from multiple sources (lowest to highest priority):

  1. Dockerfile ENV - Base defaults from image
  2. .env file - Overrides Dockerfile values
# Dockerfile
ENV NODE_ENV=development
ENV PORT=3000
# app_mydomain_com.env
NODE_ENV=production  # Overrides Dockerfile
# PORT not set, uses 3000 from Dockerfile

Result: NODE_ENV=production, PORT=3000

Secret Provider Syntax

Reference secrets from configured backends in env files:

Pass (Unix Password Manager)

DATABASE_PASSWORD=${pass:myapp/database/password}
API_SECRET=${pass:company/api-secret}
JWT_KEY=${pass:production/jwt-signing-key}

SOPS (Encrypted Files)

DATABASE_PASSWORD=${sops:secrets.yaml:database.password}
API_SECRET=${sops:production.yaml:api.secret}
STRIPE_KEY=${sops:secrets.yaml:stripe.api_key}

Syntax Reference

Provider Syntax Example
pass ${pass:<path>} ${pass:myapp/db-password}
sops ${sops:<file>:<key.path>} ${sops:secrets.yaml:db.password}

Examples

Basic Application

# app_mydomain_com.env
NODE_ENV=production
PORT=3000
LOG_LEVEL=info

Database Connection

# ~/.gordon/env/api_mydomain_com.env
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE_NAME=myapi
DATABASE_USER=apiuser
DATABASE_PASSWORD=${pass:myapi/db-password}
DATABASE_URL=postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}

Full Production Setup

# ~/.gordon/env/app_company_com.env
# Application settings
NODE_ENV=production
PORT=3000
LOG_LEVEL=warn

# Database
DATABASE_URL=postgresql://postgres:5432/production
DATABASE_PASSWORD=${pass:company/db-password}

# Redis
REDIS_URL=redis://redis:6379

# External APIs
STRIPE_SECRET_KEY=${pass:company/stripe-secret}
SENDGRID_API_KEY=${pass:company/sendgrid-key}

# Auth
JWT_SECRET=${pass:company/jwt-secret}
SESSION_SECRET=${pass:company/session-secret}

# Feature flags
ENABLE_ANALYTICS=true
MAINTENANCE_MODE=false

Development Environment

# ~/.gordon/env/app_local.env
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug
DATABASE_URL=postgresql://postgres:5432/dev
DEBUG=*

File Permissions

Gordon creates env files with secure permissions:

  • Directory: 0700 (owner only)
  • Files: 0600 (owner only)

Create files with proper permissions:

mkdir -p ~/.gordon/env
chmod 700 ~/.gordon/env
touch ~/.gordon/env/app_mydomain_com.env
chmod 600 ~/.gordon/env/app_mydomain_com.env

Auto-Creation

Gordon creates empty env files automatically when deploying a new route. You can then edit the file to add your variables.

Viewing Effective Environment

To see what environment a container receives:

docker inspect gordon-app-mydomain-com | jq '.[0].Config.Env'
source
1# Environment Variables
2
3Configure per-application environment variables using domain-based files.
4
5## Configuration
6
7```toml
8[env]
9dir = "~/.gordon/env"  # Default location
10```
11
12## Options
13
14| Option | Type | Default | Description |
15|--------|------|---------|-------------|
16| `dir` | string | `~/.gordon/env` | Directory containing .env files |
17
18## How It Works
19
20Gordon loads environment variables from files named after the domain:
21
22```
23~/.gordon/env/
24├── app_mydomain_com.env      # For app.mydomain.com
25├── api_mydomain_com.env      # For api.mydomain.com
26└── admin_mydomain_com.env    # For admin.mydomain.com
27```
28
29**Naming convention:** Replace dots with underscores, add `.env` extension.
30
31| Domain | File Name |
32|--------|-----------|
33| `app.mydomain.com` | `app_mydomain_com.env` |
34| `api.company.io` | `api_company_io.env` |
35| `staging.app.dev` | `staging_app_dev.env` |
36
37## Backend Behavior
38
39The `auth.secrets_backend` setting changes where route secrets live:
40
41### Pass Backend
42
43- Env files are not used for route secrets.
44- Use `gordon secrets set` to store per-domain secrets in pass.
45- Existing `.env` files are migrated on startup and renamed to `.env.migrated`.
46
47### SOPS or Unsafe Backend
48
49- Env files remain the source of truth.
50- Use `${sops:...}` syntax for encrypted values when `secrets_backend = "sops"`.
51
52## File Format
53
54Standard `.env` file format:
55
56```bash
57# app_mydomain_com.env
58NODE_ENV=production
59PORT=3000
60DATABASE_URL=postgresql://db:5432/myapp
61API_KEY=sk-1234567890
62DEBUG=false
63```
64
65## Variable Merging
66
67Variables are merged from multiple sources (lowest to highest priority):
68
691. **Dockerfile ENV** - Base defaults from image
702. **.env file** - Overrides Dockerfile values
71
72```dockerfile
73# Dockerfile
74ENV NODE_ENV=development
75ENV PORT=3000
76```
77
78```bash
79# app_mydomain_com.env
80NODE_ENV=production  # Overrides Dockerfile
81# PORT not set, uses 3000 from Dockerfile
82```
83
84Result: `NODE_ENV=production`, `PORT=3000`
85
86## Secret Provider Syntax
87
88Reference secrets from configured backends in env files:
89
90### Pass (Unix Password Manager)
91
92```bash
93DATABASE_PASSWORD=${pass:myapp/database/password}
94API_SECRET=${pass:company/api-secret}
95JWT_KEY=${pass:production/jwt-signing-key}
96```
97
98### SOPS (Encrypted Files)
99
100```bash
101DATABASE_PASSWORD=${sops:secrets.yaml:database.password}
102API_SECRET=${sops:production.yaml:api.secret}
103STRIPE_KEY=${sops:secrets.yaml:stripe.api_key}
104```
105
106### Syntax Reference
107
108| Provider | Syntax | Example |
109|----------|--------|---------|
110| pass | `${pass:<path>}` | `${pass:myapp/db-password}` |
111| sops | `${sops:<file>:<key.path>}` | `${sops:secrets.yaml:db.password}` |
112
113## Examples
114
115### Basic Application
116
117```bash
118# app_mydomain_com.env
119NODE_ENV=production
120PORT=3000
121LOG_LEVEL=info
122```
123
124### Database Connection
125
126```bash
127# ~/.gordon/env/api_mydomain_com.env
128DATABASE_HOST=postgres
129DATABASE_PORT=5432
130DATABASE_NAME=myapi
131DATABASE_USER=apiuser
132DATABASE_PASSWORD=${pass:myapi/db-password}
133DATABASE_URL=postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}
134```
135
136### Full Production Setup
137
138```bash
139# ~/.gordon/env/app_company_com.env
140# Application settings
141NODE_ENV=production
142PORT=3000
143LOG_LEVEL=warn
144
145# Database
146DATABASE_URL=postgresql://postgres:5432/production
147DATABASE_PASSWORD=${pass:company/db-password}
148
149# Redis
150REDIS_URL=redis://redis:6379
151
152# External APIs
153STRIPE_SECRET_KEY=${pass:company/stripe-secret}
154SENDGRID_API_KEY=${pass:company/sendgrid-key}
155
156# Auth
157JWT_SECRET=${pass:company/jwt-secret}
158SESSION_SECRET=${pass:company/session-secret}
159
160# Feature flags
161ENABLE_ANALYTICS=true
162MAINTENANCE_MODE=false
163```
164
165### Development Environment
166
167```bash
168# ~/.gordon/env/app_local.env
169NODE_ENV=development
170PORT=3000
171LOG_LEVEL=debug
172DATABASE_URL=postgresql://postgres:5432/dev
173DEBUG=*
174```
175
176## File Permissions
177
178Gordon creates env files with secure permissions:
179- Directory: `0700` (owner only)
180- Files: `0600` (owner only)
181
182Create files with proper permissions:
183
184```bash
185mkdir -p ~/.gordon/env
186chmod 700 ~/.gordon/env
187touch ~/.gordon/env/app_mydomain_com.env
188chmod 600 ~/.gordon/env/app_mydomain_com.env
189```
190
191## Auto-Creation
192
193Gordon creates empty env files automatically when deploying a new route. You can then edit the file to add your variables.
194
195## Viewing Effective Environment
196
197To see what environment a container receives:
198
199```bash
200docker inspect gordon-app-mydomain-com | jq '.[0].Config.Env'
201```
202
203## Related
204
205- [Secrets Configuration](./secrets.md)
206- [Routes](./routes.md)
207- [Attachments](./attachments.md)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close