Full-instance backup of Jira & Confluence Cloud (Standard plan) to pluggable cloud storage
Project description
Jira & Confluence Full-Instance Backup
Automated full-instance backup of Jira Cloud and Confluence Cloud for the Atlassian Standard plan. Run it by hand from an interactive menu, or unattended from Jenkins/cron. Backups are encrypted and shipped to the cloud of your choice — Google Cloud Storage, AWS S3 (and S3-compatible stores), Azure Blob, or a local/mounted directory — with notifications to any channel you use: Slack, Microsoft Teams, Discord, Google Chat, email, or a generic webhook.
Why?
On March 30, 2026, Atlassian deprecated the Backup Manager API for Jira Cloud. Direct API-token calls to the backup endpoint now return:
HTTP 403
{"error":"This feature is only accessible from the UI."}
The replacement v2 Backup & Restore API is Premium/Enterprise only, leaving Standard-plan customers with no automation path for full-instance backup — only the manual UI button. This tool restores that automation by replaying the browser UI session for Jira, while Confluence uses the OBM REST API (which still accepts API tokens). Both flow into one pipeline that archives, encrypts, uploads, and notifies.
For per-project Jira backup/restore, see the sibling project jira-project-backup-restore.
Features
| Feature | Description |
|---|---|
| Full-instance backup | Jira (all projects, attachments, avatars, logos) + Confluence (all spaces, attachments) in one run |
| Run anywhere | Interactive menu for VMs/manual use and CLI flags for Jenkins/cron — same codebase |
| Pluggable storage | GCS · AWS S3 / S3-compatible (R2, B2, MinIO, Spaces) · Azure Blob · local — pick one flag; only that SDK is needed |
| Pluggable notifications | Slack · Teams · Discord · Google Chat · email (SMTP) · generic webhook — any combination, no extra deps |
| Optional encryption | 7-Zip AES-256 with encrypted headers — on by default, switch off with --no-encrypt |
| Configurable compression | 0 (store) … 9 (ultra) |
| Custom filenames | Name templates: {product} {site} {date} {time} {datetime} {timestamp} |
| Integrity & housekeeping | manifest.json with sha256 + --validate, --cleanup, --skip-existing, --dry-run |
| Cooldown-aware | Atlassian's 48h throttle (HTTP 412) is detected and skipped cleanly — no false failures |
| Connection test | Validates Jira cookies + Confluence token, warns when the Jira session is near expiry |
Install
pip install jira-confluence-full-instance-backup # core (requests)
# add the storage backend you use:
pip install "jira-confluence-full-instance-backup[s3]" # or [gcs] / [azure]
# optional nicer interactive output (progress bars, color):
pip install "jira-confluence-full-instance-backup[ui]"
# everything:
pip install "jira-confluence-full-instance-backup[all]"
Or from source:
git clone https://github.com/davidmalko87/jira-confluence-full-instance-backup.git
cd jira-confluence-full-instance-backup
pip install -r requirements.txt # + requirements-<provider>.txt as needed
Requirements: Python 3.10+, and 7z on PATH (apt install p7zip-full, or set SEVEN_ZIP_PATH).
Quick Start
1. Configure
cp .env.example .env # fill in real values — .env is gitignored
Or use the guided menu (writes .env for you): jira-confluence-backup → Configure credentials.
2. Run — interactive menu
jira-confluence-backup # or: python main.py / python -m backup
=== Atlassian Full-Instance Backup ===
Jira https://<your-site>.atlassian.net
Storage s3:my-backups
Notify slack
1) Backup Jira 7) Validate backup
2) Backup Confluence 8) Cleanup backups
3) Backup both 9) Test connections
4) Full run 10) Configure credentials
5) Archive ./out 11) Show configuration
6) Upload ./archive 12) List local backups
0) Exit
3. Run — CLI (automation)
jira-confluence-backup --all # backup both -> archive -> upload -> notify
jira-confluence-backup --all --dry-run # preview only, no API calls / no cooldown burn
jira-confluence-backup --backup jira,confluence --archive --upload --notify
jira-confluence-backup --validate # check the archive against its manifest
jira-confluence-backup --cleanup --keep-days 28 # prune incomplete + old local backups
jira-confluence-backup --test-connection # exit 0 if both auth paths are OK
Output is plain ASCII (
[INFO]/[OK]) by default — safe on any console, including legacy Windows. Install theuiextra for colored output and progress bars.
How It Works
Setup -> Jira -> Confluence -> Archive -> Upload -> Notify
(venv) (cookies) (API token) (7z, opt. (<provider>:// (your
AES-256) <dest>/Y/M/D/) channels)
Stages are independent: a Jira cookie expiry does not stop the Confluence stage.
Auth model
| Product | Endpoint | Auth | Why |
|---|---|---|---|
| Jira | /rest/backup/1/export/runbackup |
Session cookies + UI headers | Atlassian gates this endpoint to UI sessions only — API tokens return 403 |
| Confluence | /wiki/rest/obm/1.0/runbackup |
Basic (email + API token) | OBM never received the UI-only lockdown |
Do not replace the Jira side with an API token — it is gated to browser sessions and returns
403 "This feature is only accessible from the UI.". One dedicated Atlassian admin account supplies both: its API token (for Confluence) and its browser session cookies (for Jira).
Storage backends
Set STORAGE_PROVIDER + STORAGE_DEST (or --provider / --dest). Only the chosen SDK is imported; a missing one prints a pip install hint.
| Provider | STORAGE_DEST |
Optional SDK | Credentials |
|---|---|---|---|
gcs |
bucket | requirements-gcs.txt |
GOOGLE_APPLICATION_CREDENTIALS (SA JSON) |
s3 |
bucket | requirements-s3.txt |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION |
azure |
container | requirements-azure.txt |
AZURE_STORAGE_CONNECTION_STRING |
local |
directory | (none) | (none) |
S3-compatible stores (Cloudflare R2, Backblaze B2, MinIO, DigitalOcean Spaces): use s3 plus S3_ENDPOINT_URL. Objects are written to <dest>/YYYY/MM/DD/. Retention is the bucket's job (set a lifecycle rule); use a write-only identity where possible.
Notification channels
NOTIFY_CHANNELS is a comma list — pick any. One report is built and rendered per channel; a failed channel is logged but never blocks the rest.
| Channel | Needs | Notes |
|---|---|---|
slack / discord / teams / google-chat |
NOTIFY_WEBHOOK_URL |
platform-specific incoming webhook |
email |
SMTP_* |
stdlib SMTP; port 465 → SSL, else STARTTLS |
webhook |
NOTIFY_WEBHOOK_URL |
raw JSON POST (PagerDuty / Opsgenie / your API) |
Archiving: encryption, compression, names
- Encryption (default on): 7-Zip AES-256 with encrypted headers, password from
ARCHIVE_PASSWORD. Turn it off with--no-encryptor by leaving the password blank. - Compression:
ARCHIVE_COMPRESSION/--compression0–9. - Names:
PRODUCT_NAME_TEMPLATE(the per-product.zip) andARCHIVE_NAME_TEMPLATE(the.7z). Tokens:{product} {site} {date} {time} {datetime} {timestamp} {year} {month} {day}. Defaults:{product}-{date}andatlassian-backup-{date}.
Integrity & housekeeping
Each successful run writes a manifest.json (timestamp, products, per-file + archive sha256, complete: true, encrypted) next to the archive and uploads it too.
--validate— re-checksum the local archive against the manifest.--cleanup [--keep-days N]— remove incomplete backups (no manifest) and, optionally, ones older than N days.--skip-existing— skip a product already backed up today.--dry-run— preview any flow without API calls, archiving, or uploads.
Jenkins
The Jenkinsfile runs a weekly job (cron) and is driven by environment variables:
environment {
SITE_JIRA = 'https://<YOUR_SITE>.atlassian.net'
SITE_CONFLUENCE = 'https://<YOUR_SITE>.atlassian.net/wiki'
STORAGE_PROVIDER = 'gcs' // gcs | s3 | azure | local
STORAGE_DEST = '<YOUR_BUCKET>'
NOTIFY_CHANNELS = 'slack' // any comma list
}
It installs the matching provider SDK and binds only the credentials your config needs from the Jenkins Credentials store (jira-cookies, atlassian-email/atlassian-api-token, archive-password, the storage credential, and notify-webhook-url / smtp-*). No secrets live in the repo.
Cookie Refresh Procedure
The Jira tenant.session.token JWT expires roughly every 30 days. When it does, the Jira stage exits with code 2 (Cookie auth rejected — cookies likely expired). Refresh takes ~60 seconds:
- Log into Atlassian as the backup admin account.
- Open
https://<your-site>.atlassian.net/secure/admin/CloudExport.jspa. - F12 → Application → Cookies and copy these five:
tenant.session.token,atlassian.xsrf.token,JSESSIONID,AWSALB,AWSALBCORS. - Assemble as one semicolon-separated string and update it where it's stored (
JIRA_COOKIESin.env, or thejira-cookiesJenkins credential).
Test connections warns you in advance when the token is within a few days of expiry.
Response Code Semantics
| Code | Meaning | Behavior |
|---|---|---|
| 200 | Backup queued / status returned | Continue polling |
| 403 | Auth rejected (UI-only gate) | Exit 2 — refresh Jira cookies |
| 412 | 48-hour cooldown active | Exit 0 + marker — stays green |
| 400 | Body schema rejected | Investigate body (Atlassian schema change) |
| 406 | Confluence cosmetic error | Ignore — backup actually started |
Configuration Reference
All values come from environment variables, optionally loaded from .env (see .env.example). In Jenkins they are bound from the Credentials store at runtime — never from a file in the repo.
| Env var | Purpose |
|---|---|
SITE_JIRA / SITE_CONFLUENCE |
Atlassian base URLs |
JIRA_COOKIES |
Browser session cookie blob for Jira |
ATL_EMAIL / ATL_TOKEN |
Confluence Basic auth |
ARCHIVE_PASSWORD |
7-Zip AES-256 passphrase (blank = unencrypted) |
ARCHIVE_COMPRESSION |
0–9 |
PRODUCT_NAME_TEMPLATE / ARCHIVE_NAME_TEMPLATE |
Filename templates |
STORAGE_PROVIDER / STORAGE_DEST |
Backend + bucket/container/dir |
S3_ENDPOINT_URL |
S3-compatible endpoint (s3 only) |
GOOGLE_APPLICATION_CREDENTIALS / AWS_* / AZURE_STORAGE_CONNECTION_STRING |
Provider credentials |
NOTIFY_CHANNELS |
Comma list of channels |
NOTIFY_WEBHOOK_URL / SMTP_* |
Notification delivery |
Project Structure
jira-confluence-full-instance-backup/
├── main.py # Convenience shim (python main.py)
├── Jenkinsfile # Declarative pipeline (provider/channel driven)
├── pyproject.toml # Packaging + console script + ruff config
├── .env.example # Local-testing template (real .env is gitignored)
├── requirements.txt # Core (requests)
├── requirements-{gcs,s3,azure,ui}.txt # Optional extras
└── backup/
├── cli.py # Dual-mode entrypoint (menu + CLI)
├── jira.py # Cookie-authenticated Jira backup
├── confluence.py # OBM Basic-auth Confluence backup
├── archive.py # 7-Zip (optional AES-256, configurable level)
├── upload.py # Multi-provider upload (gcs/s3/azure/local)
├── notify.py # Multi-channel notifier
├── manifest.py # manifest.json: completeness + sha256 integrity
├── config.py # Env/.env config + Configure-menu persistence
├── naming.py # Filename templating
└── ui.py # Console UI (rich-optional, ASCII-safe)
Known Limitations
These are Atlassian platform constraints, not tool limitations:
- 48h Jira cooldown between full-instance backups (weekly cadence is fine).
- Cookie lifetime ~30 days; monthly manual refresh required.
- Confluence Filestore retention ~14 days (the tool downloads immediately, so this affects only the source file).
- No restore automation — restoring a full-instance backup is manual via Atlassian's UI; for per-project restore use
jira-project-backup-restore.
Contributing
See CONTRIBUTING.md. In short: no secrets in the repo, keep cloud SDKs optional, ASCII-only console output, and test auth/backup changes against a non-prod Atlassian instance. Do not switch Jira to API-token auth (see Auth model).
License
MIT — see LICENSE.
Related
jira-project-backup-restore— per-project Jira Cloud backup/restore via REST API.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jira_confluence_full_instance_backup-0.1.0.tar.gz.
File metadata
- Download URL: jira_confluence_full_instance_backup-0.1.0.tar.gz
- Upload date:
- Size: 36.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a27f3b6989973629298f588548e2b48114a8065b096b196f2e58d8873528040
|
|
| MD5 |
370199570e8f9d66dffa00c8975ee47f
|
|
| BLAKE2b-256 |
936dad0094bb8bf71194df18c9b1d74bccd592243c63c6cee47f40a663625ae9
|
Provenance
The following attestation bundles were made for jira_confluence_full_instance_backup-0.1.0.tar.gz:
Publisher:
publish.yml on davidmalko87/jira-confluence-full-instance-backup
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jira_confluence_full_instance_backup-0.1.0.tar.gz -
Subject digest:
0a27f3b6989973629298f588548e2b48114a8065b096b196f2e58d8873528040 - Sigstore transparency entry: 1634458769
- Sigstore integration time:
-
Permalink:
davidmalko87/jira-confluence-full-instance-backup@5427d4c70ebdec78ef596adc8444ee3f72dc3ec6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/davidmalko87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5427d4c70ebdec78ef596adc8444ee3f72dc3ec6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file jira_confluence_full_instance_backup-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jira_confluence_full_instance_backup-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce09758f441a3600b74d6e19ca250c35fd403610ecce14c641d176288c782c30
|
|
| MD5 |
a39f8533ab63f6496978c5d214117b54
|
|
| BLAKE2b-256 |
4c74782fcf37b39a0271cb5d291b6ec92bf4f679e50d8c098c00628c4c007233
|
Provenance
The following attestation bundles were made for jira_confluence_full_instance_backup-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on davidmalko87/jira-confluence-full-instance-backup
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jira_confluence_full_instance_backup-0.1.0-py3-none-any.whl -
Subject digest:
ce09758f441a3600b74d6e19ca250c35fd403610ecce14c641d176288c782c30 - Sigstore transparency entry: 1634458826
- Sigstore integration time:
-
Permalink:
davidmalko87/jira-confluence-full-instance-backup@5427d4c70ebdec78ef596adc8444ee3f72dc3ec6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/davidmalko87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5427d4c70ebdec78ef596adc8444ee3f72dc3ec6 -
Trigger Event:
push
-
Statement type: