{"id":35748,"date":"2026-01-11T17:30:43","date_gmt":"2026-01-11T10:30:43","guid":{"rendered":"https:\/\/dps.media\/giai-phong-du-lieu-huong-dan-di-doi-metabase-docker-volume-sang-vps-moi-2026\/"},"modified":"2026-01-11T17:33:43","modified_gmt":"2026-01-11T10:33:43","slug":"liberate-data-guide-to-migrating-metabase-docker-volume-to-new-vps-2026","status":"publish","type":"post","link":"https:\/\/dps.media\/en\/liberate-data-guide-to-migrating-metabase-docker-volume-to-new-vps-2026\/","title":{"rendered":"Data Liberation: Guide to Migrating Metabase (Docker Volume) to New VPS 2026"},"content":{"rendered":"<p class=\"wp-block-paragraph\">Have you ever moved a complex Supabase system, and now it's time to face the next challenge: <strong>Metabase<\/strong>. While Supabase stores data clearly in bind-mount folders, Metabase by default hides data deeply in <strong>Docker Volumes<\/strong> invisible ones. This makes backup or migration to a new VPS more \u201cchallenging\u201d for non-experts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this article, we will solve the problem: How to \u201cextract\u201d all Metabase data (Charts, Dashboard, Users) from a deeply hidden Docker Volume on the old VPS to a brand new VPS, and especially convert it to Folder (Bind Mount) format for easy management forever after.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problem: \u201cInvisible\u201d Data (Docker Volumes)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When you install Metabase with the command <code data-no-translation=\"\">docker run<\/code> or sample compose files online, data is often stored in Docker Volume (Managed Volume). You won't see it when <code data-no-translation=\"\">ls \/opt<\/code> or <code data-no-translation=\"\">ls \/home<\/code>. It lies deep in <code data-no-translation=\"\">\/var\/lib\/docker\/volumes\/...<\/code>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/dps.media\/wp-content\/uploads\/mcp\/2026\/01\/volume_to_folder_concept_1768127348760.jpg\" alt=\"Convert Docker Volume to Local Folder\" title=\"\"><figcaption>Strategy: Switch from closed Volume to open Folder<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">This causes difficulty when you want to backup (must use specific volume backup command) or edit config directly. Our strategy today is: <strong>Release the data<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: \u201cDetective\u201d Docker \u2013 Find Data &amp; Password<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before migrating, you must know where the data is and the key (password) to unlock it. Many cases after migration forget the old database password, leading to the new Metabase unable to read the data.<\/p>\n\n\n<p class=\"wp-block-paragraph\">At <strong>Old VPS<\/strong>, use the command <code data-no-translation=\"\">docker inspect<\/code> to inspect the information:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/dps.media\/wp-content\/uploads\/mcp\/2026\/01\/docker_inspect_secrets_1768127332437.jpg\" alt=\"Use Docker Inspect to Find Password\" title=\"\"><figcaption>Find the hidden Database password in environment variables<\/figcaption><\/figure>\n<\/div>\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\"># 1. T\u00ecm m\u1eadt kh\u1ea9u Database (Quan tr\u1ecdng nh\u1ea5t!)\ndocker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' metabase_container_name | grep MB_DB_PASS\n\n# 2. X\u00e1c \u0111\u1ecbnh ch\u00ednh x\u00e1c \u0111\u01b0\u1eddng d\u1eabn Volume\ndocker inspect -f '{{ json .Mounts }}' metabase_db_container_name<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Please note the password string (e.g.: <code data-no-translation=\"\">ExAmPlE_P@ssw0rd...<\/code>) and the source volume path (e.g.: <code data-no-translation=\"\">\/var\/lib\/docker\/volumes\/metabase_data\/_data<\/code>). We will need them in the next step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Rsync \u2013 Data Migration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After determining the \u201chome address\u201d of the data on the old VPS, we will use <code data-no-translation=\"\">rsync<\/code> to transfer it directly to the new VPS. On the new VPS, we will create a proper folder to receive it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On New VPS:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\">mkdir -p \/opt\/metabase\/pgdata<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On Old VPS (Run rsync command):<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\"># L\u01b0u \u00fd \u0111\u01b0\u1eddng d\u1eabn ngu\u1ed3n l\u1ea5y t\u1eeb b\u01b0\u1edbc 1\n# IP_VPS_MOI: Thay b\u1eb1ng IP server m\u1edbi\n\nrsync -avzP \/var\/lib\/docker\/volumes\/metabase_data\/_data\/ root@IP_VPS_MOI:\/opt\/metabase\/pgdata\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, all your precious data is safely in the folder <code data-no-translation=\"\">\/opt\/metabase\/pgdata<\/code> on the new server. It has become physical files that you can see, copy, and backup easily!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Build New House (Docker Compose Clean Setup)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Thay v\u00ec t\u00e1i s\u1eed d\u1ee5ng c\u1ea5u h\u00ecnh c\u0169 r\u1eafm r\u1ed1i, ch\u00fang ta s\u1ebd vi\u1ebft m\u1ed9t file <code data-no-translation=\"\">docker-compose.yml<\/code> clean, beautiful, and more standard. This file will connect the Metabase Application to the Database data we just transferred.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/dps.media\/wp-content\/uploads\/mcp\/2026\/01\/metabase_compose_structure_1768127364396.jpg\" alt=\"New Metabase Docker Compose Structure\" title=\"\"><figcaption>Connection model: App -&gt; Database -&gt; Local Folder<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Create file <code data-no-translation=\"\">\/opt\/metabase\/docker-compose.yml<\/code> with the following content (Remember to replace PASSWORD with the pass you found in Step 1):<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\">version: '3.9'\nservices:\n  metabase:\n    image: metabase\/metabase:latest\n    container_name: metabase\n    restart: unless-stopped\n    ports:\n      - \"3000:3000\"\n    environment:\n      MB_DB_TYPE: postgres\n      MB_DB_DBNAME: metabase\n      MB_DB_PORT: 5432\n      MB_DB_USER: metabase\n      MB_DB_PASS: YOUR_SECRET_PASSWORD_HERE\n      MB_DB_HOST: metabase-db\n    depends_on:\n      - metabase-db\n\n  metabase-db:\n    image: postgres:15\n    container_name: metabase-db\n    restart: unless-stopped\n    environment:\n      POSTGRES_USER: metabase\n      POSTGRES_DB: metabase\n      POSTGRES_PASSWORD: YOUR_SECRET_PASSWORD_HERE\n    volumes:\n      # K\u1ebeT N\u1ed0I QUAN TR\u1eccNG NH\u1ea4T:\n      # Mount folder d\u1eef li\u1ec7u v\u1eeba rsync v\u00e0o trong database\n      - .\/pgdata:\/var\/lib\/postgresql\/data<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then start it:<\/p>\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\">docker compose up -d<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Domain &amp; SSL Configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Using <strong>Nginx Proxy Manager<\/strong> (which you installed in the previous guide) to expose Metabase to the internet securely.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Domain:<\/strong> <code data-no-translation=\"\">data.your-domain.com<\/code><\/li>\n<li><strong>Forward IP:<\/strong> <code data-no-translation=\"\">172.17.0.1<\/code><\/li>\n<li><strong>Forward Port:<\/strong> <code data-no-translation=\"\">3000<\/code><\/li>\n<li><strong>SSL:<\/strong> Let\u2019s Encrypt (Force SSL)<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/dps.media\/wp-content\/uploads\/mcp\/2026\/01\/metabase_success_dashboard_1768127381275.jpg\" alt=\"Metabase Runs Successfully on New VPS\" title=\"\"><figcaption>The system works perfectly, dashboard data remains intact<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Vi\u1ec7c chuy\u1ec3n \u0111\u1ed5i t\u1eeb Docker Managed Volume sang Bind Mount (Folder) kh\u00f4ng ch\u1ec9 gi\u00fap b\u1ea1n migrate th\u00e0nh c\u00f4ng m\u00e0 c\u00f2n l\u00e0 m\u1ed9t b\u01b0\u1edbc n\u00e2ng c\u1ea5p l\u1edbn cho vi\u1ec7c qu\u1ea3n tr\u1ecb h\u1ec7 th\u1ed1ng. T\u1eeb nay v\u1ec1 sau, vi\u1ec7c backup d\u1eef li\u1ec7u Metabase ch\u1ec9 \u0111\u01a1n gi\u1ea3n l\u00e0 copy folder <code data-no-translation=\"\">\/opt\/metabase\/pgdata<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wishing you a powerful and stable Business Intelligence system in your new home!<\/p>","protected":false},"excerpt":{"rendered":"<p>Have you ever migrated a complex Supabase system, and now it's time to face the next challenge: Metabase. While Supabase stores data clearly in bind-mount folders, Metabase by default hides data thoroughly in invisible Docker Volumes. This makes [\u2026]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-35748","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"acf":[],"rankmath_keywords":{"primary":"","secondary":[""]},"yoast_keywords":{"primary":"","secondary":[]},"yoast_focuskw":"","rankmath_focuskw":"","seo_keywords":{"primary":"","secondary":[""]},"_links":{"self":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/35748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/comments?post=35748"}],"version-history":[{"count":0,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/35748\/revisions"}],"wp:attachment":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/media?parent=35748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/categories?post=35748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/tags?post=35748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}