{"id":35012,"date":"2025-12-20T16:33:07","date_gmt":"2025-12-20T09:33:07","guid":{"rendered":"https:\/\/dps.media\/?p=35012"},"modified":"2025-12-20T16:33:09","modified_gmt":"2025-12-20T09:33:09","slug":"guide-to-migrate-n8n-to-new-vps-docker-complete-safe","status":"publish","type":"post","link":"https:\/\/dps.media\/en\/guide-to-migrate-n8n-to-new-vps-docker-complete-safe\/","title":{"rendered":"Guide to migrate n8n to a new VPS (Docker) \u2013 Complete &amp; Safe"},"content":{"rendered":"<p>Migrating n8n from old VPS to new VPS sounds simple, but in reality, if you miss a few important steps, you may face serious errors such as losing credentials, webhook not working, or even the entire workflow disappearing.<\/p>\n\n\n\n<p>This article is written based on real-world experience when migrating n8n in a production environment, ensuring the safest and most complete process.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-1024x683.png\" alt=\"\" class=\"wp-image-35013\" title=\"\" srcset=\"https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-1024x683.png 1024w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-300x200.png 300w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-768x512.png 768w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-18x12.png 18w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-754x503.png 754w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7-356x237.png 356w, https:\/\/dps.media\/wp-content\/uploads\/2025\/12\/image-7.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Objective of the migration process<\/h2>\n\n\n\n<p>After completing the migration, the new VPS must ensure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Normal n8n login<\/li>\n\n\n\n<li>All workflows remain intact<\/li>\n\n\n\n<li>Credentials are not faulty (no red color displayed)<\/li>\n\n\n\n<li>Webhooks and Cron operate stably<\/li>\n\n\n\n<li>Execution history is preserved<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Components to be migrated (VERY IMPORTANT)<\/h2>\n\n\n\n<p>A complete n8n stack includes 4 mandatory parts:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Database<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PostgreSQL \/ MySQL \/ SQLite<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. n8n data directory<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Workflows<\/li>\n\n\n\n<li>Credentials<\/li>\n\n\n\n<li>Executions<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. Environment variables<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Especially <code>N8N_ENCRYPTION_KEY<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4. Domain &amp; webhook configuration<\/h3>\n\n\n\n<p><strong>Note:<\/strong> Missing even one of these four parts can cause serious errors in the entire system.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Prepare on old VPS (Source VPS)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1.1. Check if n8n is running<\/h3>\n\n\n\n<p>First, check how n8n is currently running:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker ps\ndocker compose ps<\/code><\/pre>\n\n\n\n<p>Identify the following information:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Type of database in use<\/li>\n\n\n\n<li>Where the volume is mounted (<code>~\/.n8n<\/code> or Docker volume)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">1.2. Backup database<\/h3>\n\n\n\n<p><strong>With PostgreSQL:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker exec -t postgres \\\n  pg_dump -U n8n n8n &gt; n8n.sql<\/code><\/pre>\n\n\n\n<p><strong>With MySQL:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker exec -t mysql \\\n  mysqldump -u n8n -p n8n &gt; n8n.sql<\/code><\/pre>\n\n\n\n<p><strong>With SQLite:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp ~\/.n8n\/database.sqlite n8n.sqlite<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">1.3. Backup n8n data<\/h3>\n\n\n\n<p><strong>If using bind mount:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tar -czvf n8n-data.tar.gz ~\/.n8n<\/code><\/pre>\n\n\n\n<p><strong>If using Docker volume:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker run --rm \\\n  -v n8n_data:\/data \\\n  -v $(pwd):\/backup \\\n  alpine tar czvf \/backup\/n8n-data.tar.gz \/data<\/code><\/pre>\n\n\n\n<p><strong>Important notes:<\/strong> This directory contains all encrypted credentials.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.4. Save environment variables (.env)<\/h3>\n\n\n\n<p>File <code>.env<\/code> must have the following variables:<\/p>\n\n\n\n<p>env<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>N8N_ENCRYPTION_KEY=\nDB_TYPE=\nDB_POSTGRESDB_DATABASE=\nDB_POSTGRESDB_USER=\nDB_POSTGRESDB_PASSWORD=\nN8N_HOST=\nWEBHOOK_URL=<\/code><\/pre>\n\n\n\n<p><strong>\u26a0\ufe0f WARNING:<\/strong> Loss <code>N8N_ENCRYPTION_KEY<\/code> means losing all credentials!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Prepare new VPS (Destination VPS)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2.1. Install Docker &amp; Docker Compose<\/h3>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt update &amp;&amp; apt upgrade -y\napt install docker.io docker-compose-plugin -y\nsystemctl enable docker --now<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2.2. Create project directory<\/h3>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p \/opt\/n8n\ncd \/opt\/n8n<\/code><\/pre>\n\n\n\n<p>Copy the following files into this directory:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>docker-compose.yml<\/code><\/li>\n\n\n\n<li><code>.env<\/code><\/li>\n\n\n\n<li>Backup file (<code>n8n.sql<\/code>, <code>n8n-data.tar.gz<\/code>)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Restore data on new VPS<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">3.1. Restore n8n data<\/h3>\n\n\n\n<p><strong>With bind mount:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tar -xzvf n8n-data.tar.gz -C \/<\/code><\/pre>\n\n\n\n<p><strong>With Docker volume:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker volume create n8n_data\n\ndocker run --rm \\\n  -v n8n_data:\/data \\\n  -v $(pwd):\/backup \\\n  alpine tar xzvf \/backup\/n8n-data.tar.gz -C \/<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3.2. Restore database<\/h3>\n\n\n\n<p><strong>PostgreSQL:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d postgres\ndocker exec -i postgres \\\n  psql -U n8n n8n &lt; n8n.sql<\/code><\/pre>\n\n\n\n<p><strong>MySQL:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d mysql\ndocker exec -i mysql \\\n  mysql -u n8n -p n8n &lt; n8n.sql<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Start n8n<\/h2>\n\n\n\n<p>Start n8n:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d<\/code><\/pre>\n\n\n\n<p>Monitor logs to check:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose logs -f n8n<\/code><\/pre>\n\n\n\n<p>When you see the following log line, n8n has started successfully:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Editor is now accessible via:<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Fix domain &amp; webhook (THE MOST EASILY FORGOTTEN STEP)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">5.1. Update .env file<\/h3>\n\n\n\n<p>env<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>N8N_HOST=n8n.domainmoi.com\nN8N_PROTOCOL=https\nWEBHOOK_URL=https:\/\/n8n.domainmoi.com\/<\/code><\/pre>\n\n\n\n<p>Then restart n8n:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose restart n8n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5.2. Test webhook<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open workflow with webhook<\/li>\n\n\n\n<li>Click <strong>Test URL<\/strong><\/li>\n\n\n\n<li>Test by calling with browser or curl<\/li>\n<\/ol>\n\n\n\n<p>If webhook errors, it is almost certainly due to <code>WEBHOOK_URL<\/code> not being configured correctly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 6: Post-migration checklist<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 Successfully logged into n8n<\/li>\n\n\n\n<li>\u2705 Workflow is still sufficient<\/li>\n\n\n\n<li>\u2705 Credentials not showing red<\/li>\n\n\n\n<li>\u2705 Webhook works normally<\/li>\n\n\n\n<li>\u2705 Cron workflow runs on schedule<\/li>\n\n\n\n<li>\u2705 Execution history is intact<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Common errors when migrating n8n<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Error<\/th><th>Cause<\/th><th>How to handle<\/th><\/tr><\/thead><tbody><tr><td>Credentials error<\/td><td>Lost encryption key<\/td><td>Reuse old key<\/td><\/tr><tr><td>Webhook returns 404<\/td><td>Wrong <code>WEBHOOK_URL<\/code><\/td><td>Set correct domain<\/td><\/tr><tr><td>No workflow found<\/td><td>DB not restored yet<\/td><td>Re-import SQL<\/td><\/tr><tr><td>n8n restarts continuously<\/td><td>Wrong DB env<\/td><td>Check again <code>.env<\/code><\/td><\/tr><tr><td>OAuth error<\/td><td>Change domain<\/td><td>Re-authorize<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Real-world experience<\/h2>\n\n\n\n<p><strong>Always stop n8n before backup:<\/strong><\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose stop n8n<\/code><\/pre>\n\n\n\n<p><strong>Some other notes:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Production environment should use PostgreSQL instead of SQLite<\/li>\n\n\n\n<li>Save file <code>.env<\/code> to password manager to avoid loss<\/li>\n\n\n\n<li>Take VPS snapshot before migrate to be able to rollback if needed<\/li>\n\n\n\n<li>If using queue mode, remember to migrate Redis as well<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Migrating n8n to a new VPS will be completely safe if you ensure all 4 pillars:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Database<\/strong> \u2013 Contains all workflows and executions<\/li>\n\n\n\n<li><strong>n8n data<\/strong> \u2013 Credentials and configuration<\/li>\n\n\n\n<li><strong>Encryption key<\/strong> \u2013 To decrypt credentials<\/li>\n\n\n\n<li><strong>Webhook<\/strong> \u2013 Ensure domain and URL are correct<\/li>\n<\/ol>\n\n\n\n<p>If you're having trouble during the migration process or need further support, don't hesitate to leave a comment below. Let me know:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Are you using PostgreSQL or MySQL?<\/li>\n\n\n\n<li>Single n8n or queue mode?<\/li>\n\n\n\n<li>Are you using reverse proxy (Nginx \/ Traefik \/ Cloudflare)?<\/li>\n<\/ul>\n\n\n\n<p>I will support and provide specific commands suitable for your stack!<\/p>\n<style>\r\n.lwrp.link-whisper-related-posts{\r\n            \r\n            margin-top: 40px;\nmargin-bottom: 30px;\r\n        }\r\n        .lwrp .lwrp-title{\r\n            \r\n            \r\n        }.lwrp .lwrp-description{\r\n            \r\n            \r\n\r\n        }\r\n        .lwrp .lwrp-list-container{\r\n        }\r\n        .lwrp .lwrp-list-multi-container{\r\n            display: flex;\r\n        }\r\n        .lwrp .lwrp-list-double{\r\n            width: 48%;\r\n        }\r\n        .lwrp .lwrp-list-triple{\r\n            width: 32%;\r\n        }\r\n        .lwrp .lwrp-list-row-container{\r\n            display: flex;\r\n            justify-content: space-between;\r\n        }\r\n        .lwrp .lwrp-list-row-container .lwrp-list-item{\r\n            width: calc(33% - 20px);\r\n        }\r\n        .lwrp .lwrp-list-item:not(.lwrp-no-posts-message-item){\r\n            \r\n            max-width: 150px;\r\n        }\r\n        .lwrp .lwrp-list-item img{\r\n            max-width: 100%;\r\n            height: auto;\r\n            object-fit: cover;\r\n            aspect-ratio: 1 \/ 1;\r\n        }\r\n        .lwrp .lwrp-list-item.lwrp-empty-list-item{\r\n            background: initial !important;\r\n        }\r\n        .lwrp .lwrp-list-item .lwrp-list-link .lwrp-list-link-title-text,\r\n        .lwrp .lwrp-list-item .lwrp-list-no-posts-message{\r\n            \r\n            \r\n            \r\n            \r\n        }@media screen and (max-width: 480px) {\r\n            .lwrp.link-whisper-related-posts{\r\n                \r\n                \r\n            }\r\n            .lwrp .lwrp-title{\r\n                \r\n                \r\n            }.lwrp .lwrp-description{\r\n                \r\n                \r\n            }\r\n            .lwrp .lwrp-list-multi-container{\r\n                flex-direction: column;\r\n            }\r\n            .lwrp .lwrp-list-multi-container ul.lwrp-list{\r\n                margin-top: 0px;\r\n                margin-bottom: 0px;\r\n                padding-top: 0px;\r\n                padding-bottom: 0px;\r\n            }\r\n            .lwrp .lwrp-list-double,\r\n            .lwrp .lwrp-list-triple{\r\n                width: 100%;\r\n            }\r\n            .lwrp .lwrp-list-row-container{\r\n                justify-content: initial;\r\n                flex-direction: column;\r\n            }\r\n            .lwrp .lwrp-list-row-container .lwrp-list-item{\r\n                width: 100%;\r\n            }\r\n            .lwrp .lwrp-list-item:not(.lwrp-no-posts-message-item){\r\n                \r\n                max-width: initial;\r\n            }\r\n            .lwrp .lwrp-list-item .lwrp-list-link .lwrp-list-link-title-text,\r\n            .lwrp .lwrp-list-item .lwrp-list-no-posts-message{\r\n                \r\n                \r\n                \r\n                \r\n            };\r\n        }<\/style>\r\n<div id=\"link-whisper-related-posts-widget\" class=\"link-whisper-related-posts lwrp\">\r\n            <div class=\"lwrp-title\">Related Posts<\/div>    \r\n        <div class=\"lwrp-list-container\">\r\n                                <div class=\"lwrp-list lwrp-list-row-container lwrp-list-double-row\">\r\n                <div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/tiktok-business-insights-how-to-read-and-analyze-data\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">TikTok Business Insights: How to read and analyze data<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/how-to-get-the-green-verification-badge-on-facebook-effectively\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">How to Effectively Get a Blue Checkmark on Facebook<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/comprehensive-marketing-package-service-in-ho-chi-minh-city\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Comprehensive Marketing Service \u2013 A Complete Development Solution for Businesses<\/span><\/a><\/div>                <\/div>\r\n                            <div class=\"lwrp-list lwrp-list-row-container lwrp-list-double-row\">\r\n                <div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/have-you-considered-the-top-15-emotion-analysis-tools-to-use-in-2024-yet\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Have you considered the top 15 emotion analysis tools to use in 2024 yet?<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/how-to-do-local-marketing-to-attract-local-customers\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Local Marketing: How to attract customers in the area?<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/bank-qr-code-create-account-qr-with-simple-qr-code-generator\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Bank QR Code \u2013 Create account QR with simple QR Code Generator<\/span><\/a><\/div>                <\/div>\r\n                <\/div>\r\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Migrating n8n from the old VPS to the new VPS sounds simple, but in reality, if you miss a few important steps, you may face serious errors such as losing credentials, webhooks not working, or even the entire workflow disappearing. This article is written based on [\u2026]<\/p>","protected":false},"author":1,"featured_media":35013,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,1205],"tags":[],"class_list":["post-35012","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","category-n8n-marketing"],"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\/35012","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=35012"}],"version-history":[{"count":1,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/35012\/revisions"}],"predecessor-version":[{"id":35014,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/35012\/revisions\/35014"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/media\/35013"}],"wp:attachment":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/media?parent=35012"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/categories?post=35012"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/tags?post=35012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}