Backing Up Using the Built In Tools

From OpenEMR Project Wiki

Backup your Installation

Docker Backup Script (8.3.0 and later)

For Docker Compose deployments, OpenEMR ships a backup script at contrib/util/openemr-docker-backup.sh. It replaces the web interface backup removed in 8.3.0.

Run it on the Docker host, not inside the OpenEMR container. A copy ships inside the container's webroot for reference only.

Install

curl -o /opt/openemr/openemr-docker-backup.sh \
  https://raw.githubusercontent.com/openemr/openemr/master/contrib/util/openemr-docker-backup.sh
chmod 700 /opt/openemr/openemr-docker-backup.sh

Review the configuration block at the top of the script (COMPOSE_DIR, BACKUP_ROOT, service names, credentials, RETENTION_DAYS) and adjust it for your deployment. Then run it once by hand:

/opt/openemr/openemr-docker-backup.sh /path/to/compose/directory

Schedule

On Linux hosts, add a cron entry (this one runs daily at 2:15 AM):

15 2 * * * /opt/openemr/openemr-docker-backup.sh >> /var/log/openemr-backup.log 2>&1

For Windows / Docker Desktop (WSL2) hosts, the script's header explains how to schedule it with Windows Task Scheduler.

What it backs up

Each run creates a timestamped directory under BACKUP_ROOT (default /var/backups/openemr) containing:

  • openemr-db.sql.gz: a full database dump, including routines, triggers, and events
  • openemr-files.tar.gz: the OpenEMR webroot, including sites/ (documents, config, SSL material) and custom modules
  • The Compose configuration, including .env and the fully resolved config
  • manifest.txt, which records the image versions in use, and SHA256SUMS

It does not capture CouchDB document storage (if you've enabled it) or the container images themselves.

The script verifies archive integrity, prunes old backups, and writes a LAST_BACKUP_OK or LAST_BACKUP_FAILED marker you can monitor.

Restoring

Step-by-step restore instructions are at the bottom of the script. Test your restores. A full restore drill to a scratch VM at least quarterly also helps satisfy the HIPAA Security Rule's contingency plan testing requirement (45 CFR 164.308(a)(7)).

Offsite copies

The script only writes locally. Pair it with a tool such as rclone, restic, or borg to push backups to encrypted offsite storage. Local-only backups won't survive ransomware or hardware loss.

Manual Backup (Non-Docker Installs)

If you run OpenEMR directly on a server (package or source install, not Docker), you can back up the same two pieces by hand: the database and the sites/ directory.

Find your database settings

Your database name, user, and password are in sites/default/sqlconf.php (look for $dbase, $login, and $pass). The examples below assume a database named openemr and an OpenEMR directory of /var/www/openemr. Adjust both for your install.

Store credentials safely

To keep the password off the command line (and out of your shell history and process list), put it in a credentials file readable only by root:

cat > /root/.openemr-backup.cnf <<'EOF'
[client]
user=openemr
password=YOUR_DB_PASSWORD
host=localhost
EOF
chmod 600 /root/.openemr-backup.cnf

Run the backup

OPENEMR_DIR=/var/www/openemr
BACKUP_DIR=/var/backups/openemr/$(date +%Y-%m-%d)

umask 077
mkdir -p "$BACKUP_DIR"

# 1. Database dump (consistent snapshot, without locking users out)
mysqldump --defaults-extra-file=/root/.openemr-backup.cnf \
  --single-transaction --quick --routines --triggers --events \
  openemr | gzip > "$BACKUP_DIR/openemr-db.sql.gz"

# 2. sites/ directory (documents, config, letter templates, SSL material)
tar -czf "$BACKUP_DIR/openemr-sites.tar.gz" -C "$OPENEMR_DIR" sites

# 3. Check that both archives are intact
gzip -t "$BACKUP_DIR/openemr-db.sql.gz" && gzip -t "$BACKUP_DIR/openemr-sites.tar.gz"

If you've installed custom modules (interface/modules/custom_modules) or made local code changes, archive the whole OpenEMR directory instead of just sites/:

tar -czf "$BACKUP_DIR/openemr-files.tar.gz" -C "$(dirname "$OPENEMR_DIR")" "$(basename "$OPENEMR_DIR")"

If mysqldump reports a permissions error on routines, triggers, or events, run it with a database user that has those privileges (such as root).

Restore

With OpenEMR installed at the same version as the backup:

gunzip -c openemr-db.sql.gz | mysql --defaults-extra-file=/root/.openemr-backup.cnf openemr
tar -xzf openemr-sites.tar.gz -C /var/www/openemr
chown -R www-data:www-data /var/www/openemr/sites   # use apache:apache on RHEL-family systems

If you archived the whole OpenEMR directory, extract openemr-files.tar.gz into its parent instead (-C /var/www) and fix ownership on the whole directory.

Then log in, open a recent patient and document, and check Administration → Other → Logs for errors.

To automate the backup, save the backup commands as a script and schedule it with cron, as shown in the Docker section above. The same offsite-copy and restore-testing advice applies here.

Via the Web Interface (Legacy, before 8.3.0)

Removed in OpenEMR 8.3.0. This tool is not available in 8.3.0 and later. Use the Docker backup script or, for non-Docker installs, the manual backup steps instead. See the forum announcement for background.

On versions before 8.3.0:

  1. Go to Admin → System → Backup.
  2. Click Create Backup.
  3. Save the resulting emr_backup.tar file.

Rename the file with the backup date (for example, emr_backup_2026-10-06.tar) so you can tell your backups apart. The tarball contains openemr.sql.gz (the database) and openemr.tar.gz (the OpenEMR files, including uploaded documents).

Protecting Your Backups

Backups contain Protected Health Information (PHI): your entire database and every document uploaded to OpenEMR. Store, transmit, and dispose of them with the same safeguards you apply to any PHI under HIPAA and other applicable regulations. Encrypt them at rest, restrict access, and never send them over unencrypted channels.

Via the CLI

This method is designed to give you the same result as the GUI backup method.

For the following commands, you will need to ssh into the server.

  • You should also run pwd so that you know what the present working directory is (ie, where you are). If you ssh-ed in as root, then you should be in /root, if you ssh-ed as a user, then you should be in /home/yourusername. You need to know this location for future steps.
    pwd

Get a backup of the database

The following command will dump the database structure and contents into a gzipped file in the present working directory.

  • Run mysqldump and pipe the output to a gzip file
    mysqldump --opt --quote-names --ignore-table="$CUSTOM_DATABASE".onsite_activity_view --hex-blob -u openemr -p openemr | gzip > openemr.sql.gz
    • The -p is a short form of --password and indicates that mysqldump should prompt you for the password after executing the command. Enter the password when prompted to do so. It will be the password you used when you installed the MySQL database for OpenEMR.
    • The other options for mysqldump inicated above are
      • --opt: optimizes the dump
      • --quote-names puts backticks around the object names
      • -u is a short form of --user and indicates the mysql user account to use when running the commmand (the username follows the option)
      • the 'openemr' before the pipe indicates the name of the database to dump

Stay sshed in the server in order to do the next section.

Get a backup of the openemr folder

The following command will archive and compress the contents of /var/www/openemr and store it in the present working directory alongside the MySQL dump. note that this location may be different for different installation methods.

  • Use tar to create and compress an archive of the openemr folder and store it in the same place you stored your mysql dump file
    tar -C /var/www/openemr/ -zcf openemr.tar.gz ./
    • The options on the tar command above are as follows
      • -C: Change to the stated directory and run tar from there. It accomplishes the same as using cd to move to the stated location and then using cd to come back to the original directory when done.
      • -z: Compress archive using gzip program
      • -c: Create archive
      • -f: Archive File name (ie, the name of the output tarball)
      • -v: Verbose (ie, display progress while creating archive) If you want to see the terminal spit out a list of all the files being archived, you can include this option.

Stay sshed in the server in order to do the next section.

Tar the data and filesystem backups together

  • Use tar to take the files created in the above sections and bind them into one file
    • You can simply name the tar file 'emr_backup.tar' like the GUI process does and then rename the tar later. But why go through another step if you don't have to? You can name the tar file using the conventions mentioned above (ie, emr_backup_[date].tar) when you're making the tar.
    tar -cvf emr_backup.tar openemr.sql.gz openemr.tar.gz
    The options on the tar command above are as follows
    • c: Create archive
    • v: Verbose (i.e display progress while creating archive) If you don't want to see the terminal spit out a list of all the files being archived, you can leave this option out.
    • f: Archive File name

Recovery

1. Restore script can be found in openemr/contrib/util as an executable file.

2. Copy emr_backup.tar and restore script to the home directory.

3. Have the OpenEMR database password (see Step 8 for its location) recorded elsewhere, then delete the openemr web directory.

If not, the password will be lost with the deletion of the web directory.

4. Open Terminal.

5. Issue this command after the dollar sign: sudo ./restore ($ sudo ./restore), 1 space after $ with no space before restore.

This command must be used because it is not possible to run the script by double clicking on the icon.

6. Path to the backup file: /home/<your home directory username>/emr_backup.tar


7. Answer Y when asked about supplying the site ID.

If the practice has only 1 site, use the default values between the square brackets and hit Enter each time.


8. The OpenEMR database password can be found in openemr/sites/default/sqlconf.php, if the practice has only 1 site.


Enter the password when prompted.


Understand that there are two passwords for MySQL; one for user, openemr and one for user, root; which is required in the next step. Be certain that the distinction is clear in your mind before you attempt recovery.
With repeat restores to the same database, this step may be skipped; because the password had been stored from a prior recovery.
If the practice has multiple sites, supply the relevant data.
N.B.: If the user is restoring to a new device, he must use the password from the new device, not the old machine. If he uses the credential from the old machine, he will have difficulties logging into the new device.


9. Supply the MySQL root password. If it has been lost, here is a reset tutorial.

When restoring to a new device, remember to use the root password for the receiving device, not the machine which created the emr_backup.tar.