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

2493 lines
98 KiB
HTML

<!DOCTYPE html>
<html lang="pt-BR">
<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>Hosting Odoo Propio Selfhosted 2026 | Odoo Expertos · PT</title>
<meta name="description" content="Guia definitiva para alojar Odoo en tu propio servidor en 2026. Requisitos de hardware, instalacion paso a paso, mantenimi - Hosting Odoo Propio Selfhosted 2026 | PT">
<meta name="keywords" content="odoo self-hosted, hosting odoo propio, instalar odoo servidor propio, odoo on-premise, servidor odoo requisitos, mantenimiento odoo, odoo vps propio, configurar servidor odoo">
<meta name="author" content="Dra. Equipo Odoo Expertos">
<meta name="robots" content="noindex,follow">
<meta name="language" content="pt-BR">
<link rel="canonical" href="https://www.odoo-expertos.com/pt/odoo-hosting/hosting-odoo-propio-selfhosted-2026/">
<!-- Hreflang -->
<link rel="alternate" hreflang="pt-BR" href="https://www.odoo-expertos.com/pt/odoo-hosting/hosting-odoo-propio-selfhosted-2026/" />
<link rel="alternate" hreflang="en" href="https://www.odoo-expertos.com/en/odoo-hosting/self-hosted-odoo-2026/" />
<link rel="alternate" hreflang="de" href="https://www.odoo-expertos.com/de/odoo-hosting/odoo-selbst-gehostet-2026/" />
<link rel="alternate" hreflang="fr" href="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-auto-heberge-2026/" />
<link rel="alternate" hreflang="x-default" href="https://www.odoo-expertos.com/odoo-hosting/hosting-odoo-propio-selfhosted-2026/" />
<!-- Open Graph -->
<meta property="og:title" content="Hosting Odoo Propio Self-Hosted 2026: Guia Completa de Instalacion">
<meta property="og:description" content="Guia definitiva para alojar Odoo en tu propio servidor. Requisitos de hardware, instalacion, mantenimiento y analisis de costos.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.odoo-expertos.com/pt/odoo-hosting/hosting-odoo-propio-selfhosted-2026/">
<meta property="og:image" content="https://www.odoo-expertos.com/images/hosting-odoo-propio-selfhosted-2026.jpg">
<meta property="og:site_name" content="Odoo Expertos">
<meta property="og:locale" content="pt_BR">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Hosting Odoo Propio Self-Hosted 2026: Guia Completa">
<meta name="twitter:description" content="Guia definitiva para alojar Odoo en tu propio servidor en 2026.">
<!-- Schema.org Article -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Hosting Odoo Propio Self-Hosted 2026: Guia Completa de Instalacion y Mantenimiento",
"description": "Guia definitiva para alojar Odoo en tu propio servidor en 2026. Requisitos de hardware, instalacion paso a paso, mantenimiento y analisis de costos.",
"author": {
"@type": "Person",
"name": "Dra. 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/hosting-odoo-propio-selfhosted-2026/"
}
}
</script>
<!-- HowTo Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Como Instalar Odoo en Servidor Propio",
"description": "Guia paso a paso para instalar y configurar Odoo 18 en tu propio servidor Ubuntu",
"totalTime": "PT2H",
"estimatedCost": {
"@type": "MonetaryAmount",
"currency": "EUR",
"value": "0"
},
"supply": [
{
"@type": "HowToSupply",
"name": "Servidor Ubuntu 22.04 o 24.04 LTS"
},
{
"@type": "HowToSupply",
"name": "Acceso root o sudo"
},
{
"@type": "HowToSupply",
"name": "Dominio configurado (opcional)"
}
],
"tool": [
{
"@type": "HowToTool",
"name": "Terminal SSH"
},
{
"@type": "HowToTool",
"name": "Editor de texto"
}
],
"step": [
{
"@type": "HowToStep",
"name": "Preparar el sistema",
"text": "Actualizar el sistema operativo e instalar dependencias basicas"
},
{
"@type": "HowToStep",
"name": "Instalar PostgreSQL",
"text": "Instalar y configurar PostgreSQL 14+ como base de datos"
},
{
"@type": "HowToStep",
"name": "Crear usuario Odoo",
"text": "Crear usuario del sistema y de PostgreSQL para Odoo"
},
{
"@type": "HowToStep",
"name": "Instalar dependencias Python",
"text": "Instalar Python 3.10+ y todas las librerias requeridas"
},
{
"@type": "HowToStep",
"name": "Descargar Odoo",
"text": "Clonar el repositorio oficial de Odoo desde GitHub"
},
{
"@type": "HowToStep",
"name": "Configurar Odoo",
"text": "Crear archivo de configuracion odoo.conf"
},
{
"@type": "HowToStep",
"name": "Configurar servicio systemd",
"text": "Crear servicio para inicio automatico de Odoo"
},
{
"@type": "HowToStep",
"name": "Configurar Nginx",
"text": "Configurar proxy inverso con SSL/TLS"
}
]
}
</script>
<!-- FAQ Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Que requisitos de hardware necesita Odoo self-hosted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Para Odoo 18 Community necesitas minimo 4GB RAM, 2 CPU cores y 40GB SSD. Para produccion con 10-20 usuarios recomendamos 8GB RAM, 4 cores y 100GB NVMe. Enterprise requiere el doble de recursos."
}
},
{
"@type": "Question",
"name": "Cuanto cuesta mantener Odoo en servidor propio?",
"acceptedAnswer": {
"@type": "Answer",
"text": "El costo mensual incluye: servidor VPS (20-100 euros), tiempo de administracion (4-10 horas/mes valoradas en 200-500 euros), backups externos (5-20 euros) y licencias si usas Enterprise. Total estimado: 225-620 euros/mes considerando tiempo de personal."
}
},
{
"@type": "Question",
"name": "Es seguro alojar Odoo en mi propio servidor?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Sim, puede ser muy seguro si implementas correctamente: firewall UFW, SSL/TLS con Let's Encrypt, actualizaciones automaticas de seguridad, backups cifrados, fail2ban contra ataques de fuerza bruta, y auditorias periodicas. Simn estos controles, es mas arriesgado que hosting gestionado."
}
},
{
"@type": "Question",
"name": "Cuando tiene sentido el self-hosting de Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "El self-hosting tiene sentido cuando: tienes equipo tecnico con experiencia en Linux/PostgreSQL, necesitas personalizaciones profundas del sistema, tienes requisitos de cumplimiento que exigen control total de datos, o manejas volumenes muy altos donde el ahorro compensa el esfuerzo."
}
},
{
"@type": "Question",
"name": "Que sistema operativo es mejor para Odoo self-hosted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Ubuntu Server LTS (22.04 o 24.04) es la opcion mas recomendada por su estabilidad, soporte a largo plazo y documentacion abundante. Debian 12 es otra excelente opcion. Não recomendamos CentOS/RHEL para nuevas instalaciones debido a cambios en su modelo de soporte."
}
},
{
"@type": "Question",
"name": "Como hacer backups de Odoo self-hosted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Necesitas respaldar: 1) Base de datos PostgreSQL con pg_dump diario, 2) Filestore completo (archivos adjuntos), 3) Configuracion del servidor, 4) Modulos personalizados. Usa la regla 3-2-1: 3 copias, 2 medios diferentes, 1 ubicacion externa. Automatiza con scripts cron y almacena en S3, Backblaze o similar."
}
},
{
"@type": "Question",
"name": "Puedo migrar de hosting gestionado a self-hosted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Sim, la migracion implica: exportar base de datos PostgreSQL desde el proveedor actual, copiar el filestore completo, replicar la configuracion del servidor en tu infraestructura, y restaurar. El proceso puede tomar 2-8 horas dependiendo del tamano de datos. Planifica una ventana de mantenimiento."
}
},
{
"@type": "Question",
"name": "Cuantos usuarios soporta un servidor Odoo self-hosted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Depende de la configuracion: servidor de 4GB RAM soporta 10-20 usuarios simultaneos, 8GB soporta 30-50 usuarios, 16GB+ soporta 100+ usuarios. La clave esta en configurar correctamente los workers de Odoo segun la formula: (CPU cores x 2) + 1 workers."
}
}
]
}
</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/pt/odoo-hosting/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Hosting Odoo Propio Self-Hosted 2026",
"item": "https://www.odoo-expertos.com/pt/odoo-hosting/hosting-odoo-propio-selfhosted-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;
}
.content-section h4 {
color: #e0e0e0;
margin: 1.5rem 0 0.75rem;
}
.content-section p {
line-height: 1.8;
margin-bottom: 1rem;
color: #c0c0c0;
}
.content-section ul, .content-section ol {
margin: 1rem 0 1.5rem 1.5rem;
color: #c0c0c0;
}
.content-section li {
margin-bottom: 0.5rem;
line-height: 1.7;
}
.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: 400px;
position: relative;
}
.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);
}
.comparison-table .check {
color: #4CAF50;
font-weight: bold;
}
.comparison-table .cross {
color: #f44336;
}
.code-block {
background: #1a1a1a;
border: 1px solid #3a3a3a;
border-radius: 8px;
padding: 1.5rem;
margin: 1.5rem 0;
overflow-x: auto;
font-family: 'Fira Code', 'Monaco', monospace;
font-size: 0.9rem;
line-height: 1.6;
}
.code-block code {
color: #e0e0e0;
}
.code-block .comment {
color: #6a9955;
}
.code-block .command {
color: #dcdcaa;
}
.code-block .string {
color: #ce9178;
}
.code-block .keyword {
color: #569cd6;
}
.step-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: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.step-box h4 {
color: #FF6B35;
margin-bottom: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.step-box .step-number {
background: #FF6B35;
color: #fff;
width: 28px;
height: 28px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.9rem;
}
.warning-box {
background: rgba(255, 193, 7, 0.1);
border-left: 4px solid #FFC107;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.warning-box h4 {
color: #FFC107;
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;
}
.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;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin: 1.5rem 0;
}
.pros, .cons {
padding: 1.5rem;
border-radius: 8px;
}
.pros {
background: rgba(76, 175, 80, 0.1);
border: 1px solid rgba(76, 175, 80, 0.3);
}
.cons {
background: rgba(244, 67, 54, 0.1);
border: 1px solid rgba(244, 67, 54, 0.3);
}
.pros h4 {
color: #4CAF50;
margin-bottom: 1rem;
}
.cons h4 {
color: #f44336;
margin-bottom: 1rem;
}
.pros ul, .cons ul {
list-style: none;
padding: 0;
margin: 0;
}
.pros li::before {
content: 'OK ';
color: #4CAF50;
font-weight: bold;
}
.cons li::before {
content: 'X ';
color: #f44336;
font-weight: bold;
}
.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;
}
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
.timeline {
position: relative;
padding-left: 2rem;
margin: 2rem 0;
}
.timeline::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: linear-gradient(to bottom, #FF6B35, #FF8A50);
border-radius: 2px;
}
.timeline-item {
position: relative;
padding: 1rem 0 2rem 1.5rem;
}
.timeline-item::before {
content: '';
position: absolute;
left: -2rem;
top: 1.25rem;
width: 12px;
height: 12px;
background: #FF6B35;
border-radius: 50%;
transform: translateX(-50%);
}
.timeline-item h4 {
color: #FF8A50;
margin-bottom: 0.5rem;
}
@media (max-width: 768px) {
.toc-list {
columns: 1;
}
.pillar-meta {
flex-direction: column;
gap: 0.5rem;
}
.chart-container {
min-height: 300px;
}
.pros-cons {
grid-template-columns: 1fr;
}
.code-block {
font-size: 0.8rem;
padding: 1rem;
}
}
</style>
</head>
<body>
<div id="header"><header class="site-header"><nav class="navbar"><div class="container"><div class="nav-brand"><a href="/pt/" 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="/pt/">Inicio</a></li><li><a href="/pt/odoo/">Odoo</a></li><li><a href="/pt/odoo-ia/">Odoo IA</a></li><li><a href="/pt/odoo-hosting/">Hospedagem Odoo</a></li><li><a href="/pt/mapa-del-sitio/">Mapa do Site</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="/pt/">Inicio</a></li><li><a href="/pt/odoo/">Odoo</a></li><li><a href="/pt/odoo-ia/">Odoo IA</a></li><li><a href="/pt/odoo-hosting/">Hospedagem Odoo</a></li><li><a href="/pt/mapa-del-sitio/">Mapa do Site</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="/pt/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">Hosting Odoo Propio Self-Hosted 2026</span>
<span itemprop="position" style="display:none">3</span>
</li>
</ol>
</div>
</nav>
<!-- Hero Section -->
<section class="pillar-hero">
<div class="container">
<h1>Hosting Odoo Propio Self-Hosted 2026: Guia Completa</h1>
<p class="pillar-subtitle">Todo lo que necesitas saber para alojar Odoo en tu propio servidor. Requisitos de hardware, instalacion paso a paso, mantenimiento continuo y analisis detallado de costos frente a hosting gestionado.</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">4GB</span>
<span class="stat-label">RAM Minima Requerida</span>
</div>
<div class="stat-card">
<span class="stat-number">20-100</span>
<span class="stat-label">Euros/mes Servidor VPS</span>
</div>
<div class="stat-card">
<span class="stat-number">4-10h</span>
<span class="stat-label">Mantenimiento Mensual</span>
</div>
<div class="stat-card">
<span class="stat-number">2h</span>
<span class="stat-label">Tiempo Instalacion</span>
</div>
<div class="stat-card">
<span class="stat-number">99.5%</span>
<span class="stat-label">Uptime Alcanzable</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 al Self-Hosting de Odoo</a></li>
<li><a href="#cuando-selfhosting">Cuando Tiene Sentido el Self-Hosting</a></li>
<li><a href="#requisitos-hardware">Requisitos de Hardware Detallados</a></li>
<li><a href="#grafico-recursos">Grafico: Recursos vs Usuarios</a></li>
<li><a href="#guia-instalacion">Guia de Instalacion Paso a Paso</a></li>
<li><a href="#configuracion-seguridad">Configuracion de Seguridad</a></li>
<li><a href="#mantenimiento">Responsabilidades de Mantenimiento</a></li>
<li><a href="#analisis-costos">Analisis de Costos: Self-Hosted vs Gestionado</a></li>
<li><a href="#grafico-costos">Grafico Comparativo de Costos</a></li>
<li><a href="#faq">Preguntas Frecuentes (8+)</a></li>
<li><a href="#relacionados">Articulos Relacionados</a></li>
</ol>
</nav>
<!-- Introduction Section -->
<section id="introduccion" class="content-section fade-in">
<h2>Introduccion al Self-Hosting de Odoo: Control Total de tu ERP</h2>
<p>El self-hosting de Odoo significa instalar y mantener tu propia instancia del ERP en un servidor que controlas completamente. Esta opcion ofrece maxima flexibilidad y control, pero tambien conlleva responsabilidades significativas que debes comprender antes de tomar la decision.</p>
<p>En 2026, con Odoo 18 como version estable y la version 19 en desarrollo, el self-hosting sigue siendo una opcion viable y popular para empresas con equipos tecnicos competentes. La comunidad ha madurado enormemente, con documentacion exhaustiva, scripts de automatizacion y mejores practicas bien establecidas.</p>
<div class="highlight-box">
<h4>Conclusion Clave</h4>
<p>El self-hosting de Odoo es ideal para empresas con <strong>equipo tecnico dedicado</strong>, necesidades de <strong>personalizacion profunda</strong>, o requisitos estrictos de <strong>cumplimiento normativo</strong>. Para la mayoria de PYMES sin experiencia tecnica, un <strong>hosting gestionado como Odoo4projects</strong> ofrece mejor relacion esfuerzo-beneficio.</p>
</div>
<h3>Que Implica el Self-Hosting</h3>
<p>Cuando decides alojar Odoo en tu propio servidor, asumes la responsabilidad completa de:</p>
<ul>
<li><strong>Infraestructura:</strong> Seleccion, configuracion y mantenimiento del servidor fisico o virtual</li>
<li><strong>Sistema operativo:</strong> Instalacion, actualizaciones de seguridad y hardening</li>
<li><strong>Base de datos:</strong> PostgreSQL con optimizacion, backups y recuperacion</li>
<li><strong>Aplicacion Odoo:</strong> Instalacion, actualizaciones, modulos y personalizaciones</li>
<li><strong>Seguridad:</strong> Firewall, SSL/TLS, proteccion contra intrusiones, auditorias</li>
<li><strong>Monitoreo:</strong> Disponibilidad, rendimiento, alertas y respuesta a incidentes</li>
<li><strong>Backups:</strong> Estrategia completa de respaldo y recuperacion ante desastres</li>
</ul>
<h3>Self-Hosting vs Hosting Gestionado: Vision General</h3>
<div class="pros-cons">
<div class="pros">
<h4>Ventajas del Self-Hosting</h4>
<ul>
<li>Control total sobre la infraestructura</li>
<li>Sin limites en personalizaciones</li>
<li>Potencial ahorro a gran escala</li>
<li>Datos 100% bajo tu control</li>
<li>Sin dependencia de proveedores</li>
<li>Flexibilidad de ubicacion geografica</li>
</ul>
</div>
<div class="cons">
<h4>Desventajas del Self-Hosting</h4>
<ul>
<li>Requiere expertise tecnico</li>
<li>Tiempo significativo de administracion</li>
<li>Responsabilidad total de seguridad</li>
<li>Sin soporte directo del proveedor</li>
<li>Costo oculto del tiempo de personal</li>
<li>Complejidad en alta disponibilidad</li>
</ul>
</div>
</div>
</section>
<!-- When Self-Hosting Makes Sense -->
<section id="cuando-selfhosting" class="content-section fade-in">
<h2>Cuando Tiene Sentido el Self-Hosting de Odoo</h2>
<p>No todas las empresas deberian optar por el self-hosting. Esta decision debe basarse en una evaluacion honesta de tus capacidades, recursos y necesidades especificas. A continuacion, analizamos los escenarios donde el self-hosting realmente tiene sentido.</p>
<h3>Escenarios Ideales para Self-Hosting</h3>
<h4>1. Tienes Equipo Tecnico con Experiencia</h4>
<p>El factor mas critico es contar con personal que domine:</p>
<ul>
<li>Administracion de sistemas Linux (Ubuntu/Debian preferiblemente)</li>
<li>PostgreSQL: instalacion, configuracion, optimizacion y backups</li>
<li>Python y su ecosistema (pip, virtualenv, dependencias)</li>
<li>Redes: DNS, firewall, proxy inverso, SSL/TLS</li>
<li>Seguridad de servidores: hardening, monitoreo, respuesta a incidentes</li>
</ul>
<div class="info-box">
<h4>Nivel de Expertise Requerido</h4>
<p>Estimamos que necesitas al menos un profesional con 3+ anos de experiencia en administracion de sistemas Linux para gestionar Odoo self-hosted de forma competente. Para entornos de produccion criticos, recomendamos dos personas para evitar puntos unicos de fallo.</p>
</div>
<h4>2. Requisitos de Cumplimiento Estrictos</h4>
<p>Algunas industrias y regulaciones exigen control total sobre los datos:</p>
<ul>
<li><strong>Sector financiero:</strong> Regulaciones bancarias que exigen datos en territorio especifico</li>
<li><strong>Salud:</strong> HIPAA, GDPR con requisitos especiales para datos medicos</li>
<li><strong>Gobierno:</strong> Clasificacion de datos que impide uso de clouds publicos</li>
<li><strong>Defensa:</strong> Requisitos de seguridad que solo se cumplen on-premise</li>
</ul>
<h4>3. Necesidades de Personalizacion Profunda</h4>
<p>Si requieres modificaciones que van mas alla de los modulos estandar:</p>
<ul>
<li>Integraciones con sistemas legacy mediante protocolos propietarios</li>
<li>Modificaciones al core de Odoo (no recomendado pero a veces necesario)</li>
<li>Workflows extremadamente complejos con logica personalizada</li>
<li>Volumen de datos atipico que requiere optimizaciones especificas</li>
</ul>
<h4>4. Gran Escala con Equipo Dedicado</h4>
<p>Para organizaciones con mas de 100 usuarios concurrentes y equipo de IT robusto, el self-hosting puede ofrecer economias de escala significativas.</p>
<h3>Cuando NO Elegir Self-Hosting</h3>
<div class="warning-box">
<h4>Senales de Alerta</h4>
<p>Evita el self-hosting si alguna de estas situaciones aplica a tu organizacion:</p>
</div>
<ul>
<li><strong>No tienes personal tecnico:</strong> Contratar administracion externa puede costar mas que hosting gestionado</li>
<li><strong>Tu equipo ya esta sobrecargado:</strong> Anadir Odoo a sus responsabilidades degradara todo</li>
<li><strong>Presupuesto limitado para emergencias:</strong> Un incidente grave puede requerir consultores externos urgentes</li>
<li><strong>Necesitas soporte 24/7:</strong> Dificil de lograr internamente para equipos pequenos</li>
<li><strong>Primera implementacion de Odoo:</strong> Mejor aprender con hosting gestionado primero</li>
</ul>
</section>
<!-- Hardware Requirements -->
<section id="requisitos-hardware" class="content-section fade-in">
<h2>Requisitos de Hardware para Odoo Self-Hosted</h2>
<p>La seleccion correcta del hardware es fundamental para el rendimiento de Odoo. Un servidor subdimensionado causara lentitud frustrante, mientras que uno sobredimensionado desperdiciara recursos. A continuacion, detallamos los requisitos segun diferentes escenarios.</p>
<h3>Requisitos Minimos (Desarrollo/Pruebas)</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Componente</th>
<th>Minimo</th>
<th>Notas</th>
</tr>
</thead>
<tbody>
<tr>
<td>RAM</td>
<td>4 GB</td>
<td>Apenas suficiente para 1-3 usuarios de prueba</td>
</tr>
<tr>
<td>CPU</td>
<td>2 cores</td>
<td>Procesador moderno (2020+)</td>
</tr>
<tr>
<td>Almacenamiento</td>
<td>40 GB SSD</td>
<td>SSD obligatorio, HDD inaceptable</td>
</tr>
<tr>
<td>Sistema Operativo</td>
<td>Ubuntu 22.04 LTS</td>
<td>Soporte hasta 2027</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>14</td>
<td>Version minima soportada</td>
</tr>
<tr>
<td>Python</td>
<td>3.10</td>
<td>Incluido en Ubuntu 22.04</td>
</tr>
</tbody>
</table>
<h3>Requisitos Recomendados (Produccion PYME: 10-30 usuarios)</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Componente</th>
<th>Recomendado</th>
<th>Notas</th>
</tr>
</thead>
<tbody>
<tr>
<td>RAM</td>
<td>8-16 GB</td>
<td>8GB minimo, 16GB para comodidad</td>
</tr>
<tr>
<td>CPU</td>
<td>4 cores</td>
<td>Permite configurar multiples workers</td>
</tr>
<tr>
<td>Almacenamiento</td>
<td>100-200 GB NVMe</td>
<td>NVMe para maximo IOPS</td>
</tr>
<tr>
<td>Sistema Operativo</td>
<td>Ubuntu 24.04 LTS</td>
<td>Soporte hasta 2029</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>16</td>
<td>Mejor rendimiento con Odoo 18</td>
</tr>
<tr>
<td>Python</td>
<td>3.12</td>
<td>Mejor rendimiento que 3.10</td>
</tr>
<tr>
<td>Red</td>
<td>1 Gbps</td>
<td>Minimo para buen rendimiento</td>
</tr>
</tbody>
</table>
<h3>Requisitos Enterprise/Gran Escala (50+ usuarios)</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Componente</th>
<th>Recomendado</th>
<th>Notas</th>
</tr>
</thead>
<tbody>
<tr>
<td>RAM</td>
<td>32-64 GB</td>
<td>Permite cache agresivo</td>
</tr>
<tr>
<td>CPU</td>
<td>8-16 cores</td>
<td>Necesario para muchos workers</td>
</tr>
<tr>
<td>Almacenamiento</td>
<td>500 GB+ NVMe RAID</td>
<td>RAID 10 para redundancia y velocidad</td>
</tr>
<tr>
<td>Base de datos</td>
<td>Servidor dedicado</td>
<td>PostgreSQL en servidor separado</td>
</tr>
<tr>
<td>Red</td>
<td>10 Gbps interna</td>
<td>Para comunicacion app-db</td>
</tr>
<tr>
<td>Balanceador</td>
<td>HAProxy/Nginx</td>
<td>Para distribuir carga</td>
</tr>
</tbody>
</table>
<h3>Formula para Calcular Workers de Odoo</h3>
<div class="code-block">
<code>
<span class="comment"># Formula recomendada para workers</span>
workers = (CPU_cores * 2) + 1
<span class="comment"># Ejemplo: servidor con 4 cores</span>
workers = (4 * 2) + 1 = 9 workers
<span class="comment"># Memoria por worker (aproximado)</span>
RAM_por_worker = 150-300 MB (depende de modulos instalados)
<span class="comment"># Calculo de RAM total necesaria</span>
RAM_total = workers * RAM_por_worker + RAM_PostgreSQL + RAM_SO
RAM_total = 9 * 250MB + 2GB + 1GB = ~5.25 GB minimo
</code>
</div>
<div class="info-box">
<h4>Odoo Community vs Enterprise: Diferencia de Recursos</h4>
<p>Odoo Enterprise requiere aproximadamente un <strong>50-100% mas de recursos</strong> que Community debido a modulos adicionales como contabilidad avanzada, studio, IoT, y reportes complejos. Planifica tu hardware considerando esta diferencia si planeas usar Enterprise.</p>
</div>
</section>
<!-- D3.js Resources Chart -->
<section class="chart-section fade-in">
<h3 id="grafico-recursos">Recursos Requeridos segun Numero de Usuarios</h3>
<p>Este grafico interactivo muestra como escalan los requisitos de hardware segun el numero de usuarios concurrentes. Pasa el cursor sobre los puntos para ver detalles especificos.</p>
<div class="chart-container" id="resources-chart"></div>
</section>
<!-- Installation Guide -->
<section id="guia-instalacion" class="content-section fade-in">
<h2>Guia de Instalacion de Odoo 18 en Ubuntu 24.04</h2>
<p>A continuacion, presentamos una guia paso a paso para instalar Odoo 18 Community en Ubuntu Server 24.04 LTS. Esta guia asume que partes de una instalacion limpia del sistema operativo con acceso root o sudo.</p>
<div class="warning-box">
<h4>Antes de Comenzar</h4>
<p>Asegurate de tener: acceso SSH al servidor, dominio configurado (opcional pero recomendado), y al menos 2 horas para completar la instalacion y configuracion inicial.</p>
</div>
<div class="step-box">
<h4><span class="step-number">1</span> Preparar el Sistema</h4>
<p>Actualiza el sistema e instala las dependencias basicas necesarias.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Actualizar el sistema</span>
<span class="command">sudo apt update && sudo apt upgrade -y</span>
<span class="comment"># Instalar dependencias basicas</span>
<span class="command">sudo apt install -y git python3-pip python3-dev python3-venv \
build-essential libxml2-dev libxslt1-dev libevent-dev \
libsasl2-dev libldap2-dev libpq-dev libjpeg-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev libharfbuzz-dev \
libfribidi-dev libxcb1-dev node-less npm wkhtmltopdf</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">2</span> Instalar y Configurar PostgreSQL</h4>
<p>PostgreSQL es la unica base de datos soportada oficialmente por Odoo.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Instalar PostgreSQL 16</span>
<span class="command">sudo apt install -y postgresql postgresql-contrib</span>
<span class="comment"># Verificar que esta corriendo</span>
<span class="command">sudo systemctl status postgresql</span>
<span class="comment"># Crear usuario PostgreSQL para Odoo</span>
<span class="command">sudo -u postgres createuser --createdb --no-createrole --no-superuser odoo</span>
<span class="comment"># Establecer contrasena (guarda esto de forma segura)</span>
<span class="command">sudo -u postgres psql -c "ALTER USER odoo WITH PASSWORD 'tu_contrasena_segura';"</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">3</span> Crear Usuario del Sistema para Odoo</h4>
<p>Por seguridad, Odoo debe ejecutarse con su propio usuario sin privilegios.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Crear usuario odoo sin shell interactivo</span>
<span class="command">sudo useradd -m -d /opt/odoo -U -r -s /bin/bash odoo</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">4</span> Descargar Odoo desde GitHub</h4>
<p>Clonamos el repositorio oficial de Odoo 18.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Cambiar al usuario odoo</span>
<span class="command">sudo su - odoo</span>
<span class="comment"># Clonar Odoo 18 (rama estable)</span>
<span class="command">git clone https://github.com/odoo/odoo.git --depth 1 --branch 18.0 /opt/odoo/odoo</span>
<span class="comment"># Crear directorio para modulos personalizados</span>
<span class="command">mkdir /opt/odoo/custom-addons</span>
<span class="comment"># Volver a usuario normal</span>
<span class="command">exit</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">5</span> Crear Entorno Virtual e Instalar Dependencias Python</h4>
<p>Usamos un entorno virtual para aislar las dependencias de Odoo.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Cambiar al usuario odoo</span>
<span class="command">sudo su - odoo</span>
<span class="comment"># Crear entorno virtual</span>
<span class="command">python3 -m venv /opt/odoo/venv</span>
<span class="comment"># Activar entorno virtual</span>
<span class="command">source /opt/odoo/venv/bin/activate</span>
<span class="comment"># Actualizar pip</span>
<span class="command">pip install --upgrade pip wheel</span>
<span class="comment"># Instalar dependencias de Odoo</span>
<span class="command">pip install -r /opt/odoo/odoo/requirements.txt</span>
<span class="comment"># Desactivar y salir</span>
<span class="command">deactivate</span>
<span class="command">exit</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">6</span> Crear Archivo de Configuracion</h4>
<p>El archivo odoo.conf contiene toda la configuracion del servidor.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Crear archivo de configuracion</span>
<span class="command">sudo nano /etc/odoo.conf</span>
<span class="comment"># Contenido del archivo:</span>
[options]
admin_passwd = <span class="string">tu_master_password_muy_segura</span>
db_host = localhost
db_port = 5432
db_user = odoo
db_password = <span class="string">tu_contrasena_segura</span>
addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons
data_dir = /opt/odoo/.local/share/Odoo
logfile = /var/log/odoo/odoo.log
log_level = info
<span class="comment"># Configuracion de workers (ajustar segun CPU)</span>
workers = 5
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_cpu = 600
limit_time_real = 1200
<span class="comment"># Proxy mode (si usas Nginx)</span>
proxy_mode = True
</code>
</div>
<div class="code-block">
<code>
<span class="comment"># Crear directorio de logs y ajustar permisos</span>
<span class="command">sudo mkdir -p /var/log/odoo</span>
<span class="command">sudo chown odoo:odoo /var/log/odoo</span>
<span class="command">sudo chown odoo:odoo /etc/odoo.conf</span>
<span class="command">sudo chmod 640 /etc/odoo.conf</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">7</span> Crear Servicio Systemd</h4>
<p>Configuramos Odoo para iniciarse automaticamente con el sistema.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Crear archivo de servicio</span>
<span class="command">sudo nano /etc/systemd/system/odoo.service</span>
<span class="comment"># Contenido:</span>
[Unit]
Description=Odoo 18
Documentation=https://www.odoo.com
After=network.target postgresql.service
[Service]
Type=simple
User=odoo
Group=odoo
ExecStart=/opt/odoo/venv/bin/python3 /opt/odoo/odoo/odoo-bin -c /etc/odoo.conf
StandardOutput=journal+console
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
</code>
</div>
<div class="code-block">
<code>
<span class="comment"># Recargar systemd, habilitar e iniciar servicio</span>
<span class="command">sudo systemctl daemon-reload</span>
<span class="command">sudo systemctl enable odoo</span>
<span class="command">sudo systemctl start odoo</span>
<span class="comment"># Verificar estado</span>
<span class="command">sudo systemctl status odoo</span>
</code>
</div>
<div class="step-box">
<h4><span class="step-number">8</span> Configurar Nginx como Proxy Inverso</h4>
<p>Nginx maneja SSL/TLS y mejora el rendimiento sirviendo archivos estaticos.</p>
</div>
<div class="code-block">
<code>
<span class="comment"># Instalar Nginx y Certbot</span>
<span class="command">sudo apt install -y nginx certbot python3-certbot-nginx</span>
<span class="comment"># Crear configuracion de sitio</span>
<span class="command">sudo nano /etc/nginx/sites-available/odoo</span>
<span class="comment"># Contenido basico:</span>
upstream odoo {
server 127.0.0.1:8069;
}
upstream odoo-chat {
server 127.0.0.1:8072;
}
server {
listen 80;
server_name tu-dominio.com;
access_log /var/log/nginx/odoo-access.log;
error_log /var/log/nginx/odoo-error.log;
proxy_buffers 16 64k;
proxy_buffer_size 128k;
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
location / {
proxy_pass http://odoo;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
}
location /longpolling {
proxy_pass http://odoo-chat;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
location ~* /web/static/ {
proxy_cache_valid 200 90m;
proxy_buffering on;
expires 864000;
proxy_pass http://odoo;
}
gzip on;
gzip_types text/css text/plain application/javascript application/json;
}
</code>
</div>
<div class="code-block">
<code>
<span class="comment"># Habilitar sitio y reiniciar Nginx</span>
<span class="command">sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/</span>
<span class="command">sudo nginx -t</span>
<span class="command">sudo systemctl restart nginx</span>
<span class="comment"># Obtener certificado SSL con Let's Encrypt</span>
<span class="command">sudo certbot --nginx -d tu-dominio.com</span>
</code>
</div>
<div class="info-box">
<h4>Instalacion Completada</h4>
<p>Ahora puedes acceder a Odoo en <strong>https://tu-dominio.com</strong>. La primera vez veras el asistente de creacion de base de datos. Usa el master password que configuraste en odoo.conf para crear tu primera base de datos.</p>
</div>
</section>
<!-- Security Configuration -->
<section id="configuracion-seguridad" class="content-section fade-in">
<h2>Configuracion de Seguridad para Odoo Self-Hosted</h2>
<p>La seguridad es tu responsabilidad total en un entorno self-hosted. Una brecha de seguridad puede comprometer datos criticos de tu empresa. Implementa todas estas medidas como minimo.</p>
<h3>Firewall con UFW</h3>
<div class="code-block">
<code>
<span class="comment"># Instalar y configurar UFW</span>
<span class="command">sudo apt install ufw</span>
<span class="command">sudo ufw default deny incoming</span>
<span class="command">sudo ufw default allow outgoing</span>
<span class="command">sudo ufw allow ssh</span>
<span class="command">sudo ufw allow 'Nginx Full'</span>
<span class="command">sudo ufw enable</span>
<span class="comment"># IMPORTANTE: NO abrir puertos 8069/8072 directamente</span>
<span class="comment"># Todo el trafico debe pasar por Nginx</span>
</code>
</div>
<h3>Proteccion contra Fuerza Bruta con Fail2Ban</h3>
<div class="code-block">
<code>
<span class="comment"># Instalar fail2ban</span>
<span class="command">sudo apt install fail2ban</span>
<span class="comment"># Crear filtro para Odoo</span>
<span class="command">sudo nano /etc/fail2ban/filter.d/odoo.conf</span>
[Definition]
failregex = ^ \d+ INFO \S+ \S+ Login failed for db:\S+ login:\S+ from &lt;HOST&gt;
ignoreregex =
</code>
</div>
<div class="code-block">
<code>
<span class="comment"># Configurar jail para Odoo</span>
<span class="command">sudo nano /etc/fail2ban/jail.local</span>
[odoo]
enabled = true
port = http,https
filter = odoo
logpath = /var/log/odoo/odoo.log
maxretry = 5
findtime = 600
bantime = 3600
<span class="command">sudo systemctl restart fail2ban</span>
</code>
</div>
<h3>Actualizaciones Automaticas de Seguridad</h3>
<div class="code-block">
<code>
<span class="comment"># Instalar unattended-upgrades</span>
<span class="command">sudo apt install unattended-upgrades</span>
<span class="command">sudo dpkg-reconfigure -plow unattended-upgrades</span>
<span class="comment"># Verificar configuracion</span>
<span class="command">sudo nano /etc/apt/apt.conf.d/50unattended-upgrades</span>
</code>
</div>
<h3>Lista de Verificacion de Seguridad</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Medida</th>
<th>Prioridad</th>
<th>Estado</th>
</tr>
</thead>
<tbody>
<tr>
<td>SSL/TLS con certificado valido</td>
<td>Critica</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>Firewall UFW activo</td>
<td>Critica</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>Fail2Ban contra fuerza bruta</td>
<td>Alta</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>Actualizaciones automaticas</td>
<td>Alta</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>Master password fuerte</td>
<td>Critica</td>
<td class="check">Verificar</td>
</tr>
<tr>
<td>Backups cifrados externos</td>
<td>Critica</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>Monitoreo de logs</td>
<td>Media</td>
<td class="check">Configurar</td>
</tr>
<tr>
<td>SSH solo con clave (no password)</td>
<td>Alta</td>
<td class="check">Configurar</td>
</tr>
</tbody>
</table>
</section>
<!-- Maintenance Responsibilities -->
<section id="mantenimiento" class="content-section fade-in">
<h2>Responsabilidades de Mantenimiento Continuo</h2>
<p>El self-hosting no termina con la instalacion. El mantenimiento continuo es lo que realmente consume tiempo y recursos. A continuacion, detallamos las tareas recurrentes que deberas realizar.</p>
<h3>Tareas Diarias (Automatizables)</h3>
<ul>
<li><strong>Backup de base de datos:</strong> pg_dump automatizado con rotacion</li>
<li><strong>Backup de filestore:</strong> rsync o similar del directorio de datos</li>
<li><strong>Verificacion de logs:</strong> Alertas automaticas por errores criticos</li>
<li><strong>Monitoreo de espacio en disco:</strong> Alertar si supera 80%</li>
</ul>
<h3>Script de Backup Automatizado</h3>
<div class="code-block">
<code>
<span class="comment">#!/bin/bash</span>
<span class="comment"># /opt/odoo/scripts/backup.sh</span>
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/opt/odoo/backups
DB_NAME=tu_base_datos
<span class="comment"># Crear directorio si no existe</span>
mkdir -p $BACKUP_DIR
<span class="comment"># Backup PostgreSQL</span>
pg_dump -U odoo -h localhost $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz
<span class="comment"># Backup filestore</span>
tar -czf $BACKUP_DIR/filestore_$DATE.tar.gz /opt/odoo/.local/share/Odoo/filestore/$DB_NAME
<span class="comment"># Eliminar backups mayores a 7 dias</span>
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete
<span class="comment"># Sincronizar a almacenamiento externo (ejemplo S3)</span>
aws s3 sync $BACKUP_DIR s3://tu-bucket-backups/odoo/ --delete
</code>
</div>
<h3>Tareas Semanales</h3>
<ul>
<li><strong>Revisar actualizaciones de seguridad:</strong> Verificar que unattended-upgrades funciona</li>
<li><strong>Analizar metricas de rendimiento:</strong> Tiempos de respuesta, uso de recursos</li>
<li><strong>Verificar integridad de backups:</strong> Restaurar backup de prueba</li>
<li><strong>Revisar logs de fail2ban:</strong> Detectar patrones de ataque</li>
</ul>
<h3>Tareas Mensuales</h3>
<ul>
<li><strong>Actualizar Odoo:</strong> Aplicar parches de seguridad y bugs</li>
<li><strong>Optimizar PostgreSQL:</strong> VACUUM, ANALYZE, revisar indices</li>
<li><strong>Auditar accesos:</strong> Revisar usuarios y permisos en Odoo</li>
<li><strong>Renovar certificados SSL:</strong> Certbot lo hace automaticamente, pero verificar</li>
<li><strong>Probar recuperacion ante desastres:</strong> Simular restauracion completa</li>
</ul>
<h3>Estimacion de Tiempo de Mantenimiento</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Actividad</th>
<th>Frecuencia</th>
<th>Tiempo Estimado</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monitoreo y revision de alertas</td>
<td>Diario</td>
<td>15-30 min/dia</td>
</tr>
<tr>
<td>Actualizaciones y parches</td>
<td>Semanal</td>
<td>1-2 horas/semana</td>
</tr>
<tr>
<td>Optimizacion y mantenimiento DB</td>
<td>Mensual</td>
<td>2-4 horas/mes</td>
</tr>
<tr>
<td>Pruebas de backup/recovery</td>
<td>Mensual</td>
<td>1-2 horas/mes</td>
</tr>
<tr>
<td>Incidentes no planificados</td>
<td>Variable</td>
<td>2-8 horas/mes</td>
</tr>
<tr>
<td><strong>TOTAL ESTIMADO</strong></td>
<td>Mensual</td>
<td><strong>15-30 horas/mes</strong></td>
</tr>
</tbody>
</table>
</section>
<!-- Cost Analysis -->
<section id="analisis-costos" class="content-section fade-in">
<h2>Analisis de Costos: Self-Hosted vs Hosting Gestionado</h2>
<p>El costo real del self-hosting va mucho mas alla del precio del servidor. Es fundamental considerar el costo del tiempo de personal, que frecuentemente se subestima o ignora completamente.</p>
<h3>Costos de Self-Hosting (Desglose Mensual)</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Concepto</th>
<th>Rango Bajo</th>
<th>Rango Alto</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPS/Servidor (8GB RAM, 4 cores)</td>
<td>30 EUR</td>
<td>80 EUR</td>
</tr>
<tr>
<td>Almacenamiento backup externo</td>
<td>5 EUR</td>
<td>30 EUR</td>
</tr>
<tr>
<td>Dominio y DNS</td>
<td>2 EUR</td>
<td>5 EUR</td>
</tr>
<tr>
<td>Monitoreo (UptimeRobot, etc.)</td>
<td>0 EUR</td>
<td>20 EUR</td>
</tr>
<tr>
<td><strong>Subtotal Infraestructura</strong></td>
<td><strong>37 EUR</strong></td>
<td><strong>135 EUR</strong></td>
</tr>
<tr>
<td colspan="3" style="background: rgba(255,107,53,0.1);"><strong>Costo de Personal (el factor oculto)</strong></td>
</tr>
<tr>
<td>Mantenimiento (15-30h/mes x 40 EUR/h)</td>
<td>600 EUR</td>
<td>1,200 EUR</td>
</tr>
<tr>
<td><strong>TOTAL MENSUAL REAL</strong></td>
<td><strong>637 EUR</strong></td>
<td><strong>1,335 EUR</strong></td>
</tr>
</tbody>
</table>
<div class="warning-box">
<h4>El Costo Oculto del Tiempo</h4>
<p>Muchas empresas ignoran el costo del tiempo de su personal tecnico. Incluso si "ya tienes" un administrador de sistemas, las horas que dedica a Odoo son horas que no dedica a otras tareas. El costo de oportunidad es real.</p>
</div>
<h3>Comparativa con Hosting Gestionado</h3>
<table class="comparison-table">
<thead>
<tr>
<th>Aspecto</th>
<th>Self-Hosted</th>
<th>Hosting Gestionado</th>
</tr>
</thead>
<tbody>
<tr>
<td>Costo mensual (sin personal)</td>
<td>37-135 EUR</td>
<td>29-99 EUR</td>
</tr>
<tr>
<td>Costo mensual (con personal)</td>
<td>637-1,335 EUR</td>
<td>29-99 EUR</td>
</tr>
<tr>
<td>Tiempo de tu equipo</td>
<td>15-30 horas/mes</td>
<td>~0 horas/mes</td>
</tr>
<tr>
<td>Responsabilidad de seguridad</td>
<td>100% tuya</td>
<td>Del proveedor</td>
</tr>
<tr>
<td>Backups automaticos</td>
<td>Tu configuracion</td>
<td>Incluidos</td>
</tr>
<tr>
<td>Soporte tecnico</td>
<td>Comunidad/Pagado</td>
<td>Incluido 24/7</td>
</tr>
<tr>
<td>Actualizaciones</td>
<td>Manuales</td>
<td>Gestionadas</td>
</tr>
<tr>
<td>SLA de uptime</td>
<td>Sin garantia</td>
<td>99.9% tipico</td>
</tr>
</tbody>
</table>
<h3>Cuando el Self-Hosting es Mas Economico</h3>
<p>El self-hosting puede ser mas economico en estos escenarios especificos:</p>
<ul>
<li><strong>Ya tienes personal dedicado de IT:</strong> Y tiene capacidad ociosa significativa</li>
<li><strong>Escala muy grande:</strong> Mas de 200+ usuarios donde el hosting gestionado escala linealmente</li>
<li><strong>Infraestructura existente:</strong> Ya tienes data center propio amortizado</li>
<li><strong>Requisitos de latencia extrema:</strong> Necesitas el servidor fisicamente cerca</li>
</ul>
</section>
<!-- D3.js Cost Comparison Chart -->
<section class="chart-section fade-in">
<h3 id="grafico-costos">Comparativa de Costos: Self-Hosted vs Gestionado</h3>
<p>Este grafico compara el costo total de propiedad (TCO) a lo largo del tiempo entre self-hosting y hosting gestionado, considerando todos los costos ocultos.</p>
<div class="chart-container" id="cost-chart"></div>
</section>
<!-- Decision Matrix Chart -->
<section class="chart-section fade-in">
<h3 id="matriz-decision">Matriz de Decision: Que Opcion Elegir</h3>
<p>Visualiza como diferentes factores afectan la decision entre self-hosting y hosting gestionado segun tu situacion especifica.</p>
<div class="chart-container" id="decision-matrix"></div>
</section>
<!-- CTA Banner -->
<section class="cta-banner fade-in">
<h3>Prefiere Evitar la Complejidad del Self-Hosting?</h3>
<p>Odoo4projects ofrece hosting gestionado desde 29 euros/mes con backups automaticos, SSL incluido, soporte en espanol 24/7 y sin limites de usuarios. Enfocate en tu negocio, no en administrar servidores.</p>
<a href="https://odoo4projects.com" class="cta-btn" target="_blank" rel="noopener sponsored">Probar Gratis 14 Dias</a>
</section>
<!-- FAQ Section -->
<section id="faq" class="faq-section fade-in">
<h2>Preguntas Frecuentes sobre Odoo Self-Hosted</h2>
<div class="faq-item">
<div class="faq-question">Que requisitos de hardware necesita Odoo self-hosted?</div>
<div class="faq-answer">Para Odoo 18 Community necesitas minimo 4GB RAM, 2 CPU cores y 40GB SSD. Para produccion con 10-20 usuarios recomendamos 8GB RAM, 4 cores y 100GB NVMe. Enterprise requiere el doble de recursos debido a modulos adicionales.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cuanto cuesta mantener Odoo en servidor propio?</div>
<div class="faq-answer">El costo mensual incluye: servidor VPS (20-100 euros), tiempo de administracion (15-30 horas/mes valoradas en 600-1200 euros), backups externos (5-20 euros) y licencias si usas Enterprise. Total estimado real: 637-1335 euros/mes considerando tiempo de personal.</div>
</div>
<div class="faq-item">
<div class="faq-question">Es seguro alojar Odoo en mi propio servidor?</div>
<div class="faq-answer">Si, puede ser muy seguro si implementas correctamente: firewall UFW, SSL/TLS con Let's Encrypt, actualizaciones automaticas de seguridad, backups cifrados, fail2ban contra ataques de fuerza bruta, y auditorias periodicas. Sin estos controles, es mas arriesgado que hosting gestionado.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cuando tiene sentido el self-hosting de Odoo?</div>
<div class="faq-answer">El self-hosting tiene sentido cuando: tienes equipo tecnico con experiencia en Linux/PostgreSQL, necesitas personalizaciones profundas del sistema, tienes requisitos de cumplimiento que exigen control total de datos, o manejas volumenes muy altos donde el ahorro compensa el esfuerzo.</div>
</div>
<div class="faq-item">
<div class="faq-question">Que sistema operativo es mejor para Odoo self-hosted?</div>
<div class="faq-answer">Ubuntu Server LTS (22.04 o 24.04) es la opcion mas recomendada por su estabilidad, soporte a largo plazo y documentacion abundante. Debian 12 es otra excelente opcion. No recomendamos CentOS/RHEL para nuevas instalaciones debido a cambios en su modelo de soporte.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como hacer backups de Odoo self-hosted?</div>
<div class="faq-answer">Necesitas respaldar: 1) Base de datos PostgreSQL con pg_dump diario, 2) Filestore completo (archivos adjuntos), 3) Configuracion del servidor, 4) Modulos personalizados. Usa la regla 3-2-1: 3 copias, 2 medios diferentes, 1 ubicacion externa. Automatiza con scripts cron y almacena en S3, Backblaze o similar.</div>
</div>
<div class="faq-item">
<div class="faq-question">Puedo migrar de hosting gestionado a self-hosted?</div>
<div class="faq-answer">Si, la migracion implica: exportar base de datos PostgreSQL desde el proveedor actual, copiar el filestore completo, replicar la configuracion del servidor en tu infraestructura, y restaurar. El proceso puede tomar 2-8 horas dependiendo del tamano de datos. Planifica una ventana de mantenimiento.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cuantos usuarios soporta un servidor Odoo self-hosted?</div>
<div class="faq-answer">Depende de la configuracion: servidor de 4GB RAM soporta 10-20 usuarios simultaneos, 8GB soporta 30-50 usuarios, 16GB+ soporta 100+ usuarios. La clave esta en configurar correctamente los workers de Odoo segun la formula: (CPU cores x 2) + 1 workers.</div>
</div>
</section>
<!-- Related Articles -->
<section id="relacionados" class="content-section fade-in">
<h2>Articulos Relacionados</h2>
<div class="related-articles">
<a href="/pt/odoo-hosting/mejor-hosting-odoo-2026/" class="related-card">
<div class="related-card-image">*</div>
<div class="related-card-content">
<h4>Mejor Hosting Odoo 2026: Comparativa</h4>
<p>Analisis de 15+ proveedores de hosting gestionado</p>
</div>
</a>
<a href="/pt/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="/pt/odoo-hosting/requisitos-hosting-odoo-servidor-2025/" class="related-card">
<div class="related-card-image">REQ</div>
<div class="related-card-content">
<h4>Requisitos Tecnicos para Odoo</h4>
<p>Especificaciones de servidor recomendadas</p>
</div>
</a>
<a href="/pt/odoo-hosting/precios-hosting-odoo-costos-2025/" class="related-card">
<div class="related-card-image">$</div>
<div class="related-card-content">
<h4>Precios de Hosting Odoo</h4>
<p>Comparativa detallada de costos</p>
</div>
</a>
<a href="/pt/odoo-hosting/odoo-sh-hosting-oficial-plataforma-2025/" class="related-card">
<div class="related-card-image">SH</div>
<div class="related-card-content">
<h4>Odoo.sh: Analisis Completo</h4>
<p>Todo sobre la plataforma oficial de Odoo</p>
</div>
</a>
<a href="/pt/odoo-hosting/hosting-odoo-espana-proveedores-2025/" class="related-card">
<div class="related-card-image">ES</div>
<div class="related-card-content">
<h4>Hosting Odoo en Espana</h4>
<p>Proveedores locales con soporte en espanol</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="/pt/">Inicio</a><a href="/pt/odoo/">Odoo</a><a href="/pt/odoo-ia/">Odoo IA</a><a href="/pt/odoo-hosting/">Hospedagem Odoo</a><a href="/pt/mapa-del-sitio/">Mapa do Site</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div><nav class="footer-nav"><a href="/pt/">Inicio</a><a href="/pt/odoo/">Odoo</a><a href="/pt/odoo-ia/">Odoo IA</a><a href="/pt/odoo-hosting/">Hospedagem Odoo</a><a href="/pt/mapa-del-sitio/">Mapa do Site</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');
});
});
// Tooltip
const tooltip = d3.select('body').append('div')
.attr('class', 'd3-tooltip')
.style('opacity', 0);
// Color scale
const colorScale = d3.scaleOrdinal()
.range(['#FF6B35', '#FF8A50', '#FFA726', '#FFB74D', '#4CAF50', '#2196F3', '#9C27B0']);
// Resources vs Users Chart
function renderResourcesChart() {
const container = d3.select('#resources-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = { top: 40, right: 100, bottom: 60, left: 70 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
// Data: users vs resources
const data = [
{ users: 5, ram: 4, cpu: 2, storage: 40 },
{ users: 10, ram: 6, cpu: 2, storage: 60 },
{ users: 20, ram: 8, cpu: 4, storage: 100 },
{ users: 30, ram: 12, cpu: 4, storage: 150 },
{ users: 50, ram: 16, cpu: 6, storage: 200 },
{ users: 75, ram: 24, cpu: 8, storage: 300 },
{ users: 100, ram: 32, cpu: 8, storage: 400 },
{ users: 150, ram: 48, cpu: 12, storage: 600 },
{ users: 200, ram: 64, cpu: 16, storage: 800 }
];
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.users)])
.range([margin.left, width - margin.right]);
const yScaleRAM = d3.scaleLinear()
.domain([0, d3.max(data, d => d.ram)])
.range([height - margin.bottom, margin.top]);
// Grid
svg.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickSize(-(height - margin.top - margin.bottom)).tickFormat(''))
.selectAll('line').attr('stroke', '#333');
// X Axis
svg.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickFormat(d => d + ' usuarios'))
.attr('color', '#888');
// Y Axis
svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScaleRAM).tickFormat(d => d + ' GB'))
.attr('color', '#888');
// Axis labels
svg.append('text')
.attr('x', width / 2)
.attr('y', height - 10)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('Usuarios Concurrentes');
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -height / 2)
.attr('y', 20)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('RAM Requerida (GB)');
// Line
const line = d3.line()
.x(d => xScale(d.users))
.y(d => yScaleRAM(d.ram))
.curve(d3.curveMonotoneX);
const path = svg.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', '#FF6B35')
.attr('stroke-width', 3)
.attr('d', line);
// Animate line
const totalLength = path.node().getTotalLength();
path
.attr('stroke-dasharray', totalLength)
.attr('stroke-dashoffset', totalLength)
.transition()
.duration(2000)
.ease(d3.easeLinear)
.attr('stroke-dashoffset', 0);
// Area
const area = d3.area()
.x(d => xScale(d.users))
.y0(height - margin.bottom)
.y1(d => yScaleRAM(d.ram))
.curve(d3.curveMonotoneX);
svg.append('path')
.datum(data)
.attr('fill', 'rgba(255,107,53,0.2)')
.attr('d', area)
.attr('opacity', 0)
.transition()
.delay(1000)
.duration(1000)
.attr('opacity', 1);
// Points
svg.selectAll('circle')
.data(data)
.join('circle')
.attr('cx', d => xScale(d.users))
.attr('cy', d => yScaleRAM(d.ram))
.attr('r', 0)
.attr('fill', '#FF6B35')
.attr('stroke', '#fff')
.attr('stroke-width', 2)
.style('cursor', 'pointer')
.on('mouseover', function(event, d) {
d3.select(this).attr('r', 10);
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${d.users} usuarios</strong><br>RAM: ${d.ram} GB<br>CPU: ${d.cpu} cores<br>Storage: ${d.storage} GB`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).attr('r', 6);
tooltip.transition().duration(200).style('opacity', 0);
})
.transition()
.delay((d, i) => 1500 + i * 100)
.duration(300)
.attr('r', 6);
// Legend
const legend = svg.append('g')
.attr('transform', `translate(${width - margin.right + 10}, ${margin.top})`);
legend.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('fill', '#FF6B35');
legend.append('text')
.attr('x', 22)
.attr('y', 12)
.attr('fill', '#b0b0b0')
.attr('font-size', '12px')
.text('RAM (GB)');
}
// Cost Comparison Chart
function renderCostChart() {
const container = d3.select('#cost-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = { top: 40, right: 120, bottom: 60, left: 80 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
// Data: months vs cumulative cost
const months = [0, 3, 6, 9, 12, 18, 24, 36];
const selfHostedCosts = months.map(m => ({ month: m, cost: m * 800, type: 'Self-Hosted (con personal)' }));
const managedCosts = months.map(m => ({ month: m, cost: m * 59, type: 'Hosting Gestionado' }));
const selfHostedInfraCosts = months.map(m => ({ month: m, cost: m * 60, type: 'Self-Hosted (solo infra)' }));
const allData = [...selfHostedCosts, ...managedCosts, ...selfHostedInfraCosts];
const xScale = d3.scaleLinear()
.domain([0, 36])
.range([margin.left, width - margin.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(allData, d => d.cost)])
.range([height - margin.bottom, margin.top]);
// Grid
svg.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickSize(-(height - margin.top - margin.bottom)).tickFormat(''))
.selectAll('line').attr('stroke', '#333');
// X Axis
svg.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickFormat(d => d + ' meses'))
.attr('color', '#888');
// Y Axis
svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale).tickFormat(d => d.toLocaleString() + ' EUR'))
.attr('color', '#888');
// Axis labels
svg.append('text')
.attr('x', width / 2)
.attr('y', height - 10)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('Tiempo');
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -height / 2)
.attr('y', 20)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('Costo Acumulado');
const colors = {
'Self-Hosted (con personal)': '#f44336',
'Hosting Gestionado': '#4CAF50',
'Self-Hosted (solo infra)': '#FF6B35'
};
// Lines
const line = d3.line()
.x(d => xScale(d.month))
.y(d => yScale(d.cost))
.curve(d3.curveMonotoneX);
const datasets = [
{ data: selfHostedCosts, key: 'Self-Hosted (con personal)' },
{ data: managedCosts, key: 'Hosting Gestionado' },
{ data: selfHostedInfraCosts, key: 'Self-Hosted (solo infra)' }
];
datasets.forEach((dataset, idx) => {
const path = svg.append('path')
.datum(dataset.data)
.attr('fill', 'none')
.attr('stroke', colors[dataset.key])
.attr('stroke-width', 3)
.attr('d', line);
const totalLength = path.node().getTotalLength();
path
.attr('stroke-dasharray', totalLength)
.attr('stroke-dashoffset', totalLength)
.transition()
.duration(1500)
.delay(idx * 300)
.ease(d3.easeLinear)
.attr('stroke-dashoffset', 0);
});
// Legend
const legend = svg.append('g')
.attr('transform', `translate(${width - margin.right + 10}, ${margin.top})`);
Object.entries(colors).forEach(([key, color], i) => {
const g = legend.append('g')
.attr('transform', `translate(0, ${i * 25})`);
g.append('line')
.attr('x1', 0)
.attr('x2', 20)
.attr('y1', 7)
.attr('y2', 7)
.attr('stroke', color)
.attr('stroke-width', 3);
g.append('text')
.attr('x', 28)
.attr('y', 12)
.attr('fill', '#b0b0b0')
.attr('font-size', '11px')
.text(key);
});
}
// Decision Matrix Chart
function renderDecisionMatrix() {
const container = d3.select('#decision-matrix');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = { top: 80, right: 30, bottom: 30, left: 180 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
const factors = [
'Equipo tecnico disponible',
'Presupuesto mensual',
'Necesidad de personalizacion',
'Tiempo disponible admin',
'Requisitos de cumplimiento',
'Numero de usuarios'
];
const scenarios = ['Self-Hosted', 'Gestionado'];
// Higher = better for that option
const data = [
[90, 30], // Equipo tecnico: self-hosted mejor si tienes
[40, 85], // Presupuesto: gestionado mejor para bajo presupuesto
[95, 60], // Personalizacion: self-hosted mucho mejor
[25, 95], // Tiempo admin: gestionado mucho mejor
[85, 50], // Cumplimiento: self-hosted mejor control
[70, 80] // Usuarios: gestionado escala mejor
];
const xScale = d3.scaleBand()
.domain(scenarios)
.range([margin.left, width - margin.right])
.padding(0.15);
const yScale = d3.scaleBand()
.domain(factors)
.range([margin.top, height - margin.bottom])
.padding(0.1);
const colorHeat = d3.scaleSequential()
.domain([0, 100])
.interpolator(d3.interpolateRgb('#2a2a2a', '#4CAF50'));
// X axis
svg.append('g')
.attr('transform', `translate(0,${margin.top - 10})`)
.call(d3.axisTop(xScale))
.selectAll('text')
.attr('fill', '#b0b0b0')
.attr('font-size', '14px')
.attr('font-weight', '600');
svg.selectAll('.domain').remove();
// Y axis
svg.append('g')
.attr('transform', `translate(${margin.left - 10},0)`)
.call(d3.axisLeft(yScale))
.selectAll('text')
.attr('fill', '#b0b0b0')
.attr('font-size', '12px');
// Cells
factors.forEach((factor, i) => {
scenarios.forEach((scenario, j) => {
const value = data[i][j];
const cell = svg.append('rect')
.attr('x', xScale(scenario))
.attr('y', yScale(factor))
.attr('width', xScale.bandwidth())
.attr('height', yScale.bandwidth())
.attr('fill', colorHeat(value))
.attr('rx', 6)
.attr('opacity', 0)
.style('cursor', 'pointer');
cell.on('mouseover', function(event) {
d3.select(this).attr('stroke', '#fff').attr('stroke-width', 2);
const recommendation = value >= 70 ? 'Recomendado' : value >= 40 ? 'Aceptable' : 'No recomendado';
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${scenario}</strong><br>${factor}<br>Puntuacion: ${value}/100<br>${recommendation}`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).attr('stroke', 'none');
tooltip.transition().duration(200).style('opacity', 0);
});
cell.transition()
.duration(400)
.delay((i * 2 + j) * 80)
.attr('opacity', 1);
// Value text
svg.append('text')
.attr('x', xScale(scenario) + xScale.bandwidth() / 2)
.attr('y', yScale(factor) + yScale.bandwidth() / 2)
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.attr('fill', value > 50 ? '#fff' : '#888')
.attr('font-size', '16px')
.attr('font-weight', '600')
.attr('opacity', 0)
.text(value)
.transition()
.duration(300)
.delay((i * 2 + j) * 80 + 200)
.attr('opacity', 1);
});
});
// Legend
const legendWidth = 200;
const legendHeight = 15;
const legendX = margin.left;
const legendY = height - 20;
const legendScale = d3.scaleLinear()
.domain([0, 100])
.range([0, legendWidth]);
const legendAxis = d3.axisBottom(legendScale)
.ticks(5)
.tickFormat(d => d);
// Gradient
const defs = svg.append('defs');
const gradient = defs.append('linearGradient')
.attr('id', 'legend-gradient');
gradient.append('stop')
.attr('offset', '0%')
.attr('stop-color', '#2a2a2a');
gradient.append('stop')
.attr('offset', '100%')
.attr('stop-color', '#4CAF50');
svg.append('rect')
.attr('x', legendX)
.attr('y', legendY - legendHeight)
.attr('width', legendWidth)
.attr('height', legendHeight)
.attr('fill', 'url(#legend-gradient)')
.attr('rx', 3);
svg.append('text')
.attr('x', legendX + legendWidth + 10)
.attr('y', legendY - 3)
.attr('fill', '#888')
.attr('font-size', '11px')
.text('Recomendacion');
}
// Initialize charts when visible
const chartObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.id;
setTimeout(() => {
if (id === 'resources-chart') renderResourcesChart();
if (id === 'cost-chart') renderCostChart();
if (id === 'decision-matrix') renderDecisionMatrix();
}, 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(() => {
renderResourcesChart();
renderCostChart();
renderDecisionMatrix();
}, 300);
});
</script>
</body>
</html>