Backup discourse from the command line

:bookmark: This guide covers how to back up and restore your Discourse site using command line tools, specifically designed for self-hosted environments.

:person_raising_hand: Required user level: Administrator

:information_source: You can use the below placeholders to automatically fill out the command line prompts in this guide:

Backing up

To create a backup of your Discourse site, follow these steps:

  1. Enter the container:
./launcher enter app
  1. Run the backup:
discourse backup
exit

This will print out the final filename of your backup. Download the backup and container configuration (if needed) to your local machine:

scp =USER=@=HOST=:/var/discourse/shared/standalone/backups/default/=FILENAME= .
scp =USER=@=HOST=:/var/discourse/containers/app.yml .

Restoring

To restore a Discourse backup, follow these steps:

  1. Install a Discourse site on the server you are restoring to.

If you’re testing this procedure multiple times, you can wipe the data on your test server.

Wipe Discourse data (optional)
./launcher stop app
./launcher destroy app
rm -r /var/discourse/shared/standalone/
mkdir -p /var/discourse/shared/standalone/backups/default/

  1. Upload the backup file:
scp =FILENAME= =USER=@=HOST=:/var/discourse/shared/standalone/backups/default/
  1. Enter the container and start the restore:
./launcher enter app
discourse enable_restore
discourse restore =FILENAME=

If you happen to forget what the filename was, run the “discourse restore” command by itself to get a list of available backup files.

:information_source: For a two-container setup, use ./launcher enter web_only and replace standalone with web-only in the path to backups.

For additional information about restoring Discourse backups, see Restore a backup from the command line.

Last edited by @SaraDev 2024-08-23T20:50:17Z

Check documentPerform check on document:
40 Likes

where should I run this command? on my cloud server terminal or my local machine?
although either give me permission denied error

On your local machine.

Are you using an SSH key to connect? The error is related.

The command should then be:

scp -i /path_to_your_key/your_key.pem root@147.43.15.199:/var/discourse/shared/standalone/backups/default/discourse-2024-12-25-033740-v20241211222608.tar.gz .

I have a scenario where I want to migrate the Discourse installation to a whole new server.
My plan was:

  1. create a new blank Discourse installation
  2. backup the old Discourse, scp the backup to the new server and restore
  3. Copy over all the S3 (images, etc.) to the new S3 on a different account

The restore process goes well until it starts looking for S3 and then fail for no access. I think it is trying to access the same S3 bucket name on the old Discourse, but that one doesn’t exist on the new one and I can’t create it.

Is there a recommended solution?

I thought I could try to change the S3 bucket name on the old Discourse (before performing backup) and then when I restore, it would expect to have the new S3 bucket. But I’m afraid of what will happen to the old Discourse if I just switch it to a non-exisiting bucket.

There’s a hidden setting that will download the s3 files and our them in the backup.

You need to configure s3 in the yml file as in Configure an S3 compatible object storage provider for uploads

Then when you restore the backup it’ll push the uploads to the new bucket.

1 Like

Did you ever figure this one out?

You need to configure s3 in env variables as described in Configure an S3 compatible object storage provider for uploads

This is especially true if the s3 settings are different on the new server. Putting the s3 values in the database can cause lots of problems.

But there is a switch for the restore command that makes it pause between the various parts. It can help.

Can I double check that the file you end up with here is the same as you get when backing up from the forum website?

I always rebuild at the command line but first back up using the website. This time I forgot to back up! I think using the command line for both might help me :slight_smile: Wish me luck.

The backup script stated:

Finished!
[SUCCESS]
Backup done.
Output file is in: /var/www/discourse/public/backups/default/FILENAME.tar.gz

To begin with I tried to download that, which contains the wrong path. I found the file elsewhere, and only then noticed that the commands on this topic are correct…

Hi! I just want to call out that to backup without uploads, use the following command:

discourse backup --sql-only

1 Like

Good call-out - we should add this (and a few other tidbits) to the OP.

1 Like

Hey @supermathie ! Good to “see” you. Not sure if you remember me? Interviewed with you a while back.

Also, it would be nice if the --help parameter worked after doing discourse backup. Instead, the backup is eventually named “–helpXXX”. :lolsob:

Cheers!

With the help of some AI, here is a comprehensive list of subcommands for the discourse command.
The discourse CLI (implemented via script/discourse using the Thor gem) provides 13 core subcommands categorized into Backups & Restores, Site Management & Modes, Database Utilities, and Data Migration (Import/Export).


Command Quick Reference

Category Subcommand Primary Function
Backup & Restore backup Generates a full or database-only backup archive.
restore Restores a .tar.gz backup file into the instance.
enable_restore Grants permission to execute restore commands.
disable_restore Revokes permission to perform restores.
rollback Reverts database state after a failed restore.
Site Modes enable_readonly Toggles temporary read-only mode across the site.
disable_readonly Removes read-only mode to restore normal site writes.
request_refresh Triggers a browser refresh prompt to all active connected clients.
Database Ops remap Performs global text search-and-replace across database tables.
Data Migration export_category Exports a single category, its topics, and associated users.
import_category Imports a category archive into the current forum.
export_topics Exports specific topics by ID and their author/replier accounts.
import_topics Imports a topic archive into the current forum.

Detailed Subcommand Documentation

1. Backup & Restore Commands

discourse backup [FILENAME]

  • Description: Creates a complete backup of the forum database and assets.

  • Flags:

  • --sql-only: (Boolean, Default: false) Dumps only the PostgreSQL database, skipping local uploaded files.

  • --s3-uploads: (Boolean, Default: false) Forces inclusion of S3-stored assets into the backup archive (ignored when --sql-only is set).

  • Example:

discourse backup
discourse backup --sql-only

discourse restore [FILENAME]

  • Description: Restores a forum backup from a local .tar.gz archive located in /var/www/discourse/public/backups/default.
  • Prerequisite: Requires running discourse enable_restore first.
  • Example:
discourse restore discourse-2026-07-22-120000-v2026xxxx.tar.gz

discourse enable_restore & discourse disable_restore

  • Description: Toggles the application flag that allows or restricts console/web-based restore tasks.
  • Usage Sequence:
discourse enable_restore
discourse restore <filename>
discourse disable_restore

discourse rollback

  • Description: Rolls back the database schema and state to the point prior to a failed restore execution.

2. Site State & Client Controls

discourse enable_readonly & discourse disable_readonly

  • Description: Sets or clears the READONLY_MODE_KEY in Redis.
  • Details:
  • Freezes database writes while keeping the site readable for users.
  • Uses a short time-to-live (TTL) loop refreshed while active, preventing the site from remaining locked permanently if a terminal session crashes.

discourse request_refresh

  • Description: Dispatches a system message via MessageBus instructing all online web sessions to reload the web page. Useful after deploying asset updates or global theme changes.

3. Database Remapping

discourse remap [OPTIONS] FROM TO

  • Description: Performs a direct string search-and-replace across text columns in the database. Crucial when updating domain names, CDN paths, or image upload prefixes.

  • Flags:

  • --global: (Boolean) Scans and remaps across all tables rather than standard content tables.

  • --regex: (Boolean) Evaluates the FROM parameter as a regular expression rather than a literal string.

  • Example:

discourse remap "old-domain.com" "new-domain.com"
discourse remap --global "/uploads/default/" "/cdn-uploads/"

4. Selective Data Import & Export

discourse export_category [CATEGORY_ID]

  • Description: Serializes a single category, including all nested topics, posts, and participating user profiles, into a JSON archive file.

discourse import_category [FILE_PATH]

  • Description: Reads an archive created by export_category and merges the category data into the target instance.

discourse export_topics [TOPIC_IDS...]

  • Description: Takes one or more space-separated topic IDs and exports the topics, posts, and relevant user accounts.
  • Example:
discourse export_topics 102 105 210

discourse import_topics [FILE_PATH]

  • Description: Imports a JSON archive created by export_topics into the destination Discourse instance.
1 Like