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; the Jenkinsfile runs on Linux and Windows agents |
| One-paste Jenkins setup | Export a Script Console script from your config that creates all credentials + the pipeline job — no manual credential forms |
| 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.
It explains every field — including how to obtain the Jira cookie blob — and validates what you paste.
Hidden input is intentional. When entering secrets (API token, cookie blob, passwords), nothing is echoed to the screen — the prompt shows
[input hidden — paste, then Enter]. Paste and press Enter; the tool confirms back (e.g. "captured 5 cookie(s); all required present") so you know it registered, without ever displaying the value. Use Test connections to verify.
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
13) Export Jenkins setup
14) Refresh Jira cookies
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 is cross-platform — it runs on both Linux (sh) and Windows (powershell) agents. The agent needs Python 3.10+ and 7-Zip (apt install p7zip-full, or install 7-Zip on Windows). It runs weekly (cron('H 2 * * 4')) and installs only the selected provider's SDK.
📖 Full step-by-step guide (prerequisites, plugins, every credential, troubleshooting): docs/JENKINS_SETUP.md. The summary below is the quick version.
Fast setup — one paste (recommended)
- Configure locally:
python main.py→ Configure credentials (writes.env). - Generate the setup script:
python main.py→ Export Jenkins setup (orpython main.py --export-jenkins). This writes a gitignoredjenkins-setup.groovy. - In Jenkins: Manage Jenkins → Script Console, paste the file's contents, Run. It creates every credential (with the exact IDs) and the
atlassian-full-backuppipeline job pointing at this repo. - Open the job → Build Now, then delete
jenkins-setup.groovy(it contains secrets).
The job uses Pipeline script from SCM, so Jenkins reads the
Jenkinsfilestraight from the repo at build time — there is no Jenkinsfile to generate or maintain inside Jenkins, and updates flow automatically from the repo.
Manual setup
Edit the Jenkinsfile environment block for your site / provider / channels:
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
}
Create a Pipeline job → Pipeline script from SCM → Git → this repo → */master → Script Path Jenkinsfile, and add the credentials below (IDs must match exactly — the pipeline binds only the ones your config needs):
| Credential ID | Kind | Used when |
|---|---|---|
jira-cookies |
Secret text | always (Jira) |
atlassian-email, atlassian-api-token |
Secret text | always (Confluence) |
archive-password |
Secret text | always (may be blank = unencrypted) |
gcp-backup-sa-key |
Secret file | STORAGE_PROVIDER=gcs |
aws-access-key-id, aws-secret-access-key |
Secret text | STORAGE_PROVIDER=s3 |
azure-storage-connection-string |
Secret text | STORAGE_PROVIDER=azure |
notify-webhook-url |
Secret text | chat/webhook channels |
smtp-host/from/to/user/password |
Secret text | email channel |
No secrets live in the repo — they stay in the Jenkins Credentials store.
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 → Network, reload the page, right-click the
CloudExport.jsparequest (or any/rest/backup/1/export/...request) → Copy → Copy as cURL. - Paste the whole cURL into the menu's Configure credentials (it extracts the cookies), or into the
jira-cookiesJenkins credential /JIRA_COOKIESin.env.
The cookie blob must contain at least tenant.session.token and atlassian.xsrf.token. Other cookies such as JSESSIONID / AWSALB / AWSALBCORS are load-balancer/servlet cookies that some instances set and others don't — they're forwarded automatically when present, and not required. Using a real request's "Copy as cURL" (rather than the Application→Cookies list) ensures any that are needed come along.
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 (aligned comma lists for multiple targets, e.g. gcs,s3 + bucketA,bucketB) |
BACKUP_CRON |
Jenkins schedule (default H 2 * * 4) |
PYTHON_BIN |
Jenkins agent Python path (blank = auto-detect; set if python isn't on the service PATH) |
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
├── docs/JENKINS_SETUP.md # Full Jenkins setup guide
└── 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
├── jenkins_export.py # Generate Script Console Groovy (creds + job)
├── 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.
Troubleshooting
Run Test connections (menu option 9) first — it pinpoints which of Jira / Confluence / storage is misconfigured. Common errors and fixes (403 vs the 204 "success", cookie refresh, the 48-hour cooldown, storage permissions, Jenkins) are in docs/TROUBLESHOOTING.md.
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.5.0.tar.gz.
File metadata
- Download URL: jira_confluence_full_instance_backup-0.5.0.tar.gz
- Upload date:
- Size: 47.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 |
c6c8a687f8b865a5d308f2761cccb6bf9b60d9c8120c3615f803ff8bf4aaa4a3
|
|
| MD5 |
b1ccca5944667c7ec3a728b26c9f005d
|
|
| BLAKE2b-256 |
c6e1f7261388cf90a8b439eccc1158978db9e0546a6229823d2c3f16dbd0c7e7
|
Provenance
The following attestation bundles were made for jira_confluence_full_instance_backup-0.5.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.5.0.tar.gz -
Subject digest:
c6c8a687f8b865a5d308f2761cccb6bf9b60d9c8120c3615f803ff8bf4aaa4a3 - Sigstore transparency entry: 1635495310
- Sigstore integration time:
-
Permalink:
davidmalko87/jira-confluence-full-instance-backup@5f538480cf6772578a971d4b6c5beb83dae3149a -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/davidmalko87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5f538480cf6772578a971d4b6c5beb83dae3149a -
Trigger Event:
push
-
Statement type:
File details
Details for the file jira_confluence_full_instance_backup-0.5.0-py3-none-any.whl.
File metadata
- Download URL: jira_confluence_full_instance_backup-0.5.0-py3-none-any.whl
- Upload date:
- Size: 47.8 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 |
a43817b159c6b0e1700d682b8c36b87ed67d70ad2dd7a1a663466f9939f6d35b
|
|
| MD5 |
a02f279901c4de4c534f63765c162dd9
|
|
| BLAKE2b-256 |
c3a49408b2449c424f5bc89c4f0308937b9f16714a3aee194e61ba9fc89c9e31
|
Provenance
The following attestation bundles were made for jira_confluence_full_instance_backup-0.5.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.5.0-py3-none-any.whl -
Subject digest:
a43817b159c6b0e1700d682b8c36b87ed67d70ad2dd7a1a663466f9939f6d35b - Sigstore transparency entry: 1635495322
- Sigstore integration time:
-
Permalink:
davidmalko87/jira-confluence-full-instance-backup@5f538480cf6772578a971d4b6c5beb83dae3149a -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/davidmalko87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5f538480cf6772578a971d4b6c5beb83dae3149a -
Trigger Event:
push
-
Statement type: