{"id":5547,"date":"2018-11-08T14:40:03","date_gmt":"2018-11-08T14:40:03","guid":{"rendered":"https:\/\/blog.ssdnodes.com\/blog\/?p=2919"},"modified":"2025-07-16T14:50:08","modified_gmt":"2025-07-16T14:50:08","slug":"docker-backup-volumes","status":"publish","type":"post","link":"https:\/\/www.ssdnodes.com\/blog\/docker-backup-volumes\/","title":{"rendered":"Docker Backup: Saving and Restoring Your Volumes"},"content":{"rendered":"<div id=\"preview1\" class=\"g-b g-b--t1of2 split split-preview\">\n<div id=\"preview\" class=\"preview-html\">\n<blockquote><p>You don\u2019t have a backup unless you\u2019ve restored your data from it.<\/p><\/blockquote>\n<p>The above quote is accurate even in the age of Docker. You <em>need<\/em> to have a<a href=\"https:\/\/www.ssdnodes.com\/blog\/vps-backups-simple-overthinking\/\"> backup of your applications<\/a>, and, more importantly, your Docker volumes. Volumes are the persistent storage provider for Docker containers, and you can learn more about them <a href=\"https:\/\/www.ssdnodes.com\/blog\/docker-volumes-data\/\">here<\/a>.<\/p>\n<p>We\u2019ll pick up where that piece left off and work with the volume we created for our blog based on the <a href=\"https:\/\/www.ssdnodes.com\/blog\/ghost-cms-tutorial-ubuntu\/\">Ghost CMS<\/a>.<\/p>\n<p>Docker volumes are supposed to be managed by the Docker daemon, and we don\u2019t want to fiddle with that. The strategy here is to get a copy of a volume as a compressed file in one of our regular directories, like <code>\/home\/$USER\/backups<\/code>. This compressed copy of the volume then acts as our backup.<\/p>\n<div class=\"cta-inline\"><\/div>\n<h2><a id=\"Running_a_Docker_volume_backup_8\"><\/a>Running a Docker volume backup<\/h2>\n<p>First, we spin up a temporary container, and we mount the backup folder and the target Docker volume to this container. When an ordinary directory like <code>~\/backups<\/code> is mounted inside a Docker container we call it a bind mount. Bind mounts, unlike Docker volumes, are not exclusively managed by Docker daemons, and hence we can use them as our backup folder.<\/p>\n<p>The <a href=\"https:\/\/docs.docker.com\/storage\/volumes\/#backup-restore-or-migrate-data-volumes\" target=\"_blank\" rel=\"noopener\">official Docker documentation<\/a> recommends this behavior, so you know it\u2019s safe to try on your containers and volumes. But before you do take a backup, ask yourself this question:<\/p>\n<p><strong>Is the data in this volume changing right now?<\/strong><\/p>\n<p>If you are running a small blog where you add the content, not your customers, then the answer is most certainly no. On the other hand, an e-commerce site can receive an order at any given moment, even when you are running the backup! If that\u2019s the case, then you need to stop the main container before running a backup.<\/p>\n<p>In our example, the main container is <code>ghost-site<\/code> which uses Docker volume <code>my-volume<\/code>, mounted at <code>\/var\/lib\/ghost\/content<\/code>, to store all of its data. We first stop the container.<\/p>\n<pre><code>$ docker stop ghost-site\n<\/code><\/pre>\n<p>Next, we spin up a temporary container with the volume and the backup folder mounted into it.<\/p>\n<pre><code>$ mkdir ~\/backup\n$ docker run --rm --volumes-from ghost-site -v ~\/backup:\/backup ubuntu bash -c \u201ccd \/var\/lib\/ghost\/content &amp;&amp; tar cvf \/backup\/ghost-site.tar .\u201d\n<\/code><\/pre>\n<p>Let\u2019s dissect the second command. <code>docker run<\/code> creates a new container, that much is obvious. After that:<\/p>\n<p><code>--rm<\/code> flag tells Docker to remove the container once it stops.<br \/>\n<code>--volumes-from ghost-site<\/code> : Mounts all the volumes from container <code>ghost-site<\/code> also to this temporary container. The mount points are the same as the original container.<br \/>\n<code>-v ~\/backup:\/backup<\/code>: Bind mount of the <code>~\/backup\/<\/code> directory from your host to the <code>\/backup<\/code> directory inside the temporary container.<br \/>\n<code>ubuntu<\/code>: Specifies that the container should run an Ubuntu image.<br \/>\n<code>bash -c \u201c...\u201d :<\/code> Backs up the contents of your website as a tarball inside <code>\/backup\/<\/code> inside the container. This is the same <code>~\/backup\/<\/code> directory on your host system where a new <code>ghost-site.tar<\/code> file would appear.<\/p>\n<h2><a id=\"Restoring_from_your_Docker_volume_backup_39\"><\/a>Restoring from your Docker volume backup<\/h2>\n<p>You don\u2019t have a backup until you have at least once tried to recover your original data from the backup. Let\u2019s not wait for a disaster to strike, and then figure out how to restore. Let\u2019s do a trial run when things are running fine.<\/p>\n<p>To begin with, I have the following dummy content on my website:<\/p>\n<p>Logging into the VPS, let\u2019s delete the container and volume, mimicking a disaster.<\/p>\n<pre><code>$ docker rm -f ghost-site\n$ docker volume rm my-volume\n<\/code><\/pre>\n<p>Now, the steps for recovery would involve:<\/p>\n<p>Creating a new volume<br \/>\nSpinning up a temporary container to recover from the tarball into this volume<br \/>\nMounting this volume to the new container<\/p>\n<pre><code>$ docker volume create my-volume-2\n$ docker run --rm -v my-volume-2:\/recover -v ~\/backup:\/backup ubuntu bash -c \u201ccd \/recover &amp;&amp; tar xvf \/backup\/ghost-site.tar\u201d\n$ docker run -d -v my-volume-2:\/var\/lib\/ghost\/content -p 80:2368 ghost:latest\n<\/code><\/pre>\n<p>If everything checks out, then you will be able to see the same dummy content, log in with the same email and password. In other words, your actions preserve the <strong>state<\/strong> of the application.<\/p>\n<h2>Tarballs are not backups!<\/h2>\n<p>We showed you how to create a tarball out of the contents of your volume, but that tarball still lives on the host. If you make a critical error on configuring your host, <a href=\"https:\/\/www.ssdnodes.com\/blog\/i-kill-every-vps-i-touch\/\">lock yourself out via iptables<\/a>, or otherwise force yourself to reinstall your operating system via the <a href=\"https:\/\/www.ssdnodes.com\/manage\/clientarea.php\">dashboard<\/a>, your backup is useless!<\/p>\n<p>Setting up a remote backup solution is the best way to ensure that, in the face of disaster, your data is with you. For small websites, a simple <code>scp<\/code> command would transfer all the content securely to your local system. Larger websites with a lot of content would require a bit more sophistication. The options vary from <code>rsync<\/code> to dedicated NFS servers running periodic backups. Pick one that serves your needs the best.<\/p>\n<p>But, for the meantime, enjoy the slight sense of readiness and preparedness that comes with knowing how to backup your Docker volumes in a pinch!<\/p>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You don\u2019t have a backup unless you\u2019ve restored your data from it. Let&#8217;s walk through how to create Docker backups of important volumes in 30 seconds.<\/p>\n","protected":false},"author":20,"featured_media":5566,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[18],"tags":[182],"class_list":["post-5547","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-docker"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/5547","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/comments?post=5547"}],"version-history":[{"count":5,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/5547\/revisions"}],"predecessor-version":[{"id":13498,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/5547\/revisions\/13498"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media\/5566"}],"wp:attachment":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media?parent=5547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/categories?post=5547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/tags?post=5547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}