Automated daily PostgreSQL backup of your TeslaMate database to Filen encrypted cloud storage.
| File | Purpose |
|---|---|
backup.sh |
Main backup script — dumps DB, uploads to Filen, rotates old backups |
restore.sh |
Restore script — lists backups, downloads from Filen, restores DB |
install-cron.sh |
One-command cron job installer |
.env |
Configuration (created on first run of install-cron.sh) |
curl -sL https://filen.io/cli.sh | bashVerify installation:
filen --versionNote: Filen is sunsetting the current TypeScript CLI in favor of a Rust rewrite. The current v0.0.36 works fine. If the install script fails, download the binary directly from https://github.com/FilenCloudDienste/filen-cli/releases/tag/v0.0.36
Interactive login (do this once via SSH):
filen loginEnter your Filen email and password when prompted.
For headless/cron use, export an auth config so the CLI doesn't need interactive login:
filen export-auth-configThis creates a .filen-cli-auth-config file. The CLI will use it automatically
for future non-interactive commands.
If you have 2FA enabled on Filen: You'll need to provide the 2FA code during initial login. After that, the exported auth config handles subsequent sessions.
filen mkdir /teslamate-backupsTest that uploads work:
echo "test" > /tmp/filen-test.txt
filen upload /tmp/filen-test.txt /teslamate-backups/
filen ls /teslamate-backups/
rm /tmp/filen-test.txtYou should see filen-test.txt listed. Delete it:
filen rm /teslamate-backups/filen-test.txt# If from a repo:
git clone <your-repo-url> ~/teslamate-filen-backup
cd ~/teslamate-filen-backup
# Or just copy the files:
mkdir -p ~/teslamate-filen-backup
# ... copy backup.sh, restore.sh, install-cron.sh here
chmod +x backup.sh restore.sh install-cron.shRun the installer once — it will create the .env file:
./install-cron.shEdit the .env file to match your setup:
nano .envKey settings to verify:
# Must point to where your TeslaMate docker-compose.yml lives
TESLAMATE_COMPOSE_DIR=$HOME/teslamate
# Must match the service name in your docker-compose.yml
# (usually "database" or "db")
TESLAMATE_DB_SERVICE=database
# Must match POSTGRES_USER and POSTGRES_DB in your docker-compose.yml
TESLAMATE_DB_USER=teslamate
TESLAMATE_DB_NAME=teslamatecd ~/teslamate-filen-backup
set -a && source .env && set +a
./backup.shYou should see output like:
[2026-02-11 03:00:00] ═══ TeslaMate Backup Starting ═══
[2026-02-11 03:00:01] Dumping database...
[2026-02-11 03:00:05] Database dump complete: teslamate_20260211_030000.sql.gz (12M)
[2026-02-11 03:00:06] Uploading to Filen: /teslamate-backups/
[2026-02-11 03:00:15] Upload complete
[2026-02-11 03:00:16] ✓ Upload verified on Filen
[2026-02-11 03:00:16] Rotating local backups (keeping last 7 days)...
[2026-02-11 03:00:16] Local backups remaining: 1
[2026-02-11 03:00:16] ═══ Backup Complete ═══
Verify on Filen:
filen ls /teslamate-backups/./install-cron.shThis installs a daily 3:00 AM backup. To change the schedule:
# Every 12 hours
./install-cron.sh '0 */12 * * *'
# Twice daily at 3 AM and 3 PM
./install-cron.sh '0 3,15 * * *'
# Daily at midnight
./install-cron.sh '0 0 * * *'Verify:
crontab -lList available backups (both local and on Filen):
./restore.shRestore the most recent local backup:
./restore.sh latestRestore a specific backup:
./restore.sh teslamate_20260211_030000.sql.gzIf the file is only on Filen (not local), the script will download it first.
After restoring: If you had custom SQL views (from the dashboards guide), re-run them:
docker compose exec -T database psql -U teslamate -d teslamate < ~/teslamate-custom-dashboards/sql/custom_views.sql
Add to your .env:
NOTIFY_URL=https://ntfy.sh/your-unique-topic-nameThen install the ntfy app on your phone and subscribe to the same topic.
You'll get a push notification after each backup: ✅ TeslaMate backup OK: teslamate_20260211.sql.gz (12M)
Create a bot via @BotFather, get your chat ID, then use:
NOTIFY_URL=https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<CHAT_ID>&text=Note: for Telegram the script would need slight modification since Telegram expects the message as a URL parameter. The ntfy.sh approach is simpler.
| TeslaMate age | Approx dump size | Monthly Filen usage (daily backups) |
|---|---|---|
| 1 month | ~5-15 MB | ~150-450 MB |
| 6 months | ~20-50 MB | ~600 MB - 1.5 GB |
| 1 year | ~40-100 MB | ~1.2-3 GB |
| 2+ years | ~80-200 MB | ~2.4-6 GB |
With default retention (30 days on Filen, 7 days local), you'll use roughly 30× your daily dump size on Filen at steady state.
Filen's free tier gives you 10 GB, which should be plenty for the first year+.
Make sure the binary is in your PATH:
# Check where it installed
ls ~/.filen-cli/bin/ 2>/dev/null || ls /usr/local/bin/filen 2>/dev/null
# Add to PATH if needed (add to ~/.bashrc)
export PATH="$HOME/.filen-cli/bin:$PATH"For cron jobs, the PATH may be different. You can set FILEN_CLI in .env
to the full path:
FILEN_CLI=$HOME/.filen-cli/bin/filenThe cron environment doesn't have the same environment as your shell.
Make sure you ran filen export-auth-config and that the auth config
is in the default data directory (~/.config/filen-cli/ or ~/.filen-cli/).
If running as a non-root user, make sure your user is in the docker group:
sudo usermod -aG docker $USER
# Then log out and back inCheck that TeslaMate is actually running and has data:
cd ~/teslamate
docker compose ps
docker compose exec database psql -U teslamate -d teslamate -c "SELECT count(*) FROM positions;"Check cron logs:
grep CRON /var/log/syslog | tail -20
# or
journalctl -u cron --since "1 hour ago"Also check the cron-specific log:
cat ~/teslamate-filen-backup/cron.log