Files
odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/index.html
T
2026-08-28 10:11:11 -03:00

2054 lines
90 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<link rel="preconnect" href="https://d3js.org" crossorigin>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="alternate icon" href="/favicon.ico">
<title>Migracion Hosting Odoo 2026 | Odoo Expertos</title>
<meta name="description" content="Guia definitiva para migrar tu Odoo a nuevo hosting en 2026. Backup de base de datos PostgreSQL, filestore, DNS, testing y errores - Migracion Hosting Odoo 2026 | ES">
<meta name="keywords" content="migracion odoo, migrar odoo hosting, backup odoo, exportar base datos odoo, filestore odoo, cambiar servidor odoo, mover odoo otro hosting, migracion odoo 2026">
<meta name="author" content="Dr. Equipo Odoo Expertos">
<meta name="robots" content="index, follow">
<meta name="language" content="es">
<link rel="canonical" href="https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/">
<!-- Hreflang -->
<link rel="alternate" hreflang="es" href="https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/" />
<link rel="alternate" hreflang="en" href="https://www.odoo-expertos.com/en/odoo-hosting/odoo-hosting-migration-2026/" />
<link rel="alternate" hreflang="de" href="https://www.odoo-expertos.com/de/odoo-hosting/odoo-hosting-migration-2026/" />
<link rel="alternate" hreflang="fr" href="https://www.odoo-expertos.com/fr/odoo-hosting/migration-hebergement-odoo-2026/" />
<link rel="alternate" hreflang="x-default" href="https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/" />
<!-- Open Graph -->
<meta property="og:title" content="Migracion Hosting Odoo 2026: Guia Completa Paso a Paso">
<meta property="og:description" content="Guia definitiva para migrar tu Odoo a nuevo hosting. Backup PostgreSQL, filestore, DNS y testing. Proceso completo con checklist.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/">
<meta property="og:image" content="https://www.odoo-expertos.com/images/migracion-hosting-odoo-2026.jpg">
<meta property="og:site_name" content="Odoo Expertos">
<meta property="og:locale" content="es_ES">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Migracion Hosting Odoo 2026: Guia Completa">
<meta name="twitter:description" content="Guia definitiva para migrar tu Odoo a nuevo hosting en 2026. Proceso paso a paso.">
<!-- Schema.org Article -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Migracion Hosting Odoo 2026: Guia Completa Paso a Paso",
"description": "Guia definitiva para migrar tu Odoo a nuevo hosting en 2026. Backup de base de datos PostgreSQL, filestore, DNS, testing y errores comunes.",
"author": {
"@type": "Person",
"name": "Dr. Equipo Odoo Expertos",
"url": "https://www.odoo-expertos.com/autor/maria-elena-rodriguez/",
"jobTitle": "Consultora Senior en Sistemas ERP"
},
"publisher": {
"@type": "Organization",
"name": "Odoo Expertos",
"logo": {
"@type": "ImageObject",
"url": "https://www.odoo-expertos.com/logo.png"
}
},
"datePublished": "2026-01-25",
"dateModified": "2026-01-25",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/"
}
}
</script>
<!-- HowTo Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Como Migrar Odoo a Nuevo Hosting",
"description": "Guia paso a paso para migrar una instalacion de Odoo a un nuevo servidor de hosting",
"totalTime": "PT4H",
"estimatedCost": {
"@type": "MonetaryAmount",
"currency": "EUR",
"value": "0"
},
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "Preparacion y Planificacion",
"text": "Documentar la configuracion actual, listar modulos instalados y dependencias, planificar ventana de mantenimiento"
},
{
"@type": "HowToStep",
"position": 2,
"name": "Backup de Base de Datos PostgreSQL",
"text": "Exportar la base de datos completa usando pg_dump con formato custom para maxima compatibilidad"
},
{
"@type": "HowToStep",
"position": 3,
"name": "Copia del Filestore",
"text": "Comprimir y transferir el directorio filestore que contiene todos los archivos adjuntos"
},
{
"@type": "HowToStep",
"position": 4,
"name": "Configuracion del Nuevo Servidor",
"text": "Instalar Odoo, PostgreSQL y dependencias en el nuevo hosting siguiendo los requisitos de version"
},
{
"@type": "HowToStep",
"position": 5,
"name": "Restauracion de Datos",
"text": "Restaurar la base de datos con pg_restore y copiar el filestore al directorio correcto"
},
{
"@type": "HowToStep",
"position": 6,
"name": "Cambio de DNS",
"text": "Actualizar los registros DNS para apuntar al nuevo servidor y esperar propagacion"
},
{
"@type": "HowToStep",
"position": 7,
"name": "Testing y Validacion",
"text": "Verificar funcionalidades criticas, probar modulos principales y validar integridad de datos"
}
]
}
</script>
<!-- FAQ Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Cuanto tiempo tarda migrar Odoo a otro hosting?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Una migracion tipica de Odoo tarda entre 2-6 horas dependiendo del tamano de la base de datos y filestore. Para bases de datos pequenas (menos de 5GB) puede completarse en 2 horas. Instalaciones grandes con muchos archivos pueden requerir 6-8 horas o mas."
}
},
{
"@type": "Question",
"name": "Puedo migrar Odoo sin tiempo de inactividad?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Es posible minimizar el downtime usando tecnicas de replicacion. La estrategia recomendada es: preparar el nuevo servidor, sincronizar datos, hacer un backup final rapido y cambiar DNS. El tiempo de inactividad minimo es de 15-30 minutos para el cambio final."
}
},
{
"@type": "Question",
"name": "Que archivos necesito para migrar Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Los componentes esenciales son: 1) Backup de base de datos PostgreSQL (pg_dump), 2) Directorio filestore completo (~/.local/share/Odoo/filestore/), 3) Archivo de configuracion odoo.conf, 4) Modulos personalizados (carpeta addons custom). Opcionalmente: certificados SSL y configuracion nginx."
}
},
{
"@type": "Question",
"name": "Como hago backup de la base de datos Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Usa el comando: pg_dump -Fc -h localhost -U odoo nombre_base_datos > backup.dump. El formato custom (-Fc) permite restauracion flexible. Alternativamente, desde la interfaz web de Odoo en /web/database/manager puedes exportar un archivo ZIP que incluye base de datos y filestore."
}
},
{
"@type": "Question",
"name": "Que hacer si la migracion de Odoo falla?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Mantener siempre el servidor original funcionando hasta confirmar que todo funciona. Los errores mas comunes son: versiones incompatibles de PostgreSQL, permisos incorrectos en filestore, modulos faltantes. Revisa los logs en /var/log/odoo/odoo.log para diagnosticar problemas especificos."
}
},
{
"@type": "Question",
"name": "Puedo migrar de Odoo Community a Enterprise durante el cambio de hosting?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Si, es posible pero requiere pasos adicionales. Primero migra normalmente, luego activa la licencia Enterprise y agrega los modulos enterprise. La base de datos Community es compatible con Enterprise. Recomendamos hacer esta actualizacion despues de confirmar que la migracion basica funciona."
}
},
{
"@type": "Question",
"name": "Como migro los modulos personalizados de Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Copia el directorio completo de modulos custom al nuevo servidor. Asegurate de que la ruta este configurada en addons_path del archivo odoo.conf. Despues de restaurar la base de datos, actualiza los modulos desde la interfaz de aplicaciones o con: odoo -u all -d nombre_base_datos."
}
},
{
"@type": "Question",
"name": "Es necesario actualizar la version de Odoo al migrar?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No es obligatorio, pero es una oportunidad ideal para actualizar. Si decides actualizar version (ej: de Odoo 17 a 18), hazlo DESPUES de confirmar que la migracion al nuevo hosting funciona con la version actual. Las actualizaciones de version requieren scripts de migracion especificos."
}
}
]
}
</script>
<!-- BreadcrumbList Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Inicio",
"item": "https://www.odoo-expertos.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Hosting Odoo",
"item": "https://www.odoo-expertos.com/odoo-hosting/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Migracion Hosting Odoo 2026",
"item": "https://www.odoo-expertos.com/odoo-hosting/migracion-hosting-odoo-2026/"
}
]
}
</script>
<link rel="stylesheet" href="/css/main.min.css">
<style>
.pillar-hero {
background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 50%, #1a1a1a 100%);
padding: 4rem 2rem;
text-align: center;
border-bottom: 3px solid #FF6B35;
position: relative;
overflow: hidden;
}
.pillar-hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(ellipse at center, rgba(255,107,53,0.15) 0%, transparent 70%);
pointer-events: none;
}
.pillar-hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
color: #FF6B35;
margin-bottom: 1rem;
line-height: 1.2;
position: relative;
}
.pillar-subtitle {
font-size: 1.3rem;
color: #b0b0b0;
max-width: 800px;
margin: 0 auto 2rem;
}
.pillar-meta {
display: flex;
justify-content: center;
gap: 2rem;
flex-wrap: wrap;
font-size: 0.9rem;
color: #888;
}
.pillar-meta span {
display: flex;
align-items: center;
gap: 0.5rem;
}
.quick-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1.5rem;
padding: 2rem;
background: #2a2a2a;
border-radius: 12px;
margin: 2rem 0;
}
.stat-card {
text-align: center;
padding: 1.5rem;
background: rgba(255,107,53,0.1);
border-radius: 8px;
border: 1px solid rgba(255,107,53,0.2);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
border-color: #FF6B35;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: #FF6B35;
display: block;
}
.stat-label {
color: #b0b0b0;
font-size: 0.9rem;
margin-top: 0.5rem;
}
.toc {
background: #2a2a2a;
border: 2px solid #FF6B35;
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
}
.toc h2 {
color: #FF6B35;
margin-bottom: 1rem;
font-size: 1.5rem;
}
.toc-list {
list-style: none;
padding: 0;
columns: 2;
column-gap: 2rem;
}
.toc-list li {
margin-bottom: 0.75rem;
break-inside: avoid;
}
.toc-list a {
color: #e0e0e0;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
transition: color 0.3s ease;
}
.toc-list a:hover {
color: #FF6B35;
}
.toc-list a::before {
content: '->';
color: #FF6B35;
}
.content-section {
margin: 3rem 0;
}
.content-section h2 {
color: #FF8A50;
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid rgba(255,107,53,0.3);
}
.content-section h3 {
color: #FFB74D;
margin: 2rem 0 1rem;
}
.chart-section {
margin: 3rem 0;
padding: 2rem;
background: #2a2a2a;
border-radius: 12px;
}
.chart-section h3 {
color: #FF8A50;
margin-bottom: 1rem;
}
.chart-container {
width: 100%;
min-height: 450px;
position: relative;
}
.step-card {
background: #2a2a2a;
border-radius: 12px;
padding: 2rem;
margin: 1.5rem 0;
border-left: 4px solid #FF6B35;
position: relative;
}
.step-card::before {
content: attr(data-step);
position: absolute;
top: -15px;
left: 20px;
background: #FF6B35;
color: #fff;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1.2rem;
}
.step-card h3 {
color: #FF8A50;
margin-bottom: 1rem;
padding-left: 2rem;
}
.step-card .duration {
display: inline-block;
background: rgba(255,107,53,0.2);
color: #FFB74D;
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.85rem;
margin-bottom: 1rem;
}
.code-block {
background: #1a1a1a;
border: 1px solid #3a3a3a;
border-radius: 8px;
padding: 1.25rem;
overflow-x: auto;
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
color: #e0e0e0;
}
.code-block code {
color: #4CAF50;
}
.code-block .comment {
color: #888;
}
.warning-box {
background: rgba(244, 67, 54, 0.1);
border-left: 4px solid #f44336;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.warning-box h4 {
color: #f44336;
margin-bottom: 0.5rem;
}
.success-box {
background: rgba(76, 175, 80, 0.1);
border-left: 4px solid #4CAF50;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.success-box h4 {
color: #4CAF50;
margin-bottom: 0.5rem;
}
.info-box {
background: rgba(33, 150, 243, 0.1);
border-left: 4px solid #2196F3;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.info-box h4 {
color: #2196F3;
margin-bottom: 0.5rem;
}
.checklist {
background: #2a2a2a;
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
}
.checklist h3 {
color: #FF6B35;
margin-bottom: 1.5rem;
}
.checklist-item {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 0.75rem 0;
border-bottom: 1px solid #3a3a3a;
}
.checklist-item:last-child {
border-bottom: none;
}
.checklist-item input[type="checkbox"] {
width: 20px;
height: 20px;
accent-color: #FF6B35;
margin-top: 2px;
}
.checklist-item label {
color: #b0b0b0;
cursor: pointer;
}
.checklist-item label:hover {
color: #e0e0e0;
}
.pitfall-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.pitfall-card {
background: #2a2a2a;
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(244, 67, 54, 0.3);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.pitfall-card:hover {
transform: translateY(-5px);
border-color: #f44336;
}
.pitfall-card h4 {
color: #f44336;
margin-bottom: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.pitfall-card h4::before {
content: '!';
background: #f44336;
color: #fff;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.9rem;
}
.pitfall-card p {
color: #b0b0b0;
font-size: 0.95rem;
margin-bottom: 1rem;
}
.pitfall-card .solution {
background: rgba(76, 175, 80, 0.1);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.9rem;
}
.pitfall-card .solution strong {
color: #4CAF50;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
background: #2a2a2a;
border-radius: 12px;
overflow: hidden;
}
.comparison-table th,
.comparison-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid #3a3a3a;
}
.comparison-table th {
background: rgba(255,107,53,0.2);
color: #FF6B35;
font-weight: 600;
}
.comparison-table tr:hover {
background: rgba(255,107,53,0.05);
}
.faq-section {
margin: 3rem 0;
}
.faq-item {
background: #2a2a2a;
border-radius: 8px;
margin-bottom: 1rem;
overflow: hidden;
}
.faq-question {
padding: 1.25rem;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
font-weight: 500;
transition: background 0.3s ease;
}
.faq-question:hover {
background: rgba(255,107,53,0.1);
}
.faq-question::after {
content: '+';
font-size: 1.5rem;
color: #FF6B35;
transition: transform 0.3s ease;
}
.faq-item.open .faq-question::after {
transform: rotate(45deg);
}
.faq-answer {
padding: 0 1.25rem;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
color: #b0b0b0;
}
.faq-item.open .faq-answer {
padding: 0 1.25rem 1.25rem;
max-height: 500px;
}
.cta-banner {
background: linear-gradient(135deg, rgba(255,107,53,0.2) 0%, rgba(255,138,80,0.1) 100%);
border: 2px solid rgba(255,107,53,0.5);
border-radius: 12px;
padding: 2.5rem;
text-align: center;
margin: 3rem 0;
}
.cta-banner h3 {
color: #FF6B35;
margin-bottom: 1rem;
font-size: 1.8rem;
}
.cta-banner p {
margin-bottom: 1.5rem;
color: #b0b0b0;
font-size: 1.1rem;
}
.cta-banner .cta-btn {
display: inline-block;
padding: 1rem 2.5rem;
background: #FF6B35;
color: #fff;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
font-size: 1.1rem;
transition: background 0.3s ease, transform 0.3s ease;
}
.cta-banner .cta-btn:hover {
background: #FF8A50;
transform: scale(1.05);
}
.related-articles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.related-card {
background: #2a2a2a;
border-radius: 8px;
overflow: hidden;
transition: transform 0.3s ease;
text-decoration: none;
}
.related-card:hover {
transform: translateY(-5px);
}
.related-card-image {
height: 150px;
background: linear-gradient(135deg, rgba(255,107,53,0.3), rgba(255,138,80,0.3));
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
}
.related-card-content {
padding: 1.25rem;
}
.related-card h4 {
color: #fff;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.related-card p {
color: #888;
font-size: 0.9rem;
margin: 0;
}
.d3-tooltip {
position: absolute;
background: rgba(0,0,0,0.95);
color: #fff;
padding: 0.75rem 1rem;
border-radius: 8px;
font-size: 0.9rem;
pointer-events: none;
z-index: 100;
max-width: 280px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
border: 1px solid rgba(255,107,53,0.3);
}
.d3-tooltip strong {
color: #FF6B35;
}
.highlight-box {
background: linear-gradient(135deg, rgba(255,107,53,0.1) 0%, rgba(255,138,80,0.05) 100%);
border-left: 4px solid #FF6B35;
padding: 1.5rem;
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.highlight-box h4 {
color: #FF6B35;
margin-bottom: 0.5rem;
}
.timeline-connector {
position: relative;
padding-left: 30px;
}
.timeline-connector::before {
content: '';
position: absolute;
left: 10px;
top: 0;
bottom: 0;
width: 2px;
background: linear-gradient(to bottom, #FF6B35 0%, #4CAF50 100%);
}
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 768px) {
.toc-list {
columns: 1;
}
.pillar-meta {
flex-direction: column;
gap: 0.5rem;
}
.chart-container {
min-height: 350px;
}
.pitfall-grid {
grid-template-columns: 1fr;
}
.step-card::before {
top: -10px;
left: 15px;
width: 30px;
height: 30px;
font-size: 1rem;
}
}
</style>
</head>
<body>
<div id="header"><header class="site-header"><nav class="navbar"><div class="container"><div class="nav-brand"><a href="/" class="logo"><span class="logo-text">Odoo Expertos</span></a></div><button class="nav-toggle" aria-label="Toggle navigation"><span></span><span></span><span></span></button><div class="nav-menu"><ul class="nav-list"><li><a href="/">Inicio</a></li><li><a href="/odoo/">Odoo</a></li><li><a href="/odoo-ia/">Odoo IA</a></li><li><a href="/odoo-hosting/">Hosting Odoo</a></li><li><a href="/mapa-del-sitio/">Mapa del Sitio</a></li></ul></div></div></nav></header></div><button class="nav-toggle" aria-label="Toggle navigation"><span></span><span></span><span></span></button><div class="nav-menu"><ul class="nav-list"><li><a href="/">Inicio</a></li><li><a href="/odoo/">Odoo</a></li><li><a href="/odoo-ia/">Odoo IA</a></li><li><a href="/odoo-hosting/">Hosting Odoo</a></li><li><a href="/mapa-del-sitio/">Mapa del Sitio</a></li></ul></div></div></nav></header></div>
<!-- Breadcrumbs -->
<nav class="breadcrumbs">
<div class="container">
<ol class="breadcrumb-list" itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/"><span itemprop="name">Inicio</span></a>
<span itemprop="position" style="display:none">1</span>
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/odoo-hosting/"><span itemprop="name">Hosting Odoo</span></a>
<span itemprop="position" style="display:none">2</span>
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<span itemprop="name">Migracion Hosting Odoo 2026</span>
<span itemprop="position" style="display:none">3</span>
</li>
</ol>
</div>
</nav>
<!-- Hero Section -->
<section class="pillar-hero">
<div class="container">
<h1>Migracion Hosting Odoo 2026: Guia Completa Paso a Paso</h1>
<p class="pillar-subtitle">Aprende a migrar tu instalacion de Odoo a un nuevo servidor de forma segura. Guia detallada con backup de base de datos PostgreSQL, filestore, configuracion DNS, testing y solucion de errores comunes.</p>
<div class="pillar-meta">
<span>Publicado: 25 enero 2026</span>
<span>Actualizado: 25 enero 2026</span>
<span>30 min lectura</span>
<span>Dr. Equipo Odoo Expertos</span>
</div>
</div>
</section>
<main class="container">
<!-- Quick Stats -->
<section class="quick-stats fade-in">
<div class="stat-card">
<span class="stat-number">7</span>
<span class="stat-label">Pasos del Proceso</span>
</div>
<div class="stat-card">
<span class="stat-number">2-6h</span>
<span class="stat-label">Tiempo Estimado</span>
</div>
<div class="stat-card">
<span class="stat-number">99%</span>
<span class="stat-label">Tasa de Exito</span>
</div>
<div class="stat-card">
<span class="stat-number">15min</span>
<span class="stat-label">Downtime Minimo</span>
</div>
<div class="stat-card">
<span class="stat-number">8+</span>
<span class="stat-label">Errores Comunes</span>
</div>
</section>
<!-- Table of Contents -->
<nav class="toc fade-in">
<h2>Contenido de esta Guia</h2>
<ol class="toc-list">
<li><a href="#introduccion">Introduccion y Planificacion</a></li>
<li><a href="#workflow-diagram">Diagrama del Flujo de Migracion</a></li>
<li><a href="#preparacion">Paso 1: Preparacion del Entorno</a></li>
<li><a href="#backup-database">Paso 2: Backup Base de Datos PostgreSQL</a></li>
<li><a href="#filestore">Paso 3: Copia del Filestore</a></li>
<li><a href="#nuevo-servidor">Paso 4: Configuracion Nuevo Servidor</a></li>
<li><a href="#restauracion">Paso 5: Restauracion de Datos</a></li>
<li><a href="#dns">Paso 6: Cambio de DNS</a></li>
<li><a href="#testing">Paso 7: Testing y Validacion</a></li>
<li><a href="#errores-comunes">Errores Comunes y Soluciones</a></li>
<li><a href="#checklist">Checklist de Migracion</a></li>
<li><a href="#faq">Preguntas Frecuentes (8+)</a></li>
</ol>
</nav>
<!-- Introduction -->
<section id="introduccion" class="content-section fade-in">
<h2>Introduccion: Por Que Migrar tu Odoo a Otro Hosting</h2>
<p>La migracion de Odoo a un nuevo hosting es una de las tareas mas criticas que puede enfrentar un administrador de sistemas ERP. Ya sea por mejor rendimiento, costes mas bajos, mejor soporte o simplemente porque tu proveedor actual no cumple con tus expectativas, cambiar de hosting requiere una planificacion meticulosa para evitar perdida de datos y minimizar el tiempo de inactividad.</p>
<div class="highlight-box">
<h4>Objetivo de Esta Guia</h4>
<p>Al finalizar esta guia, seras capaz de realizar una migracion completa de Odoo con <strong>menos de 30 minutos de downtime</strong>, manteniendo la integridad total de tus datos, archivos y configuraciones. Cubriremos desde el backup inicial hasta la validacion final post-migracion.</p>
</div>
<h3>Razones Comunes para Migrar</h3>
<ul>
<li><strong>Rendimiento insuficiente:</strong> El servidor actual no soporta la carga de usuarios o procesos</li>
<li><strong>Costes elevados:</strong> Existen alternativas mas economicas con igual o mejor servicio</li>
<li><strong>Mejor soporte:</strong> Necesitas soporte en espanol o asistencia tecnica especializada</li>
<li><strong>Cumplimiento normativo:</strong> Requisitos de GDPR o localizacion de datos en Europa</li>
<li><strong>Escalabilidad:</strong> El proveedor actual no permite crecer segun tus necesidades</li>
<li><strong>Funcionalidades:</strong> El nuevo hosting ofrece backups automaticos, IA, o integraciones</li>
</ul>
<h3>Componentes de una Instalacion Odoo</h3>
<p>Antes de iniciar la migracion, es fundamental entender que componentes forman una instalacion completa de Odoo:</p>
<table class="comparison-table">
<thead>
<tr>
<th>Componente</th>
<th>Ubicacion Tipica</th>
<th>Descripcion</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Base de datos PostgreSQL</strong></td>
<td>/var/lib/postgresql/</td>
<td>Todos los datos de negocio: clientes, facturas, inventario, etc.</td>
</tr>
<tr>
<td><strong>Filestore</strong></td>
<td>~/.local/share/Odoo/filestore/</td>
<td>Archivos adjuntos: PDFs, imagenes, documentos subidos</td>
</tr>
<tr>
<td><strong>Codigo Odoo</strong></td>
<td>/opt/odoo/ o /usr/lib/python3/</td>
<td>El framework Odoo y modulos base</td>
</tr>
<tr>
<td><strong>Modulos custom</strong></td>
<td>/opt/odoo/custom-addons/</td>
<td>Modulos personalizados y de terceros</td>
</tr>
<tr>
<td><strong>Configuracion</strong></td>
<td>/etc/odoo/odoo.conf</td>
<td>Parametros del servidor, rutas, workers</td>
</tr>
<tr>
<td><strong>Certificados SSL</strong></td>
<td>/etc/letsencrypt/ o /etc/ssl/</td>
<td>Certificados HTTPS para conexion segura</td>
</tr>
</tbody>
</table>
<div class="info-box">
<h4>Nota Importante</h4>
<p>Los dos componentes mas criticos son la <strong>base de datos PostgreSQL</strong> y el <strong>filestore</strong>. Sin estos, perderas todos tus datos de negocio. El codigo de Odoo puede reinstalarse, pero los datos son irreemplazables sin un backup adecuado.</p>
</div>
</section>
<!-- D3.js Workflow Diagram -->
<section class="chart-section fade-in">
<h3 id="workflow-diagram">Diagrama del Flujo de Migracion</h3>
<p>Este diagrama interactivo muestra el flujo completo del proceso de migracion. Cada nodo representa una fase critica. Pasa el cursor sobre cada fase para ver detalles y tiempo estimado.</p>
<div class="chart-container" id="workflow-chart"></div>
</section>
<!-- Step 1: Preparation -->
<section id="preparacion" class="content-section fade-in">
<h2>Paso 1: Preparacion del Entorno</h2>
<div class="step-card" data-step="1">
<h3>Documentacion y Planificacion</h3>
<span class="duration">30-60 minutos</span>
<p>Antes de tocar cualquier archivo, documenta tu instalacion actual. Esto te salvara de problemas durante la restauracion.</p>
<h4>1.1 Documentar Version de Odoo</h4>
<div class="code-block">
<code># Verificar version de Odoo instalada</code><br>
<code>odoo --version</code><br><br>
<code># O desde la interfaz web, ir a:</code><br>
<code># Configuracion -> Opciones Generales -> Sobre Odoo</code>
</div>
<h4>1.2 Listar Modulos Instalados</h4>
<div class="code-block">
<code># Desde PostgreSQL, listar modulos activos</code><br>
<code>psql -U odoo -d tu_base_datos -c "SELECT name, state FROM ir_module_module WHERE state = 'installed';"</code><br><br>
<code># Guardar en archivo</code><br>
<code>psql -U odoo -d tu_base_datos -c "SELECT name FROM ir_module_module WHERE state = 'installed';" > modulos_instalados.txt</code>
</div>
<h4>1.3 Documentar Configuracion Actual</h4>
<div class="code-block">
<code># Copiar archivo de configuracion</code><br>
<code>cp /etc/odoo/odoo.conf ~/backup_config/odoo.conf.backup</code><br><br>
<code># Documentar configuracion nginx si aplica</code><br>
<code>cp /etc/nginx/sites-available/odoo ~/backup_config/nginx_odoo.backup</code>
</div>
<h4>1.4 Verificar Espacio en Disco</h4>
<div class="code-block">
<code># Tamano de la base de datos</code><br>
<code>psql -U odoo -d tu_base_datos -c "SELECT pg_size_pretty(pg_database_size('tu_base_datos'));"</code><br><br>
<code># Tamano del filestore</code><br>
<code>du -sh ~/.local/share/Odoo/filestore/tu_base_datos/</code>
</div>
<div class="warning-box">
<h4>Precaucion</h4>
<p>Asegurate de tener al menos <strong>3 veces el espacio</strong> del tamano total de datos en el nuevo servidor. Necesitaras espacio para: datos originales, archivos comprimidos temporales, y margen de seguridad.</p>
</div>
</div>
</section>
<!-- Step 2: Database Backup -->
<section id="backup-database" class="content-section fade-in">
<h2>Paso 2: Backup de Base de Datos PostgreSQL</h2>
<div class="step-card" data-step="2">
<h3>Exportacion Completa de la Base de Datos</h3>
<span class="duration">15-60 minutos (segun tamano)</span>
<p>El backup de PostgreSQL es el paso mas critico. Usaremos <code>pg_dump</code> con formato custom para maxima flexibilidad.</p>
<h4>2.1 Metodo Recomendado: pg_dump con formato Custom</h4>
<div class="code-block">
<code># Backup completo con formato custom (recomendado)</code><br>
<code>pg_dump -Fc -h localhost -U odoo -d tu_base_datos -f backup_$(date +%Y%m%d_%H%M%S).dump</code><br><br>
<code># Explicacion de parametros:</code><br>
<span class="comment"># -Fc: Formato custom (comprimido, restauracion flexible)</span><br>
<span class="comment"># -h localhost: Host de PostgreSQL</span><br>
<span class="comment"># -U odoo: Usuario de PostgreSQL</span><br>
<span class="comment"># -d tu_base_datos: Nombre de la base de datos</span><br>
<span class="comment"># -f: Archivo de salida con fecha</span>
</div>
<h4>2.2 Metodo Alternativo: Backup desde Interfaz Web</h4>
<p>Si prefieres usar la interfaz grafica de Odoo:</p>
<ol>
<li>Accede a <code>https://tu-servidor/web/database/manager</code></li>
<li>Ingresa la master password (configurada en odoo.conf)</li>
<li>Haz clic en "Backup" junto a tu base de datos</li>
<li>Selecciona formato "zip" para incluir filestore automaticamente</li>
<li>Descarga el archivo generado</li>
</ol>
<div class="info-box">
<h4>Diferencia entre Formatos</h4>
<p><strong>Formato Custom (-Fc):</strong> Mas rapido, permite restauracion parcial de tablas, compresion optima. Ideal para bases grandes.<br>
<strong>Formato ZIP (web):</strong> Incluye filestore automaticamente, mas facil de usar, pero mas lento y archivos mas grandes.</p>
</div>
<h4>2.3 Verificar Integridad del Backup</h4>
<div class="code-block">
<code># Verificar que el archivo no esta corrupto</code><br>
<code>pg_restore -l backup_20260125_120000.dump | head -20</code><br><br>
<code># Deberia mostrar lista de objetos en el backup</code><br>
<code># Si hay error, el archivo esta corrupto - repetir backup</code>
</div>
<h4>2.4 Backup durante Horario de Baja Actividad</h4>
<p>Para garantizar consistencia de datos, programa el backup final durante horario de minima actividad. Considera:</p>
<ul>
<li>Notificar a usuarios sobre ventana de mantenimiento</li>
<li>Detener trabajos programados (cron jobs de Odoo)</li>
<li>Considerar poner Odoo en modo mantenimiento</li>
</ul>
<div class="code-block">
<code># Opcion: Detener Odoo durante backup final para maxima consistencia</code><br>
<code>sudo systemctl stop odoo</code><br>
<code>pg_dump -Fc -U odoo -d tu_base_datos -f backup_final.dump</code><br>
<code>sudo systemctl start odoo</code>
</div>
</div>
</section>
<!-- Step 3: Filestore -->
<section id="filestore" class="content-section fade-in">
<h2>Paso 3: Copia del Filestore</h2>
<div class="step-card" data-step="3">
<h3>Transferencia de Archivos Adjuntos</h3>
<span class="duration">15-120 minutos (segun tamano)</span>
<p>El filestore contiene todos los archivos subidos a Odoo: facturas PDF, imagenes de productos, documentos adjuntos a registros, etc.</p>
<h4>3.1 Localizar el Filestore</h4>
<div class="code-block">
<code># Ubicacion por defecto (usuario odoo)</code><br>
<code>ls -la ~/.local/share/Odoo/filestore/</code><br><br>
<code># O verificar en odoo.conf</code><br>
<code>grep data_dir /etc/odoo/odoo.conf</code><br><br>
<code># Ejemplo de salida:</code><br>
<span class="comment"># data_dir = /var/lib/odoo/.local/share/Odoo</span>
</div>
<h4>3.2 Comprimir el Filestore</h4>
<div class="code-block">
<code># Comprimir con tar y gzip para transferencia eficiente</code><br>
<code>cd ~/.local/share/Odoo/filestore/</code><br>
<code>tar -czvf ~/filestore_backup_$(date +%Y%m%d).tar.gz tu_base_datos/</code><br><br>
<code># Verificar tamano</code><br>
<code>ls -lh ~/filestore_backup_*.tar.gz</code>
</div>
<h4>3.3 Transferir al Nuevo Servidor</h4>
<div class="code-block">
<code># Opcion 1: SCP (mas simple)</code><br>
<code>scp ~/filestore_backup_20260125.tar.gz usuario@nuevo-servidor:/tmp/</code><br>
<code>scp ~/backup_final.dump usuario@nuevo-servidor:/tmp/</code><br><br>
<code># Opcion 2: rsync (mejor para archivos grandes, soporta reanudacion)</code><br>
<code>rsync -avz --progress ~/filestore_backup_20260125.tar.gz usuario@nuevo-servidor:/tmp/</code><br><br>
<code># Opcion 3: Para conexiones lentas, usar screen/tmux para evitar cortes</code><br>
<code>screen -S transfer</code><br>
<code>rsync -avz --progress --partial ~/filestore_backup*.tar.gz usuario@nuevo-servidor:/tmp/</code>
</div>
<div class="success-box">
<h4>Consejo Pro</h4>
<p>Si el filestore es muy grande (>10GB), considera usar <strong>rsync con compresion</strong> y la opcion <code>--partial</code> para poder reanudar transferencias interrumpidas. Tambien puedes sincronizar en paralelo mientras el servidor original sigue funcionando.</p>
</div>
<h4>3.4 Verificar Transferencia</h4>
<div class="code-block">
<code># En el nuevo servidor, verificar checksum</code><br>
<code># En servidor origen:</code><br>
<code>md5sum ~/filestore_backup_20260125.tar.gz</code><br><br>
<code># En servidor destino:</code><br>
<code>md5sum /tmp/filestore_backup_20260125.tar.gz</code><br><br>
<code># Los hashes deben coincidir exactamente</code>
</div>
</div>
</section>
<!-- Step 4: New Server Setup -->
<section id="nuevo-servidor" class="content-section fade-in">
<h2>Paso 4: Configuracion del Nuevo Servidor</h2>
<div class="step-card" data-step="4">
<h3>Preparar el Entorno de Destino</h3>
<span class="duration">30-90 minutos</span>
<p>El nuevo servidor debe tener instalados todos los componentes necesarios antes de restaurar los datos.</p>
<h4>4.1 Requisitos del Sistema (Odoo 18)</h4>
<table class="comparison-table">
<tr><th>Componente</th><th>Version Requerida</th></tr>
<tr><td>Sistema Operativo</td><td>Ubuntu 22.04/24.04 LTS o Debian 12</td></tr>
<tr><td>Python</td><td>3.10 o superior</td></tr>
<tr><td>PostgreSQL</td><td>14, 15 o 16 (recomendado 16)</td></tr>
<tr><td>Node.js</td><td>18 LTS o superior</td></tr>
<tr><td>wkhtmltopdf</td><td>0.12.6 con patched qt</td></tr>
</table>
<h4>4.2 Instalacion de Dependencias</h4>
<div class="code-block">
<code># Actualizar sistema</code><br>
<code>sudo apt update && sudo apt upgrade -y</code><br><br>
<code># Instalar PostgreSQL 16</code><br>
<code>sudo apt install -y postgresql-16 postgresql-client-16</code><br><br>
<code># Instalar dependencias Python</code><br>
<code>sudo apt install -y python3-pip python3-dev python3-venv \</code><br>
<code> libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \</code><br>
<code> libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev \</code><br>
<code> libfreetype6-dev liblcms2-dev libwebp-dev libharfbuzz-dev \</code><br>
<code> libfribidi-dev libxcb1-dev libpq-dev</code><br><br>
<code># Instalar Node.js 18</code><br>
<code>curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -</code><br>
<code>sudo apt install -y nodejs</code><br><br>
<code># Instalar wkhtmltopdf</code><br>
<code>wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb</code><br>
<code>sudo apt install -y ./wkhtmltox_0.12.6.1-3.jammy_amd64.deb</code>
</div>
<h4>4.3 Instalar Odoo</h4>
<div class="code-block">
<code># Crear usuario odoo</code><br>
<code>sudo useradd -m -d /opt/odoo -U -r -s /bin/bash odoo</code><br><br>
<code># Clonar Odoo (misma version que el origen)</code><br>
<code>sudo su - odoo</code><br>
<code>git clone https://www.github.com/odoo/odoo --depth 1 --branch 18.0 /opt/odoo/odoo</code><br><br>
<code># Crear entorno virtual e instalar dependencias</code><br>
<code>python3 -m venv /opt/odoo/venv</code><br>
<code>source /opt/odoo/venv/bin/activate</code><br>
<code>pip install wheel</code><br>
<code>pip install -r /opt/odoo/odoo/requirements.txt</code>
</div>
<h4>4.4 Configurar PostgreSQL</h4>
<div class="code-block">
<code># Crear usuario PostgreSQL para Odoo</code><br>
<code>sudo -u postgres createuser -s odoo</code><br><br>
<code># Opcional: Establecer password</code><br>
<code>sudo -u postgres psql -c "ALTER USER odoo WITH PASSWORD 'tu_password_seguro';"</code>
</div>
<div class="warning-box">
<h4>Version de PostgreSQL</h4>
<p>Es importante que la version de PostgreSQL en el nuevo servidor sea <strong>igual o superior</strong> a la del servidor origen. No puedes restaurar un backup de PostgreSQL 16 en un servidor con PostgreSQL 14. Verifica versiones antes de continuar.</p>
</div>
</div>
</section>
<!-- Step 5: Restore -->
<section id="restauracion" class="content-section fade-in">
<h2>Paso 5: Restauracion de Datos</h2>
<div class="step-card" data-step="5">
<h3>Importar Base de Datos y Filestore</h3>
<span class="duration">20-90 minutos</span>
<h4>5.1 Crear Base de Datos Vacia</h4>
<div class="code-block">
<code># Crear base de datos con mismo nombre que el origen</code><br>
<code>sudo -u postgres createdb -O odoo tu_base_datos</code><br><br>
<code># O si usas password:</code><br>
<code>createdb -h localhost -U odoo tu_base_datos</code>
</div>
<h4>5.2 Restaurar Base de Datos</h4>
<div class="code-block">
<code># Restaurar desde formato custom</code><br>
<code>pg_restore -h localhost -U odoo -d tu_base_datos -v /tmp/backup_final.dump</code><br><br>
<code># Si hay errores de permisos, usar --no-owner</code><br>
<code>pg_restore -h localhost -U odoo -d tu_base_datos -v --no-owner /tmp/backup_final.dump</code><br><br>
<code># Para ver progreso en bases grandes:</code><br>
<code>pg_restore -h localhost -U odoo -d tu_base_datos -v /tmp/backup_final.dump 2>&1 | tee restore.log</code>
</div>
<h4>5.3 Restaurar Filestore</h4>
<div class="code-block">
<code># Crear directorio de filestore</code><br>
<code>sudo mkdir -p /opt/odoo/.local/share/Odoo/filestore/</code><br><br>
<code># Descomprimir filestore</code><br>
<code>cd /opt/odoo/.local/share/Odoo/filestore/</code><br>
<code>sudo tar -xzvf /tmp/filestore_backup_20260125.tar.gz</code><br><br>
<code># Ajustar permisos</code><br>
<code>sudo chown -R odoo:odoo /opt/odoo/.local/</code><br>
<code>sudo chmod -R 755 /opt/odoo/.local/share/Odoo/filestore/</code>
</div>
<h4>5.4 Copiar Modulos Personalizados</h4>
<div class="code-block">
<code># Crear directorio para modulos custom</code><br>
<code>sudo mkdir -p /opt/odoo/custom-addons</code><br><br>
<code># Copiar desde backup o transferir directamente</code><br>
<code>scp -r usuario@servidor-origen:/opt/odoo/custom-addons/* /opt/odoo/custom-addons/</code><br><br>
<code># Ajustar permisos</code><br>
<code>sudo chown -R odoo:odoo /opt/odoo/custom-addons</code>
</div>
<h4>5.5 Configurar odoo.conf</h4>
<div class="code-block">
<code># Crear archivo de configuracion</code><br>
<code>sudo nano /etc/odoo/odoo.conf</code><br><br>
<code>[options]</code><br>
<code>admin_passwd = tu_master_password_segura</code><br>
<code>db_host = localhost</code><br>
<code>db_port = 5432</code><br>
<code>db_user = odoo</code><br>
<code>db_password = tu_password_postgres</code><br>
<code>addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons</code><br>
<code>data_dir = /opt/odoo/.local/share/Odoo</code><br>
<code>logfile = /var/log/odoo/odoo.log</code><br>
<code>workers = 4</code><br>
<code>max_cron_threads = 2</code>
</div>
<div class="success-box">
<h4>Verificacion Rapida</h4>
<p>Antes de continuar con DNS, prueba que Odoo arranca correctamente:</p>
<code>sudo -u odoo /opt/odoo/venv/bin/python /opt/odoo/odoo/odoo-bin -c /etc/odoo/odoo.conf</code>
<p>Accede a <code>http://IP-NUEVO-SERVIDOR:8069</code> y verifica que ves la pantalla de login.</p>
</div>
</div>
</section>
<!-- Step 6: DNS -->
<section id="dns" class="content-section fade-in">
<h2>Paso 6: Cambio de DNS</h2>
<div class="step-card" data-step="6">
<h3>Redirigir el Dominio al Nuevo Servidor</h3>
<span class="duration">15-60 minutos (propagacion: hasta 48h)</span>
<p>Una vez verificado que Odoo funciona en el nuevo servidor, es momento de redirigir el trafico.</p>
<h4>6.1 Configurar Nginx como Proxy Inverso</h4>
<div class="code-block">
<code># Instalar nginx</code><br>
<code>sudo apt install -y nginx</code><br><br>
<code># Crear configuracion para Odoo</code><br>
<code>sudo nano /etc/nginx/sites-available/odoo</code>
</div>
<div class="code-block">
<code># Contenido del archivo nginx:</code><br><br>
<code>upstream odoo {</code><br>
<code> server 127.0.0.1:8069;</code><br>
<code>}</code><br><br>
<code>upstream odoochat {</code><br>
<code> server 127.0.0.1:8072;</code><br>
<code>}</code><br><br>
<code>server {</code><br>
<code> listen 80;</code><br>
<code> server_name tu-dominio.com www.tu-dominio.com;</code><br><br>
<code> proxy_read_timeout 720s;</code><br>
<code> proxy_connect_timeout 720s;</code><br>
<code> proxy_send_timeout 720s;</code><br><br>
<code> location / {</code><br>
<code> proxy_pass http://odoo;</code><br>
<code> proxy_set_header Host $host;</code><br>
<code> proxy_set_header X-Real-IP $remote_addr;</code><br>
<code> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</code><br>
<code> proxy_set_header X-Forwarded-Proto $scheme;</code><br>
<code> }</code><br><br>
<code> location /longpolling {</code><br>
<code> proxy_pass http://odoochat;</code><br>
<code> }</code><br>
<code>}</code>
</div>
<div class="code-block">
<code># Activar sitio y reiniciar nginx</code><br>
<code>sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/</code><br>
<code>sudo nginx -t</code><br>
<code>sudo systemctl restart nginx</code>
</div>
<h4>6.2 Configurar SSL con Let's Encrypt</h4>
<div class="code-block">
<code># Instalar certbot</code><br>
<code>sudo apt install -y certbot python3-certbot-nginx</code><br><br>
<code># Obtener certificado SSL</code><br>
<code>sudo certbot --nginx -d tu-dominio.com -d www.tu-dominio.com</code><br><br>
<code># Verificar renovacion automatica</code><br>
<code>sudo certbot renew --dry-run</code>
</div>
<h4>6.3 Actualizar Registros DNS</h4>
<p>En el panel de tu registrador de dominio (GoDaddy, Cloudflare, Namecheap, etc.):</p>
<ol>
<li>Localiza los registros A para tu dominio</li>
<li>Cambia la IP del registro A principal a la IP del nuevo servidor</li>
<li>Si usas www, actualiza tambien ese registro</li>
<li>Reduce el TTL a 300 segundos antes del cambio para acelerar propagacion</li>
</ol>
<table class="comparison-table">
<thead>
<tr>
<th>Tipo</th>
<th>Nombre</th>
<th>Valor (antes)</th>
<th>Valor (despues)</th>
<th>TTL</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>@</td>
<td>123.45.67.89</td>
<td>98.76.54.32</td>
<td>300</td>
</tr>
<tr>
<td>A</td>
<td>www</td>
<td>123.45.67.89</td>
<td>98.76.54.32</td>
<td>300</td>
</tr>
</tbody>
</table>
<div class="info-box">
<h4>Tiempo de Propagacion DNS</h4>
<p>Los cambios DNS pueden tardar entre 15 minutos y 48 horas en propagarse globalmente. Durante este periodo, algunos usuarios veran el servidor antiguo y otros el nuevo. <strong>Mantener ambos servidores activos</strong> durante las primeras 48-72 horas.</p>
</div>
</div>
</section>
<!-- Step 7: Testing -->
<section id="testing" class="content-section fade-in">
<h2>Paso 7: Testing y Validacion</h2>
<div class="step-card" data-step="7">
<h3>Verificar Funcionamiento Completo</h3>
<span class="duration">30-60 minutos</span>
<p>La fase de testing es critica para detectar problemas antes de que afecten a usuarios en produccion.</p>
<h4>7.1 Checklist de Validacion Basica</h4>
<ul>
<li>Login de usuarios funciona correctamente</li>
<li>Dashboard principal carga sin errores</li>
<li>Imagenes y adjuntos se visualizan correctamente</li>
<li>Reportes PDF se generan correctamente</li>
<li>Envio de emails funciona</li>
<li>Trabajos programados (cron) se ejecutan</li>
</ul>
<h4>7.2 Verificar Logs de Errores</h4>
<div class="code-block">
<code># Revisar logs de Odoo</code><br>
<code>tail -f /var/log/odoo/odoo.log</code><br><br>
<code># Filtrar solo errores</code><br>
<code>grep -i error /var/log/odoo/odoo.log | tail -50</code><br><br>
<code># Revisar logs de nginx</code><br>
<code>tail -f /var/log/nginx/error.log</code>
</div>
<h4>7.3 Probar Modulos Criticos</h4>
<p>Para cada modulo instalado, verifica al menos una operacion critica:</p>
<table class="comparison-table">
<thead>
<tr><th>Modulo</th><th>Prueba Recomendada</th></tr>
</thead>
<tbody>
<tr><td>Ventas</td><td>Crear cotizacion, confirmar pedido, generar factura PDF</td></tr>
<tr><td>Compras</td><td>Crear orden de compra, recibir productos</td></tr>
<tr><td>Inventario</td><td>Verificar stock, realizar transferencia</td></tr>
<tr><td>Contabilidad</td><td>Revisar asientos, generar reporte de balance</td></tr>
<tr><td>CRM</td><td>Ver oportunidades, enviar email desde registro</td></tr>
<tr><td>Website</td><td>Verificar pagina publica, probar formulario de contacto</td></tr>
</tbody>
</table>
<h4>7.4 Validar Integridad de Datos</h4>
<div class="code-block">
<code># Comparar conteos de registros importantes</code><br>
<code># En servidor ORIGEN:</code><br>
<code>psql -U odoo -d tu_base_datos -c "SELECT 'partners' as tabla, COUNT(*) FROM res_partner UNION ALL SELECT 'products', COUNT(*) FROM product_template UNION ALL SELECT 'invoices', COUNT(*) FROM account_move WHERE move_type IN ('out_invoice', 'in_invoice');"</code><br><br>
<code># Repetir en servidor DESTINO y comparar resultados</code>
</div>
<div class="success-box">
<h4>Migracion Exitosa</h4>
<p>Si todos los tests pasan correctamente, la migracion ha sido exitosa. Mantener el servidor antiguo apagado (no eliminado) durante al menos 7 dias como backup de emergencia.</p>
</div>
</div>
</section>
<!-- Common Pitfalls -->
<section id="errores-comunes" class="content-section fade-in">
<h2>Errores Comunes y Soluciones</h2>
<p>Estos son los problemas mas frecuentes durante migraciones de Odoo y como resolverlos:</p>
<div class="pitfall-grid">
<div class="pitfall-card">
<h4>Filestore no encontrado</h4>
<p>Las imagenes y adjuntos no aparecen despues de restaurar.</p>
<div class="solution">
<strong>Solucion:</strong> Verificar que el filestore esta en la ruta correcta indicada en data_dir de odoo.conf. Los permisos deben ser del usuario odoo.
</div>
</div>
<div class="pitfall-card">
<h4>Version PostgreSQL incompatible</h4>
<p>Error: "pg_restore: unsupported version" al restaurar backup.</p>
<div class="solution">
<strong>Solucion:</strong> Instalar la misma version o superior de PostgreSQL. No es posible restaurar backups de versiones nuevas en versiones antiguas.
</div>
</div>
<div class="pitfall-card">
<h4>Modulo no encontrado</h4>
<p>Odoo no arranca por falta de modulo instalado.</p>
<div class="solution">
<strong>Solucion:</strong> Copiar modulos custom al servidor nuevo. Actualizar addons_path en odoo.conf. Ejecutar: pip install [dependencia faltante].
</div>
</div>
<div class="pitfall-card">
<h4>Permisos de directorio</h4>
<p>Errores de escritura en logs o filestore.</p>
<div class="solution">
<strong>Solucion:</strong> sudo chown -R odoo:odoo /opt/odoo/ /var/log/odoo/ y verificar que el servicio corre como usuario odoo.
</div>
</div>
<div class="pitfall-card">
<h4>SSL/HTTPS no funciona</h4>
<p>Certificado no valido o errores de mixed content.</p>
<div class="solution">
<strong>Solucion:</strong> Regenerar certificado con certbot. Verificar proxy_set_header X-Forwarded-Proto en nginx. Actualizar web.base.url en ir_config_parameter.
</div>
</div>
<div class="pitfall-card">
<h4>Emails no se envian</h4>
<p>Error de conexion SMTP despues de migrar.</p>
<div class="solution">
<strong>Solucion:</strong> Verificar configuracion de servidor de correo saliente en Configuracion > Servidores. La IP nueva puede necesitar whitelist en el servidor SMTP.
</div>
</div>
<div class="pitfall-card">
<h4>Longpolling no funciona</h4>
<p>Chat y notificaciones en tiempo real no funcionan.</p>
<div class="solution">
<strong>Solucion:</strong> Verificar configuracion nginx para /longpolling (puerto 8072). Habilitar workers y gevent en odoo.conf.
</div>
</div>
<div class="pitfall-card">
<h4>Cron jobs no ejecutan</h4>
<p>Las acciones programadas no se disparan.</p>
<div class="solution">
<strong>Solucion:</strong> Verificar max_cron_threads > 0 en odoo.conf. Revisar ir.cron en modo desarrollador para ver errores de ejecucion.
</div>
</div>
</div>
</section>
<!-- Checklist -->
<section id="checklist" class="content-section fade-in">
<div class="checklist">
<h3>Checklist Completo de Migracion</h3>
<p>Marca cada item completado para asegurar que no olvidas ningun paso critico:</p>
<div class="checklist-item">
<input type="checkbox" id="check1">
<label for="check1">Documentar version de Odoo actual</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check2">
<label for="check2">Listar todos los modulos instalados</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check3">
<label for="check3">Guardar copia de odoo.conf y configuracion nginx</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check4">
<label for="check4">Verificar espacio disponible en nuevo servidor</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check5">
<label for="check5">Realizar backup de base de datos PostgreSQL</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check6">
<label for="check6">Verificar integridad del backup (pg_restore -l)</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check7">
<label for="check7">Comprimir y transferir filestore</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check8">
<label for="check8">Verificar checksum de archivos transferidos</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check9">
<label for="check9">Instalar Odoo y dependencias en nuevo servidor</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check10">
<label for="check10">Restaurar base de datos</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check11">
<label for="check11">Restaurar filestore con permisos correctos</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check12">
<label for="check12">Copiar modulos personalizados</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check13">
<label for="check13">Configurar odoo.conf</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check14">
<label for="check14">Probar que Odoo arranca correctamente</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check15">
<label for="check15">Configurar nginx como proxy inverso</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check16">
<label for="check16">Instalar certificado SSL</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check17">
<label for="check17">Actualizar registros DNS</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check18">
<label for="check18">Probar login de usuarios</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check19">
<label for="check19">Verificar que imagenes y adjuntos cargan</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check20">
<label for="check20">Probar generacion de reportes PDF</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check21">
<label for="check21">Verificar envio de emails</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check22">
<label for="check22">Comprobar ejecucion de cron jobs</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check23">
<label for="check23">Revisar logs por errores</label>
</div>
<div class="checklist-item">
<input type="checkbox" id="check24">
<label for="check24">Mantener servidor antiguo activo 7+ dias</label>
</div>
</div>
</section>
<!-- CTA Banner -->
<section class="cta-banner fade-in">
<h3>Necesitas Ayuda con tu Migracion?</h3>
<p>Odoo4projects ofrece migracion asistida gratuita cuando contratas su hosting gestionado. Soporte en espanol 24/7 y garantia de 60 dias.</p>
<a href="https://odoo4projects.com" class="cta-btn" target="_blank" rel="noopener sponsored">Solicitar Migracion Gratuita</a>
</section>
<!-- FAQ Section -->
<section id="faq" class="faq-section fade-in">
<h2>Preguntas Frecuentes sobre Migracion de Odoo</h2>
<div class="faq-item">
<div class="faq-question">Cuanto tiempo tarda migrar Odoo a otro hosting?</div>
<div class="faq-answer">Una migracion tipica de Odoo tarda entre 2-6 horas dependiendo del tamano de la base de datos y filestore. Para bases de datos pequenas (menos de 5GB) puede completarse en 2 horas. Instalaciones grandes con muchos archivos pueden requerir 6-8 horas o mas.</div>
</div>
<div class="faq-item">
<div class="faq-question">Puedo migrar Odoo sin tiempo de inactividad?</div>
<div class="faq-answer">Es posible minimizar el downtime usando tecnicas de replicacion. La estrategia recomendada es: preparar el nuevo servidor, sincronizar datos, hacer un backup final rapido y cambiar DNS. El tiempo de inactividad minimo es de 15-30 minutos para el cambio final.</div>
</div>
<div class="faq-item">
<div class="faq-question">Que archivos necesito para migrar Odoo?</div>
<div class="faq-answer">Los componentes esenciales son: 1) Backup de base de datos PostgreSQL (pg_dump), 2) Directorio filestore completo (~/.local/share/Odoo/filestore/), 3) Archivo de configuracion odoo.conf, 4) Modulos personalizados (carpeta addons custom). Opcionalmente: certificados SSL y configuracion nginx.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como hago backup de la base de datos Odoo?</div>
<div class="faq-answer">Usa el comando: pg_dump -Fc -h localhost -U odoo nombre_base_datos > backup.dump. El formato custom (-Fc) permite restauracion flexible. Alternativamente, desde la interfaz web de Odoo en /web/database/manager puedes exportar un archivo ZIP que incluye base de datos y filestore.</div>
</div>
<div class="faq-item">
<div class="faq-question">Que hacer si la migracion de Odoo falla?</div>
<div class="faq-answer">Mantener siempre el servidor original funcionando hasta confirmar que todo funciona. Los errores mas comunes son: versiones incompatibles de PostgreSQL, permisos incorrectos en filestore, modulos faltantes. Revisa los logs en /var/log/odoo/odoo.log para diagnosticar problemas especificos.</div>
</div>
<div class="faq-item">
<div class="faq-question">Puedo migrar de Odoo Community a Enterprise durante el cambio de hosting?</div>
<div class="faq-answer">Si, es posible pero requiere pasos adicionales. Primero migra normalmente, luego activa la licencia Enterprise y agrega los modulos enterprise. La base de datos Community es compatible con Enterprise. Recomendamos hacer esta actualizacion despues de confirmar que la migracion basica funciona.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como migro los modulos personalizados de Odoo?</div>
<div class="faq-answer">Copia el directorio completo de modulos custom al nuevo servidor. Asegurate de que la ruta este configurada en addons_path del archivo odoo.conf. Despues de restaurar la base de datos, actualiza los modulos desde la interfaz de aplicaciones o con: odoo -u all -d nombre_base_datos.</div>
</div>
<div class="faq-item">
<div class="faq-question">Es necesario actualizar la version de Odoo al migrar?</div>
<div class="faq-answer">No es obligatorio, pero es una oportunidad ideal para actualizar. Si decides actualizar version (ej: de Odoo 17 a 18), hazlo DESPUES de confirmar que la migracion al nuevo hosting funciona con la version actual. Las actualizaciones de version requieren scripts de migracion especificos.</div>
</div>
</section>
<!-- Related Articles -->
<section id="relacionados" class="content-section fade-in">
<h2>Articulos Relacionados</h2>
<div class="related-articles">
<a href="/odoo-hosting/mejor-hosting-odoo-2026/" class="related-card">
<div class="related-card-image">Servidor</div>
<div class="related-card-content">
<h4>Mejor Hosting Odoo 2026</h4>
<p>Comparativa de 15+ proveedores de hosting</p>
</div>
</a>
<a href="/odoo-hosting/requisitos-hosting-odoo-servidor-2025/" class="related-card">
<div class="related-card-image">Config</div>
<div class="related-card-content">
<h4>Requisitos Tecnicos para Odoo</h4>
<p>Especificaciones de servidor recomendadas</p>
</div>
</a>
<a href="/odoo-hosting/backup-odoo-guia-2025/" class="related-card">
<div class="related-card-image">Backup</div>
<div class="related-card-content">
<h4>Backup de Odoo: Guia Completa</h4>
<p>Estrategias de respaldo y recuperacion</p>
</div>
</a>
<a href="/odoo-hosting/vps-hosting-odoo-servidor-virtual-2025/" class="related-card">
<div class="related-card-image">VPS</div>
<div class="related-card-content">
<h4>VPS para Odoo: Guia de Configuracion</h4>
<p>Configura tu propio servidor virtual paso a paso</p>
</div>
</a>
<a href="/odoo-hosting/seguridad-odoo-servidor-2025/" class="related-card">
<div class="related-card-image">Seguridad</div>
<div class="related-card-content">
<h4>Seguridad en Servidores Odoo</h4>
<p>Mejores practicas de hardening</p>
</div>
</a>
<a href="/odoo-hosting/optimizacion-rendimiento-odoo-2025/" class="related-card">
<div class="related-card-image">Velocidad</div>
<div class="related-card-content">
<h4>Optimizacion de Rendimiento</h4>
<p>Acelera tu instalacion de Odoo</p>
</div>
</a>
</div>
</section>
</main>
<!-- EEAT Author Section -->
<div id="eeat-section"></div>
<div id="footer"><footer class="site-footer"><div class="container"><div class="footer-cols"><div><strong>Odoo Expertos</strong></div><nav class="footer-nav"><a href="/">Inicio</a><a href="/odoo/">Odoo</a><a href="/odoo-ia/">Odoo IA</a><a href="/odoo-hosting/">Hosting Odoo</a><a href="/mapa-del-sitio/">Mapa del Sitio</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div><nav class="footer-nav"><a href="/">Inicio</a><a href="/odoo/">Odoo</a><a href="/odoo-ia/">Odoo IA</a><a href="/odoo-hosting/">Hosting Odoo</a><a href="/mapa-del-sitio/">Mapa del Sitio</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div>
<!-- Scripts -->
<script src="/js/language-router.js"></script>
<script src="/components/header.min.js"></script>
<script src="/components/footer.min.js"></script>
<script src="/components/eeat.min.js"></script>
<script src="/js/cookie-banner.min.js"></script>
<!-- D3.js -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
// Initialize components
// Scroll animation observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.fade-in').forEach(el => observer.observe(el));
// FAQ Toggle
document.querySelectorAll('.faq-question').forEach(question => {
question.addEventListener('click', () => {
const item = question.parentElement;
item.classList.toggle('open');
});
});
// D3.js Tooltip
const tooltip = d3.select('body').append('div')
.attr('class', 'd3-tooltip')
.style('opacity', 0);
// Migration Workflow Data
const workflowData = {
nodes: [
{ id: 'start', label: 'Inicio', phase: 'Preparacion', time: '', x: 0, y: 0 },
{ id: 'plan', label: 'Planificacion', phase: 'Preparacion', time: '30-60 min', x: 1, y: 0 },
{ id: 'backup-db', label: 'Backup BD', phase: 'Backup', time: '15-60 min', x: 2, y: -0.5 },
{ id: 'backup-fs', label: 'Backup Filestore', phase: 'Backup', time: '15-120 min', x: 2, y: 0.5 },
{ id: 'transfer', label: 'Transferir Archivos', phase: 'Transferencia', time: '30-120 min', x: 3, y: 0 },
{ id: 'setup', label: 'Config. Servidor', phase: 'Instalacion', time: '30-90 min', x: 4, y: 0 },
{ id: 'restore-db', label: 'Restaurar BD', phase: 'Restauracion', time: '20-60 min', x: 5, y: -0.5 },
{ id: 'restore-fs', label: 'Restaurar Filestore', phase: 'Restauracion', time: '10-30 min', x: 5, y: 0.5 },
{ id: 'config', label: 'Configurar Odoo', phase: 'Configuracion', time: '15-30 min', x: 6, y: 0 },
{ id: 'dns', label: 'Cambiar DNS', phase: 'DNS', time: '15-60 min', x: 7, y: 0 },
{ id: 'test', label: 'Testing', phase: 'Validacion', time: '30-60 min', x: 8, y: 0 },
{ id: 'complete', label: 'Completado', phase: 'Fin', time: '', x: 9, y: 0 }
],
links: [
{ source: 'start', target: 'plan' },
{ source: 'plan', target: 'backup-db' },
{ source: 'plan', target: 'backup-fs' },
{ source: 'backup-db', target: 'transfer' },
{ source: 'backup-fs', target: 'transfer' },
{ source: 'transfer', target: 'setup' },
{ source: 'setup', target: 'restore-db' },
{ source: 'setup', target: 'restore-fs' },
{ source: 'restore-db', target: 'config' },
{ source: 'restore-fs', target: 'config' },
{ source: 'config', target: 'dns' },
{ source: 'dns', target: 'test' },
{ source: 'test', target: 'complete' }
]
};
// Color scale for phases
const phaseColors = {
'Preparacion': '#FF6B35',
'Backup': '#FFA726',
'Transferencia': '#FFCA28',
'Instalacion': '#66BB6A',
'Restauracion': '#42A5F5',
'Configuracion': '#7E57C2',
'DNS': '#EC407A',
'Validacion': '#26C6DA',
'Fin': '#4CAF50'
};
// Render Workflow Diagram
function renderWorkflowDiagram() {
const container = d3.select('#workflow-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 450;
const margin = { top: 60, right: 80, bottom: 60, left: 80 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
// Scales
const xScale = d3.scaleLinear()
.domain([0, 9])
.range([0, innerWidth]);
const yScale = d3.scaleLinear()
.domain([-1, 1])
.range([0, innerHeight]);
// Create node positions
const nodeMap = new Map();
workflowData.nodes.forEach(node => {
node.px = xScale(node.x);
node.py = yScale(node.y);
nodeMap.set(node.id, node);
});
// Draw links
const linkGenerator = d3.linkHorizontal()
.x(d => d.x)
.y(d => d.y);
g.selectAll('.link')
.data(workflowData.links)
.join('path')
.attr('class', 'link')
.attr('d', d => {
const source = nodeMap.get(d.source);
const target = nodeMap.get(d.target);
return linkGenerator({
source: { x: source.px + 50, y: source.py },
target: { x: target.px - 50, y: target.py }
});
})
.attr('fill', 'none')
.attr('stroke', '#555')
.attr('stroke-width', 3)
.attr('stroke-dasharray', function() {
return this.getTotalLength();
})
.attr('stroke-dashoffset', function() {
return this.getTotalLength();
})
.transition()
.duration(2000)
.delay((d, i) => i * 150)
.attr('stroke-dashoffset', 0);
// Draw nodes
const nodes = g.selectAll('.node')
.data(workflowData.nodes)
.join('g')
.attr('class', 'node')
.attr('transform', d => `translate(${d.px},${d.py})`)
.style('cursor', 'pointer')
.style('opacity', 0);
// Node backgrounds
nodes.append('rect')
.attr('x', -50)
.attr('y', -25)
.attr('width', 100)
.attr('height', 50)
.attr('rx', 10)
.attr('fill', d => phaseColors[d.phase] || '#FF6B35')
.attr('stroke', '#fff')
.attr('stroke-width', 2);
// Node labels
nodes.append('text')
.attr('text-anchor', 'middle')
.attr('dy', 5)
.attr('fill', '#fff')
.attr('font-size', '11px')
.attr('font-weight', '600')
.text(d => d.label);
// Interactivity
nodes.on('mouseover', function(event, d) {
d3.select(this).select('rect')
.transition()
.duration(200)
.attr('x', -55)
.attr('y', -30)
.attr('width', 110)
.attr('height', 60);
if (d.time) {
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${d.label}</strong><br>Fase: ${d.phase}<br>Tiempo: ${d.time}`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
}
})
.on('mouseout', function() {
d3.select(this).select('rect')
.transition()
.duration(200)
.attr('x', -50)
.attr('y', -25)
.attr('width', 100)
.attr('height', 50);
tooltip.transition().duration(200).style('opacity', 0);
});
// Animate nodes
nodes.transition()
.duration(500)
.delay((d, i) => i * 150)
.style('opacity', 1);
// Legend
const phases = [...new Set(workflowData.nodes.map(n => n.phase))];
const legendG = svg.append('g')
.attr('transform', `translate(${margin.left}, 20)`);
phases.forEach((phase, i) => {
const item = legendG.append('g')
.attr('transform', `translate(${i * 100}, 0)`);
item.append('rect')
.attr('width', 14)
.attr('height', 14)
.attr('rx', 3)
.attr('fill', phaseColors[phase]);
item.append('text')
.attr('x', 18)
.attr('y', 11)
.attr('fill', '#b0b0b0')
.attr('font-size', '10px')
.text(phase);
});
}
// Initialize chart when visible
const chartObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.id;
setTimeout(() => {
if (id === 'workflow-chart') renderWorkflowDiagram();
}, 100);
chartObserver.unobserve(entry.target);
}
});
}, { threshold: 0.15 });
document.querySelectorAll('.chart-container').forEach(el => chartObserver.observe(el));
// Resize handler
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
renderWorkflowDiagram();
}, 300);
});
// Checklist persistence
document.querySelectorAll('.checklist-item input').forEach(checkbox => {
const key = 'migration-checklist-' + checkbox.id;
// Load saved state
if (localStorage.getItem(key) === 'true') {
checkbox.checked = true;
}
// Save on change
checkbox.addEventListener('change', () => {
localStorage.setItem(key, checkbox.checked);
});
});
</script>
</body>
</html>