ProxSave can send backup status notifications through multiple channels. You can enable more than one channel at the same time (recommended for redundancy).
Quick start
Most setups configure notification variables in configs/backup.env. If you upgraded from an older ProxSave version and your backup.env is missing new keys, run:
proxsave --upgrade-config
Preview changes without writing:
proxsave --upgrade-config-dry-run
Common behavior (all channels)
When notifications are sent
Notifications are dispatched only at the end of a real run (after archive creation and any storage sync/retention steps). If you run ProxSave with --dry-run (or DRY_RUN=true), notifications are skipped.
Delivery order and criticality
Notification failures never abort the backup. Errors are logged and the run continues.
Dispatch order:
- Telegram
- Gotify
- Webhook
Status mapping
Backup status in notifications is derived from the final exit code:
- success: exit code
0 - warning: exit code
1(non-fatal warnings detected during the run) - failure: exit code
>= 2
Where to configure
Notification configuration is normally stored in configs/backup.env (installed by the interactive installer).
Telegram
Telegram supports two modes:
- centralized (default): ProxSave fetches bot/chat credentials from a centralized Telegram service using your server ID.
- personal: you provide your own bot token and chat ID.
Configuration
TELEGRAM_ENABLED=true
BOT_TELEGRAM_TYPE=centralized # centralized | personal
# Personal mode only
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=987654321
Centralized mode registration
During install/upgrade ProxSave prints instructions similar to: “Open @ProxmoxAN_bot and enter your code”. Send that code to the bot to link your server ID.
Notes:
- Your server ID is automatically generated and persisted under identity/.server_identity (you normally do not need to set
SERVER_IDmanually). - If the centralized service is unreachable or the server is not registered, Telegram notifications are disabled for that run.
- Typical handshake failure codes (logged): 403 (bot not started / first communication), 409 (missing registration), 422 (invalid server ID).
Personal mode credentials
TELEGRAM_BOT_TOKENmust look likedigits:...(Telegram bot token format).TELEGRAM_CHAT_IDmust be numeric (group chat IDs can be negative).
What the Telegram message contains
Telegram notifications are plain text and include (at minimum):
- ProxSave version (when available)
- Backup type (PVE/PBS) and hostname
- Local/Secondary/Cloud storage status summaries (and whether a tier is disabled)
- Email status (useful when Telegram is used as a redundant channel)
- Included/missing file counts
- Free space (Local and, when enabled, Secondary)
- Backup date, duration, and exit code
- Optional “update available” hint when a new ProxSave version is detected
Email supports two delivery methods:
- relay: sends the notification through the built-in HTTPS relay service.
- sendmail: hands the message off to the local sendmail binary (requires a local MTA).
Optional fallback: if EMAIL_DELIVERY_METHOD=relay and EMAIL_FALLBACK_SENDMAIL=true, ProxSave tries sendmail if the relay fails.
Configuration
EMAIL_ENABLED=true
EMAIL_DELIVERY_METHOD=relay # relay | sendmail
EMAIL_FALLBACK_SENDMAIL=true # fallback to sendmail if relay fails
EMAIL_RECIPIENT=admin@example.com # empty = auto-detect from Proxmox
EMAIL_FROM=no-reply@proxmox.tis24.it
Notes:
- If
EMAIL_RECIPIENTis empty, ProxSave attempts to auto-detect it from Proxmox (theroot@pamemail address). - Root recipients are intentionally rejected; set
EMAIL_RECIPIENTto a real mailbox. - If sendmail is used (primary or fallback), ProxSave performs a quick outbound port 25 preflight; if port 25 looks blocked, sendmail delivery is skipped for that run.
Practical guidance:
- Choose relay if you want ProxSave to deliver over HTTPS (requires outbound network access).
- Choose sendmail if the host has a correctly configured local MTA that can deliver mail.
Gotify
Send push notifications to a self-hosted Gotify server.
GOTIFY_ENABLED=true
GOTIFY_SERVER_URL=https://gotify.example.com
GOTIFY_TOKEN=AaBbCcDdEeFf123456
GOTIFY_PRIORITY_SUCCESS=2
GOTIFY_PRIORITY_WARNING=5
GOTIFY_PRIORITY_FAILURE=8
Notes:
- ProxSave posts to the Gotify /message endpoint with the token as a query parameter.
- Title and body are derived from the same subject/plain-text report used by Email.
Webhook
Webhook notifications can send JSON payloads to one or more endpoints.
Global configuration
WEBHOOK_ENABLED=true
WEBHOOK_ENDPOINTS=discord_alerts,teams_ops
WEBHOOK_FORMAT=generic
WEBHOOK_TIMEOUT=30
WEBHOOK_MAX_RETRIES=3
WEBHOOK_RETRY_DELAY=2
Per-endpoint configuration
For each endpoint name in WEBHOOK_ENDPOINTS, ProxSave builds a variable prefix by uppercasing the name and replacing - with _.
Example for endpoint name discord_alerts:
WEBHOOK_DISCORD_ALERTS_URL=https://discord.com/api/webhooks/XXX/YYY
WEBHOOK_DISCORD_ALERTS_FORMAT=discord # discord | slack | teams | generic
WEBHOOK_DISCORD_ALERTS_METHOD=POST # POST recommended; GET/HEAD do not send a payload
WEBHOOK_DISCORD_ALERTS_HEADERS="X-Custom-Token:abc123,X-Another:value"
WEBHOOK_DISCORD_ALERTS_AUTH_TYPE=none # none | bearer | basic | hmac
WEBHOOK_DISCORD_ALERTS_AUTH_TOKEN= # bearer
WEBHOOK_DISCORD_ALERTS_AUTH_USER= # basic
WEBHOOK_DISCORD_ALERTS_AUTH_PASS= # basic
WEBHOOK_DISCORD_ALERTS_AUTH_SECRET= # hmac
Notes:
- URLs must be http:// or https://.
- If
WEBHOOK_ENABLED=truebut no valid endpoints are configured (no URLs), webhook initialization fails and is logged as a warning. - Custom headers use comma-separated Key:Value pairs. Some headers are protected and will be ignored if you try to set them: Host, Content-Length, Content-Type, Transfer-Encoding.
- GET and HEAD do not include a request body; use POST if you want the JSON payload to be delivered.
- Authentication:
- bearer: sets Authorization: Bearer <token>
- basic: sets Authorization: Basic <base64(user:pass)>
- hmac / hmac-sha256: sets X-Signature and X-Signature-Algorithm: hmac-sha256 computed over the JSON payload
Formats
Supported formats:
- discord: Discord embed payload
- slack: Slack blocks payload
- teams: Microsoft Teams connector payload
- generic: structured JSON (recommended for custom integrations)
Generic payload (field overview)
The generic format sends a JSON object with stable top-level fields such as:
- status, status_message, status_emoji, exit_code
- hostname, proxmox_type, server_id, server_mac, script_version
- timestamp, timestamp_iso
- backup (filename/size/duration/files)
- compression (type/level/mode/ratio)
- storage (local, plus optional secondary/cloud when enabled)
- issues (errors, warnings, total)
- update (new/current/latest version information)
- log_categories (optional, when available)
Success semantics
When multiple endpoints are configured, ProxSave attempts all of them. Webhook notifications are considered successful if at least one endpoint succeeds.
Example: Telegram + Email + Webhook (Discord)
# Telegram (personal mode)
TELEGRAM_ENABLED=true
BOT_TELEGRAM_TYPE=personal
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=987654321
# Email
EMAIL_ENABLED=true
EMAIL_DELIVERY_METHOD=relay
EMAIL_FALLBACK_SENDMAIL=true
EMAIL_RECIPIENT=admin@example.com
EMAIL_FROM=noreply@proxmox.example.com
# Webhook (Discord)
WEBHOOK_ENABLED=true
WEBHOOK_ENDPOINTS=discord_alerts
WEBHOOK_DISCORD_ALERTS_URL=https://discord.com/api/webhooks/XXXX/YYYY
WEBHOOK_DISCORD_ALERTS_FORMAT=discord
WEBHOOK_DISCORD_ALERTS_METHOD=POST
Testing and troubleshooting
Testing delivery
proxsave --dry-run is useful to validate configuration and permissions, but it does not send notifications.
To test notification delivery, run proxsave without --dry-run with the desired channels enabled and check ${BASE_DIR}/log/ for the delivery result.
If you need more details, rerun with debug logging:
proxsave --log-level debug
Troubleshooting checklist
- Telegram:
- Personal mode requires a valid token format and a numeric
TELEGRAM_CHAT_ID(group chat IDs can be negative). - Centralized mode requires a working network connection; if the handshake fails, Telegram is disabled for that run.
- Email:
- Ensure
EMAIL_RECIPIENTresolves to a real mailbox (root recipients are blocked). - If using sendmail, verify an MTA is installed/configured and outbound SMTP is possible.
- Webhook:
- Use POST if you expect a JSON payload.
- Check the response status/body in logs; retries are applied based on
WEBHOOK_MAX_RETRIESandWEBHOOK_RETRY_DELAY.