Deployment configuration for cryptograss infrastructure. Maybelle is the control plane for deploying and managing hunter (development VPS) and maybelle itself (CI/CD server).
- secrets/ - Single unified vault for all secrets (gitignored plaintext, encrypted for production)
- hunter/ - Deployment configuration for hunter VPS (multi-user magenta development environment)
- maybelle/ - Deployment configuration for maybelle server (Jenkins CI/CD)
All deployments run from maybelle server.
cd ~/maybelle-config/hunter
./deploy.shcd ~/maybelle-config/maybelle
ansible-playbook -i localhost, ansible/maybelle.yml --ask-vault-passSecrets are stored in secrets/vault-plaintext.yml (gitignored). Required variables:
Hunter secrets:
memory_lane_postgres_password- PostgreSQL passwordjustin_vscode_password- Justin's code-server passwordrj_vscode_password- R.J.'s code-server password
Maybelle secrets:
maybelle_env- Jenkins environment variables (multiline string)jenkins_admin_password- Jenkins admin logingithub_token- GitHub API token
Note: TLS certificates are handled automatically by Caddy via Let's Encrypt.
For production, encrypt with:
ansible-vault encrypt secrets/vault-plaintext.yml -o secrets/vault.ymlTo edit encrypted vault:
ansible-vault edit secrets/vault.ymlTo decrypt for local development:
ansible-vault decrypt secrets/vault.yml -o secrets/vault-plaintext.ymlMaybelle (maybelle.cryptograss.live):
- Jenkins CI/CD in Docker
- Caddy reverse proxy with automatic SSL
- Builds arthel (justinholmes.com + cryptograss.live)
- Hosts Memory Lane (PostgreSQL + Django + MCP server)
- Deploys to hunter via SSH
Hunter (hunter.cryptograss.live):
- Multi-user development containers
- Watcher service (monitors conversations, writes to maybelle's database)
- Per-user isolation with dedicated ports and SSH
Production builds go through a two-stage process for security:
- Jenkins builds the site and writes to
/var/jenkins_home/www/builds/production/ - Jenkins creates a
.deploy-readymarker file with build metadata - Root cron (every 2 min) checks for marker, rsyncs to NearlyFreeSpeech, removes marker
This separation means a compromised Jenkins cannot directly push to production - an attacker would also need root access on maybelle.
Logs:
- Deploy log:
/var/log/nfs-deploy.log - Viewable in Jenkins via the backup-memory-lane job
Memory Lane database backups run automatically:
- Bi-hourly: Every 2 hours at :00, named by Ethereum block height
- Location:
/mnt/persist/magenta/backups/ - Retention: 2 days
- Script:
/mnt/persist/magenta/backup-postgres.sh
- Schedule: 3am daily (copied from bi-hourly)
- Location:
/mnt/persist/magenta/backups/daily/ - Retention: 30 days
- Schedule: 4am daily (after daily backup created)
- Destination: NearlyFreeSpeech
/home/private/backups/ - Retention: Mirrors daily folder (~30 days)
- Script:
/usr/local/bin/backup-to-nfs.sh - Log:
/var/log/nfs-backup.log
The backup-memory-lane Jenkins job runs every 2 hours at :30 and checks:
- Latest backup exists and is <3 hours old
- Daily backup count and age
- Offsite sync log for recent successful syncs
# On maybelle as root:
/mnt/persist/magenta/backup-postgres.sh# On maybelle as root:
/usr/local/bin/backup-to-nfs.shOn maybelle rebuild, ansible will:
- Check if database is empty
- List available backups (sorted by size)
- Prompt for which backup to restore
To manually restore:
docker exec magenta-postgres pg_restore -U magent -d magenta_memory --no-owner --no-privileges /backups/[backup-file].dumpSecrets are stored in secrets/vault.yml (ansible-vault encrypted).
Required secrets:
| Variable | Purpose |
|---|---|
memory_lane_postgres_password |
PostgreSQL password for Memory Lane |
ingest_api_key |
API key for watcher to submit conversations |
jenkins_admin_password |
Jenkins admin login |
maybelle_github_token |
GitHub API token for Jenkins |
jenkins_github_ssh_key |
SSH key for Jenkins GitHub access (base64) |
hunter_root_ssh_key |
SSH key for maybelle→hunter access (base64) |
nfs_ssh_key |
SSH key for production deploys and backups (base64) |
justin_vscode_password |
Justin's code-server password on hunter |
To edit:
ansible-vault edit secrets/vault.ymlThis repo consolidates deployment configuration from:
magenta/hunter/→hunter/arthel/deployment/→maybelle/- Scattered secrets →
secrets/vault.yml