Self-hosted FastAPI app to back up and restore Cloudflare Tunnel configurations, with scheduling and
3.5K
Tikka Masala is a small FastAPI web app for backing up and restoring Cloudflare Tunnel configurations. It gives you a simple UI to verify a token, list available tunnels, save JSON snapshots locally, and restore a saved configuration later.
Website: https://tikkamasala.gioxx.org
Account ID and API token from environment, browser, or databaseRecommended token permissions:
Account: Cloudflare Tunnel -> EditZone: DNS -> EditFor backup-only usage, you can later reduce the token to read-only permissions if your workflow allows it.
You can configure the app through environment variables, whether you use Docker Compose, docker run, Portainer, or a direct shell session.
| Variable | Required | Description |
|---|---|---|
CLOUDFLARE_ACCOUNT_ID | No | Prefills the Cloudflare account ID in the UI. |
CLOUDFLARE_API_TOKEN | No | Prefills the API token in the UI. |
TOKEN_ENCRYPTION_KEY | Recommended | Fernet key used to encrypt the API token before saving it in SQLite. |
AUTO_BACKUP_TIMEZONE | No | Force automatic backups to use a specific IANA timezone such as Europe/Rome. |
BACKUP_RETENTION_DAYS | No | Automatically delete backups older than this many days after new backups are created. |
NOTIFICATION_WEBHOOK_URL | No | Send JSON notifications to a generic webhook endpoint. |
NOTIFICATION_WEBHOOK_EVENTS | No | Comma-separated list of notification events to emit to the webhook. |
TELEGRAM_BOT_TOKEN | No | Telegram bot token used to send notifications through the Bot API. |
TELEGRAM_CHAT_ID | No | Telegram chat, group, or channel ID where notifications should be sent. |
TELEGRAM_NOTIFICATION_EVENTS | No | Comma-separated list of notification events to emit to Telegram. |
DATA_DIR | No | Storage path for the SQLite database and JSON backups. Default: /data. |
REQUEST_TIMEOUT | No | Outbound Cloudflare API timeout in seconds. Default: 20. |
LOG_LEVEL | No | Application log level written to container stdout. Default: INFO. |
CLOUDFLARE_API_BASE | No | Override for the Cloudflare API base URL. Default: https://api.cloudflare.com/client/v4. |
DEMO | No | Enable demo mode. Defaults to false. Demo mode disables persistence, automatic backups, notifications, and the backup archive. |
Start from .env.sample:
cp .env.sample .env
Generate a Fernet key for TOKEN_ENCRYPTION_KEY with:
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
The included docker-compose.yml mounts ./data into the container so backups and settings survive restarts.
docker compose up -d --build
Then open:
http://localhost:8080
Example .env for Compose:
CLOUDFLARE_ACCOUNT_ID=your-32-char-account-id
CLOUDFLARE_API_TOKEN=your-cloudflare-api-token
TOKEN_ENCRYPTION_KEY=your-generated-fernet-key
AUTO_BACKUP_TIMEZONE=Europe/Rome
BACKUP_RETENTION_DAYS=90
NOTIFICATION_WEBHOOK_URL=
NOTIFICATION_WEBHOOK_EVENTS=auto_backup_success,auto_backup_partial,auto_backup_failed,restore_failed,retention_cleanup
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
TELEGRAM_NOTIFICATION_EVENTS=auto_backup_success,auto_backup_partial,auto_backup_failed,restore_failed,retention_cleanup
LOG_LEVEL=INFO
DEMO=false
docker build -t tikkamasala .
docker run -d \
--name tikkamasala \
--restart unless-stopped \
--env-file .env \
-p 8080:8080 \
-v "$(pwd)/data:/data" \
tikkamasala
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
set -a
source .env
set +a
uvicorn app.main:app --host 0.0.0.0 --port 8080
The UI can prefill authentication fields from three sources:
Effective priority:
Account ID: database, then environmentAPI token: browser cookie, then database, then environmentAutomatic backups use only server-side credentials:
Account ID: database or environmentAPI token: encrypted database value or environmentBrowser cookies are never used by the scheduler.
After a successful token verification or API action:
Account ID is saved in ./data/app.dbAPI token is stored in a browser cookieAPI token is also saved in ./data/app.db only if TOKEN_ENCRYPTION_KEY is configuredImportant:
Clear saved auth data removes only the saved Account ID and API token from the database and clears the browser cookieCLOUDFLARE_ACCOUNT_ID or CLOUDFLARE_API_TOKEN are still present in the environment, the UI will continue to show those values as prefilledEverything is stored under DATA_DIR, which defaults to /data in the container and typically maps to ./data on the host.
app.db: SQLite database for backup metadata, restore history, and saved auth settingsbackups/*.json: exported tunnel configuration snapshotsTikka Masala saves the tunnel configuration returned by the Cloudflare Tunnel configuration endpoints, along with backup metadata such as:
It does not back up arbitrary account-wide Cloudflare settings.
Restoring a backup replaces the current remote configuration of the selected tunnel with the configuration stored in the snapshot.
The backup detail page keeps a restore history so you can see:
Tikka Masala can schedule recurring backups for tunnels visible in the configured account.
The scheduler is built into the app and stores its configuration in the local SQLite database. From the home page you can:
Run nowBy default, automatic backups use the timezone detected from the browser when you save the schedule. If you want a fixed server-side timezone for all users, set AUTO_BACKUP_TIMEZONE.
The Advanced schedule page (/auto-backup/tunnel-filters) lets you control backup scope and per-tunnel frequency:
Backup mode:
Frequency overrides (per tunnel):
This lets you, for example, run the scheduler daily but back up low-priority tunnels only once a week.
Important notes:
BACKUP_RETENTION_DAYS is set, old backup files and related database records are deleted automatically after new backups are createdTikka Masala can send server-side notifications through:
You can use either channel on its own or enable both at the same time.
Set:
NOTIFICATION_WEBHOOK_URL to the target endpointNOTIFICATION_WEBHOOK_EVENTS to a comma-separated list of eventsTELEGRAM_BOT_TOKEN to your Telegram bot tokenTELEGRAM_CHAT_ID to the destination chat IDTELEGRAM_NOTIFICATION_EVENTS to a comma-separated list of eventsSupported events:
notification_testmanual_backup_successmanual_backup_failedauto_backup_successauto_backup_partialauto_backup_failedrestore_successrestore_failedretention_cleanupIf NOTIFICATION_WEBHOOK_EVENTS or TELEGRAM_NOTIFICATION_EVENTS is left empty, Tikka Masala enables the default event set for that channel:
auto_backup_successauto_backup_partialauto_backup_failedrestore_failedretention_cleanupWebhook notifications send a JSON payload with:
Telegram notifications send the same information as a formatted plain-text message through the Telegram Bot API.
When notifications are configured:
Notifications box with channel and event countsSend test notification from the UI to verify webhook and/or Telegram delivery immediatelynotification_test eventEach event has a built-in default message. You can override it from the Customize notification messages page (/notifications/messages).
Messages support {placeholder} tokens that are replaced at runtime with event-specific values. Two tokens are always available regardless of the event:
{version} — current app version{timestamp} — ISO 8601 UTC timestamp of the notificationAvailable tokens per event:
| Event | Available tokens |
|---|---|
notification_test | (none specific) |
manual_backup_success | {backup_id}, {account_id}, {tunnel_id}, {tunnel_name}, {route_count} |
manual_backup_failed | {account_id}, {tunnel_id}, {error} |
auto_backup_success | {trigger}, {account_id}, {tunnel_count}, {backup_count}, {error_count}, {skipped_count}, {processed_count}, {backed_up_tunnels}, {skipped_tunnels} |
auto_backup_partial | {trigger}, {account_id}, {tunnel_count}, {backup_count}, {error_count}, {skipped_count}, {processed_count}, {backed_up_tunnels}, {skipped_tunnels} |
auto_backup_failed | {trigger}, {account_id}, {tunnel_count}, {backup_count}, {error_count}, {skipped_count}, {processed_count}, {backed_up_tunnels}, {skipped_tunnels} |
restore_success | {backup_id}, {account_id}, {tunnel_id} |
restore_failed | {backup_id}, {account_id}, {tunnel_id}, {error} |
retention_cleanup | {deleted_count}, {retention_days}, {cutoff} |
For auto_backup_* events:
{tunnel_count} — total tunnels discovered on the account{processed_count} — tunnels the run actually attempted (backup_count + error_count){skipped_count} — tunnels skipped by per-tunnel scheduling rules (not selected, weekly/monthly cooldown){backed_up_tunnels} — comma-separated list of tunnel names that were backed up (or — if none){skipped_tunnels} — comma-separated list of skipped tunnel names with the reason in parentheses (or — if none)Leaving a field empty restores the built-in default for that event. Unknown tokens are left as-is in the output.
Note: as of 1.3.4, the default
auto_backup_*messages include the new tokens above. If you had already saved a custom message, clear the field (or click Use default) on the notification customization page to pick up the new format.
Set DEMO=true when you want to exercise the UI without persisting auth data or enabling server-side automation.
In demo mode:
Manual tunnel listing and manual backup downloads still work.
TOKEN_ENCRYPTION_KEY is missing, the token is not written to SQLite.TOKEN_ENCRYPTION_KEY.app/main.pyapp/templates/index.htmlapp/templates/backup.htmlapp/templates/scheduled_runs.htmlapp/templates/tunnel_filters.htmlapp/templates/notification_messages.htmlContent type
Image
Digest
sha256:482253d21…
Size
59.6 MB
Last updated
29 days ago
docker pull gfsolone/tikkamasala