evnx backup
Create an encrypted, portable backup of your .env file using AES-256-GCM and Argon2id key derivation.
Prerequisites
evnx backup creates a cryptographically secure, portable backup of your .env file. The backup is encrypted with AES-256-GCM using a key derived from your password via Argon2id, ensuring your secrets remain confidential even if the backup file is exposed.
Before you start
Command signature
evnx backup [OPTIONS]Options:
| Flag | Type | Default | Description |
|---|---|---|---|
--env | string | .env | Path to the .env file to back up |
--output | string | <env>.backup | Destination path for the encrypted backup |
--key-file | path | — | Use a file as the encryption key instead of a password prompt |
--keep | number | 3 | Number of previous backups to retain alongside the new one |
--verify | bool | false | Re-decrypt and integrity-check the backup immediately after writing |
--verbose | bool | false | Print diagnostic information at each pipeline stage |
How encryption works
Security model
Every backup uses industry-standard cryptography:
┌─────────────────────────────────────────┐
│ 1. Password entered or read from file │
│ 2. Fresh 32-byte salt generated │
│ 3. Argon2id derives 32-byte AES key │
│ • Memory: 64 MiB │
│ • Iterations: 3 │
│ • Parallelism: 1 │
│ 4. Fresh 12-byte nonce generated │
│ 5. AES-256-GCM encrypts JSON envelope │
│ 6. Binary envelope Base64-encoded │
│ 7. File written with 0o600 permissions │
└─────────────────────────────────────────┘
Binary format (version 1)
┌─────────┬────────────┬──────────┬────────────────────────────────┐
│ version │ salt │ nonce │ AES-256-GCM ciphertext │
│ 1 byte │ 32 bytes │ 12 bytes │ variable (JSON envelope) │
└─────────┴────────────┴──────────┴────────────────────────────────┘The entire structure is Base64-encoded before being written to disk.
Encrypted payload structure
The ciphertext decrypts to a JSON envelope containing both your .env content and metadata:
{
"schema_version": 1,
"version": 1,
"created_at": "2026-03-10T14:30:00Z",
"original_file": ".env.production",
"tool_version": "0.4.0",
"content": "DATABASE_URL=postgresql://...\nAPI_KEY=sk-...\n"
}Why metadata is encrypted
Embedding metadata inside the encrypted payload means it is both confidential (an attacker cannot learn filenames or timestamps without the password) and tamper-evident (altering metadata invalidates the GCM authentication tag).
Basic usage
Create a backup of .env
evnx backup╔══════════════════════════════════════╗
║ evnx backup ║
║ Encrypt and back up your .env file ║
╚══════════════════════════════════════╝
✓ Read 342 bytes from .env
Enter encryption password: ••••••••
Confirm password: ••••••••
✓ Backup created successfully
Source .env
Backup .env.backup
Size 1 024 bytes (encrypted + Base64)
Verified no
⚠️ Important:
• Keep your password (or key file) safe — it cannot be recovered
• Store the backup in a secure, separate location
• To restore: evnx restore .env.backup --output .env
• Test the restore before deleting the original .env
Backup a specific environment file
evnx backup --env .env.production --output prod.backupVerbose mode for debugging
evnx backup --verbose╔══════════════════════════════════════╗
║ evnx backup ║
║ Encrypt and back up your .env file ║
╚══════════════════════════════════════╝
Source path : .env
Read 342 bytes from .env
✓ Read 342 bytes from .env
Enter encryption password: ••••••••
Password accepted — awaiting confirmation
Confirm password: ••••••••
Passwords match
Backup pipeline starting
Source : .env
Output : .env.backup
Keep : 3
Verify : false
Argon2id key derivation in progress…
Encryption complete — writing backup file
Backup written to .env.backup
✓ Backup created successfully
Source .env
Backup .env.backup
Size 1 024 bytes (encrypted + Base64)
Verified no
Backup rotation
By default evnx keeps the 3 most recent backups alongside the new one. Before each write, existing files are shifted up by one position:
.env.backup → .env.backup.1
.env.backup.1 → .env.backup.2
.env.backup.2 → .env.backup.3 (overwritten if already exists — see warning)
After the rotation the slot is free and the new backup is written to .env.backup.
# Keep the last 5 backups
evnx backup --keep 5
# Disable rotation — overwrite silently
evnx backup --keep 0Files beyond --keep are overwritten, never deleted
If a file already exists at position --keep (e.g. .env.backup.5 when using --keep 5),
evnx will warn you and overwrite it during rotation. Increase --keep or prune the file
manually if you need to retain it.
Post-write integrity verification
The --verify flag re-decrypts the backup immediately after writing and compares
the recovered content byte-for-byte against the original. This proves the backup
is readable before you discard or archive the source file.
evnx backup --verify✓ Backup created and verified successfully
Source .env
Backup .env.backup
Size 1 024 bytes (encrypted + Base64)
Verified yes
If the check fails (corrupt write, filesystem error) evnx exits with code 6 and
leaves the backup file on disk for manual inspection. Your original .env is
never modified.
Performance cost
--verify runs a second full Argon2id round (~1 s on commodity hardware).
For interactive use this is imperceptible. In CI pipelines backing up many files
in sequence, consider whether the safety guarantee is worth the added time.
Non-interactive / CI usage with --key-file
For automated pipelines where typing a password is not possible, supply a key file instead. The file's contents are used as the encryption password source — no prompts are shown.
evnx backup --key-file /run/secrets/backup-keyHow key material is read:
- ›UTF-8 files — content is trimmed of surrounding whitespace. A file
containing
correct-horse-battery-staple\nis treated identically to one without the trailing newline. - ›Binary files — content is Base64-encoded first to produce a stable ASCII string before being fed into Argon2id.
Both paths go through the same Argon2id KDF, so key length beyond the KDF input limit is handled automatically.
Full CI example
# GitHub Actions
- name: Backup .env.production
run: |
evnx backup \
--env .env.production \
--output backups/prod-$(date +%Y%m%d).backup \
--key-file /run/secrets/BACKUP_KEY \
--keep 7 \
--verify# Docker / docker-compose
services:
backup:
image: evnx
command: >
backup
--env /secrets/.env
--key-file /run/secrets/backup_key
--keep 5
--verify
volumes:
- ./backups:/backups
secrets:
- backup_keyKey file security
Treat key files with the same care as the .env file itself. Store them in a
secrets manager (Vault, AWS Secrets Manager, GitHub Secrets) rather than on
disk alongside your repository. Never commit a key file to version control.
File permissions and security
Automatic permission hardening
On Unix-like systems, evnx backup creates backup files with restrictive
permissions regardless of the current umask:
$ evnx backup
$ ls -l .env.backup
-rw------- 1 user user 1024 Mar 10 14:30 .env.backup # 0o600: owner read/write onlyThis applies to every file in the rotation chain (.env.backup.1,
.env.backup.2, …) — all are originally created by evnx with 0o600.
Troubleshooting
"Password must be at least 8 characters"
evnx enforces a minimum password length as a sanity guard. Argon2id makes brute-forcing expensive, but short passwords remain vulnerable to dictionary attacks.
Fix: Use a longer password or passphrase:
# ✅ Strong passphrase
evnx backup # then type: correct-horse-battery-staple"Passwords do not match" (exit code 3)
The confirmation prompt did not match the original entry. Re-run the command and
type both prompts carefully. This check does not apply when --key-file is used.
"File does not look like a standard .env file"
evnx heuristically checks whether the input resembles a .env file. This
warning is non-fatal — the backup proceeds regardless.
⚠️ File does not look like a standard .env file — backing up anyway
When this is expected
This warning appears when backing up files with unusual formatting, files
containing mostly comments, or non-.env files you intentionally want to
encrypt. If unexpected, verify the --env path is correct.
"Backup integrity check failed" (exit code 6)
The --verify check failed: evnx could not re-decrypt the file it just wrote,
or the recovered content did not match the original. The backup file is left on
disk for inspection.
Possible causes:
- ›Filesystem error during write (full disk, permission change mid-write)
- ›Storage hardware fault
Fix: Check available disk space, inspect the backup file, and retry. If the problem persists on a specific path, try a different output location.
"Key file not found" or "Key file is not a regular file"
evnx validates the key file path before attempting to read it.
Fix: Verify the path exists and is a regular file (not a directory or symlink to a missing target):
ls -l /run/secrets/backup-key"Backup feature not enabled"
The backup/restore feature is optional and must be enabled at build time:
✗ Backup feature not enabled
Rebuild with: cargo build --features backup
Fix:
cargo install evnx --features backup
# or for local development:
cargo build --features backupBest practices
Password and key file management
- ›Never commit passwords or key files to version control
- ›Use a password manager or secrets manager (Vault, AWS Secrets Manager, 1Password Secrets Automation) to generate and store credentials
- ›Use different passwords/keys for different environments (dev / staging / prod)
- ›Rotate credentials periodically and re-encrypt existing backups after rotation
Backup storage
- ›Store backups in a location separate from your source code repository
- ›Use encrypted storage or a secret manager for the backup files themselves
- ›Use
--keepwith a value appropriate to your recovery window - ›Run
--verifyfor any backup you intend to archive or ship offsite - ›Test restore procedures regularly — a backup you cannot restore is not a backup
Recommended CI invocation
evnx backup \
--env .env.production \
--output /secure/backups/prod.backup \
--key-file /run/secrets/backup_key \
--keep 7 \
--verifyThis combination: uses a machine-readable key (no TTY required), retains a week of daily backups, and proves each one is readable before the job exits.
Exit codes
| Code | Meaning |
|---|---|
0 | Backup created successfully |
1 | Generic error: IO failure, encoding error, unexpected failure |
2 | Source file not found or not a regular file |
3 | Password confirmation did not match |
4 | Encryption failed |
5 | Failed to write backup file to disk |
6 | Post-write integrity check failed (--verify) |
Related commands
- ›evnx restore — decrypt and restore a backup to a
.envfile - ›evnx validate — check
.envfiles for misconfiguration - ›evnx scan — detect secrets and sensitive patterns in
.envfiles