How to back up and restore Portainer
Portainer's built-in backup, under Settings > Back up Portainer, packs its database, certificates and the Compose files of the stacks it deployed into one .tar.gz. Community Edition downloads it on demand; Business Edition can also schedule it to local disk, S3 or Azure Blob. You restore it only onto a fresh Portainer, from the setup screen, and it never includes your containers, images or volumes, so back those up separately.
What Portainer keeps in portainer_data
The install command mounts a volume called portainer_data at /data in the Portainer container (portainer_portainer_data when Portainer runs as a Swarm stack). The built-in backup copies these parts of it:
| Path in /data | What it holds |
|---|---|
portainer.db | The BoltDB database: users, teams, environments, registries, Git and cloud credentials, settings, stack definitions. Called portainer.edb when database encryption is on. |
compose/ | Each stack's Compose file, in compose/<stack-id>/, and the working copy of stacks deployed from Git |
certs/ | Portainer's own HTTPS certificate and key, self-signed unless you supplied one |
tls/ | TLS files you uploaded for environments and LDAP |
custom_templates/, edge_stacks/, edge_jobs/ | Files behind custom templates, Edge stacks and Edge jobs |
chisel/ | The private key of the Edge tunnel server |
portainer.key, portainer.pub | The key pair Portainer signs its requests to agents with |
Portainer also saves a copy of the database in backups/ during each upgrade. That copy is not part of the backup file.
What a Portainer backup does not include
- Containers, images and volumes. Portainer's documentation says the backup brings Portainer's configuration back to a known-good state, not the containers it manages. Back up volumes with a helper container and databases with a dump.
- Bind-mounted data, and anything else on the hosts, such as Docker's own configuration.
- The encryption secret. An encrypted database opens only with the secret file you mount into the container. Keep a copy of that file somewhere else.
- How Portainer itself runs: the
docker runcommand or Compose file, its ports and flags such as--sslcert. Save it next to the backups.
Portainer deploys each stack as a Compose project named after the stack, so Compose labels the stack's volumes with that name. List one stack's volumes:
docker volume ls --filter label=com.docker.compose.project=wordpressDownload a backup from the dashboard
This works in both editions and needs an admin account:
- Select Settings in the menu and scroll to Back up Portainer.
- Choose Download backup file.
- Optionally turn on Password protect and enter a password. The file is then encrypted, and only Portainer's restore can open it.
- Select Download backup. Your browser saves a
.tar.gzfile.
Portainer closes its database while it copies the file, so the copy is consistent. The archive holds TLS keys, registry passwords and Git credentials: use the password option, or encrypt it yourself before it leaves the machine.
Scheduled backups in Business Edition
Business Edition adds three options to the same panel, each run on a cron rule (41 3 * * 2 runs at 3:41 every Tuesday):
| Option | Where the file goes | Notes |
|---|---|---|
| Scheduled local backup | /data/scheduled-backups/ in the container | Retention in days; 0 keeps every file. That folder sits in portainer_data itself, so mount another volume and point PORTAINER_BACKUP_PATH at it. It is read at startup: restart after changing it. |
| Store in S3 | Your bucket | Fill S3 compatible host for anything but AWS. Blank keys use credentials from the environment, such as IRSA on EKS. Optional password. Export backup runs one now. |
| Store in Azure Blob | A Blob container | Service principal, managed identity or storage account key. Optional password. |
Community Edition has none of these in its interface, but its API has the same backup call.
Schedule backups in Community Edition with the API
POST /api/backup returns the same archive as the download button and accepts an admin's access token. Logged in as an admin, open My account, then Access tokens, and add one. Save it as a header line, X-API-Key: followed by the token, in /root/.portainer-api-header, and run chmod 600 on that file. Then:
#!/usr/bin/env bash
set -euo pipefail
URL=https://127.0.0.1:9443
DIR=/var/backups/portainer
STAMP=$(date +%F-%H%M)
install -d -m 700 "$DIR"
curl -fsS --insecure -X POST "$URL/api/backup" \
-H @/root/.portainer-api-header -H "Content-Type: application/json" -d '{}' \
-o "$DIR/portainer-$STAMP.tar.gz"
curl -fsS --insecure "$URL/api/system/status" > "$DIR/portainer-$STAMP.version.json"
# fail unless the archive opens and holds the database
tar -tzf "$DIR/portainer-$STAMP.tar.gz" | grep -E '(^|/)portainer\.e?db$' > /dev/null
find "$DIR" -name 'portainer-*' -mtime +14 -delete-H @filereads the header from the file, so the token never appears in the process list.-fmakes curl fail on an HTTP error, such as a revoked token.--insecureaccepts Portainer's default self-signed certificate. The request never leaves the machine; with your own certificate, use its hostname and drop the flag.-d '{}'sends no password, so the script can check the archive with tar. To have Portainer encrypt it, send{"password":"..."}and drop the check./api/system/statusneeds no login and records the Portainer version, which a restore needs.find ... -mtime +14 -deletekeeps two weeks of local copies.
30 2 * * * root /usr/local/sbin/portainer-backup.shThen copy /var/backups/portainer off the server, for example with rclone. Scheduling backups with cron covers logging and failure mail.
Back up the portainer_data volume itself
A volume archive also keeps what the backup file skips, such as the upgrade copies in backups/. Stop Portainer first: BoltDB changes its file in place, and Portainer writes to it every five minutes even when nobody is logged in, because it snapshots each environment on that interval by default. Stopping Portainer does not stop the containers it manages.
docker stop portainerdocker run --rm -v portainer_data:/data:ro -v /var/backups/portainer:/backup alpine tar czf /backup/portainer_data-$(date +%F).tar.gz -C /data .docker start portainerEach flag is explained in backing up Docker volumes. Portainer is down only while tar runs.
Restore onto a fresh Portainer
Portainer restores only during first-time setup, on an instance with an empty data volume. The commands below are for a rebuilt host; on the same host, remove only the old container and use a new volume name, keeping the old volume until the restore checks out.
1. Start Portainer on a new volume, at the version the backup was taken on (the script above records it) or newer. A newer version upgrades the database; an older one can't open it. If the old database was encrypted, mount the same secret file now.
docker volume create portainer_datadocker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.45.12. Since 2.43 and 2.39.4, a new instance prints a one-time setup token. Read it from the log:
docker logs portainer 2>&1 | grep setup_token=3. Within five minutes of the container starting, open https://<host>:9443, expand Restore Portainer from backup, choose Upload backup file, select the file, and enter its password and the setup token. Select Restore Portainer.
Portainer loads the files, restarts (--restart=always brings the container back) and shows the login page; sign in with your old credentials. Without a browser, send the same request with curl, adding -F "password=..." for a protected file:
curl -k -X POST https://127.0.0.1:9443/api/restore -H "X-Setup-Token: <token>" -F "file=@/var/backups/portainer/portainer-2026-10-04-0230.tar.gz"Business Edition can also fetch the file from S3: choose Retrieve from S3 and give the bucket details and file name. To restore a volume archive instead, skip the setup screen: create the volume, extract the archive into it, then start Portainer with the docker run command above:
docker run --rm -v portainer_data:/data -v /var/backups/portainer:/backup:ro alpine tar xzf /backup/portainer_data-2026-10-04.tar.gz --numeric-owner -C /dataAfter either kind of restore:
- Stacks reappear in the list, but on a new host their containers and volumes don't exist yet. Restore the volumes first, then redeploy each stack from its page.
- Edge agents find Portainer through the server URL encrypted in their Edge key. Keep the same DNS name, or each Edge agent has to be redeployed.
Back up before every upgrade
New versions usually change the database schema, and an older Portainer can't open a newer database. Portainer's update guide recommends a backup first; to roll back, you reinstall the old version and restore that backup. Without one, the upgrade's own copy works: stop and remove the container, rename portainer.db in the volume, copy backups/portainer.db.bak to portainer.db, and start the previous image version. Pin a tag such as portainer/portainer-ce:2.45.1 rather than lts, so you always know which version a backup needs.
Test the backup
Restore into a throwaway instance on another port, without the Docker socket. A restored Portainer is a full copy: if it can reach your socket or agents, it can act on them, for example by running stacks' automatic Git updates.
docker run -d --name portainer-test --restart=unless-stopped -p 127.0.0.1:9444:9443 -v portainer_test:/data portainer/portainer-ce:2.45.1Take its setup token with docker logs portainer-test 2>&1 | grep setup_token= and run the curl restore above against port 9444. Open it through an SSH tunnel (ssh -L 9444:127.0.0.1:9444 you@server, then https://localhost:9444), sign in, and check users, environments and stacks. The local environment shows as down, as expected without the socket. Then remove it:
docker rm -f portainer-test && docker volume rm portainer_testDo it monthly and after upgrades; see testing backup restores.
Common errors
Invalid or missing setup token. Provide the X-Setup-Token header with the token printed in the server logs at startup.: copy thesetup_token=value from this container's log. Each new container prints its own.the Portainer instance timed out for security purposes, to re-enable your Portainer instance, you will need to restart Portainer: setup wasn't finished within five minutes.docker stop portainerthendocker start portainergives five more.Cannot restore already initialized instance: this instance already has an admin account. Restore only into a fresh container on a new, empty volume.failed to decrypt the archive. Please ensure the password is correct and try again: wrong password for a protected file.The portainer database is encrypted, but no secret was loaded: the restored database isportainer.edb. Mount the same secret file and start the container again.- The first-time setup screen appears on a Portainer that used to work: the container isn't using your volume. Check the
-v portainer_data:/datamount. - The backup file is huge: stacks deployed from Git are cloned into
/data/compose/<stack-id>/, once per stack, and the clones are in the backup.
Frequently asked questions
- Does a Portainer backup include my containers and volumes?
- No. It holds Portainer's own configuration: users, environments, settings, credentials and stack files. Back up volumes and databases separately.
- Can Portainer Community Edition schedule backups?
- Not from its interface: scheduled local, S3 and Azure Blob backups are Business Edition features. Community Edition can call POST /api/backup from cron with an admin's access token.
- Can I restore a backup into a Portainer that is already set up?
- No. Restore works only during first-time setup, on an instance with an empty data volume.
- Where does Portainer store its data?
- In the portainer_data volume, mounted at /data in the container. As a Swarm stack the volume is usually portainer_portainer_data, on the manager node running Portainer.
- Can I restore a backup on a newer Portainer version?
- Yes. A newer version upgrades the database when it starts. An older version can't open a database from a newer one.
How this was checked
Commands, limits and prices were checked against these official pages, on October 4, 2026:
- Portainer documentation: Settings, Back up Portainer and Restoring Portainer from a backup
- Portainer FAQ: What does Portainer's backup include?
- Portainer FAQ: Why is my Portainer backup so large?
- Portainer FAQ: How do I find, skip, or customize my setup token?
- Portainer FAQ: "Your Portainer instance has timed out for security purposes"
- Portainer FAQ: How can I roll back to a previous version of Portainer?
- Portainer FAQ: How can I ensure Portainer's configuration is retained?
- Portainer FAQ: Moving Edge Agent deployments to a new Portainer Server
- Portainer documentation: Install Portainer CE with Docker on Linux
- Portainer documentation: Updating on Docker Standalone
- Portainer documentation: Encrypting the Portainer database
- Portainer documentation: Accessing the Portainer API
- Portainer source: backup archive contents
- Portainer source: restore
- Portainer source: backup and restore API handlers
- Portainer source: setup token
- Portainer 2.45.1 release
- Docker CLI reference: docker volume ls (label filter)
- curl manual: -H, --header (@file)