Guía corporativa TEMA para hosting en DigitalOcean con Django, React, Next.js y PostgreSQL

TEMA · Guía técnica interna de infraestructura

Lleva tus desarrollos a la nube con DigitalOcean

Del hosting compartido de Hostinger a infraestructura en la nube que escala. Una guía práctica del equipo TEMA para comprar, crear, administrar y gestionar hosting, y desplegar rápido tus aplicaciones de Django, React, Next.js y PostgreSQL con dominios y subdominios propios.

Ubuntu 24.04 LTS Nginx + Gunicorn PostgreSQL PM2 Node/Next Certbot HTTPS
15
secciones paso a paso
4
stacks: Django · React · Next · PSQL
~13USD
al mes para arrancar
subdominios en un Droplet

Punto de partida

De Hostinger a DigitalOcean, sin perderte

El cambio mental es uno solo: Hostinger te da un espacio dentro de un servidor ya montado; DigitalOcean te da el servidor entero y tú lo montas. Ganas control total y capacidad de escalar; a cambio, administras el sistema. Esta guía es el plano de obra.

AspectoHostinger (compartido)DigitalOcean
ModeloHosting compartido gestionado (hPanel)Servidores propios (Droplets) por SSH · también PaaS
Acceso raízLimitado / noControl total (root)
Django / Node en producciónComplicado o limitadoNativo (Gunicorn, PM2)
PostgreSQLNormalmente solo MySQLPostgres local o gestionado
EscalarCambiar de planRedimensionar, balanceadores, réplicas
FacturaciónPor plan anual/mensualPor hora, con tope mensual
Curva de aprendizajeBajaMedia (esta guía la aplana)

Elige tu camino

Dos formas de desplegar

Camino A · Control

Droplet (VPS)

Un servidor Linux que administras tú. Máximo control y el mejor costo cuando alojas varias apps. Es el 80% de esta guía. Recomendado para TEMA.

Camino B · Velocidad

App Platform (PaaS)

Conectas tu repositorio de GitHub y DigitalOcean construye y despliega solo. Sin administrar servidor. Ideal para arrancar un prototipo hoy mismo.

01Conceptos y glosario esencial

DigitalOcean tiene su propio vocabulario. Con estos términos claros, el resto de la guía fluye sin fricción.

TérminoQué esEquivalente mental
DropletMáquina virtual Linux (tu servidor): CPU, RAM, disco y región.Un VPS / tu "PC en la nube"
Managed DatabasePostgreSQL administrado por DO: backups, parches y alta disponibilidad.Base de datos sin preocupaciones
App PlatformConstruye y despliega desde tu repo Git (PaaS).Como Vercel / Heroku en DO
SpacesAlmacenamiento de objetos compatible con S3.Disco para imágenes y archivos
SnapshotFoto completa del Droplet para restaurar o clonar.Copia de seguridad de sistema
Reserved IPIP fija reasignable entre Droplets sin tocar el DNS.IP estática móvil
ProjectCarpeta lógica para agrupar recursos por cliente o app.Una carpeta de proyecto
RegiónUbicación física (NYC, AMS, FRA, LON…).Dónde vive tu servidor
Regiones para LATAM y Europa. Para usuarios en LATAM, NYC1/NYC3 (Nueva York) suele dar buena latencia. Para Europa, AMS3 (Ámsterdam), FRA1 (Fráncfort) o LON1 (Londres). No hay datacenter en Sudamérica, así que NYC es el equilibrio habitual.

02Crear cuenta, pago y facturación

  1. Regístrate

    En digitalocean.com con correo, GitHub o Google. Verifica el correo.

  2. Agrega método de pago

    Tarjeta o PayPal. DO pide una verificación inicial pequeña (se reembolsa). Sin pago válido no se crean Droplets.

  3. Entiende la facturación por horas

    Se cobra por hora de uso con tope mensual. Apagar el Droplet NO detiene el cobro: para dejar de pagar hay que destruirlo (haz un snapshot antes si quieres conservarlo).

  4. Activa alertas de presupuesto

    En Billing → Billing alerts define un monto (p. ej. USD 30) para recibir aviso si el gasto lo supera.

  5. Organiza con Projects

    Un Project por cliente o app: cada Droplet, base de datos y dominio queda agrupado y es fácil de rastrear.

Ojo con el crédito de bienvenida. Si usas un código promocional, el crédito caduca. Cuando se agota o vence, empieza el cobro real a tu tarjeta. Revisa Billing periódicamente.

03Crear tu primer Droplet

El Droplet es tu servidor. Lo crearemos con Ubuntu, la distribución más documentada y la que asumen casi todos los tutoriales de Django y Node.

Antes de empezar: crea tu llave SSH

La forma segura de entrar es con llave SSH, no con contraseña. Genera el par de llaves en tu computadora:

tu-máquina · Git Bash / PowerShell / macOS
$ ssh-keygen -t ed25519 -C 'tu-correo@tema.com.pe'
# Enter para la ruta por defecto (~/.ssh/id_ed25519). Opcional: passphrase
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1... tu-correo@tema.com.pe
Windows. Usa PowerShell o Git Bash; ambos traen ssh-keygen. La llave pública (.pub) se comparte; la privada nunca se comparte ni se sube a ningún repositorio.

Crear el Droplet en el panel

  1. Create → Droplets

    Botón verde Create (arriba a la derecha) → Droplets.

  2. Región

    La más cercana a tus usuarios. Para LATAM: New York.

  3. Imagen del SO

    Ubuntu 24.04 (LTS) x64.

  4. Tamaño

    Shared CPU → Basic → Regular. Para 1–2 apps: 2 GB RAM / 1 vCPU / 50 GB (~USD 12/mes). Django + Postgres agradecen 2 GB.

  5. Autenticación

    SSH Key → Add SSH Key y pega tu llave pública. Evita la opción de contraseña.

  6. Nombre y proyecto

    Un hostname claro (web-prod-01) y asígnalo a un Project. Activa Improved metrics.

  7. Create Droplet

    En ~1 minuto tendrás una IP pública (ej. 159.65.xx.xx). Cópiala.

tu-máquina · conectar
$ ssh root@159.65.XX.XX
# Primera vez: pregunta la huella del host → escribe: yes
Welcome to Ubuntu 24.04 LTS ...
root@web-prod-01:~#
¡Estás dentro! El prompt root@web-prod-01:~# significa que ya controlas el servidor. Todo lo siguiente se ejecuta dentro de esta sesión SSH.

04Asegurar el servidor

Un Droplet recién creado está expuesto a internet como root. Cinco minutos de configuración evitan el 90% de los problemas.

1 · Actualiza el sistema

servidor · root
# apt update && apt upgrade -y

2 · Crea un usuario con sudo (deja de usar root)

servidor · root
# adduser deploy            # define contraseña (Enter en el resto)
# usermod -aG sudo deploy    # permisos de administrador
# rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

3 · Activa el firewall (UFW)

servidor · deploy
$ sudo ufw allow OpenSSH        # puerto 22 (SSH) — ¡no te encierres fuera!
$ sudo ufw allow 'Nginx Full'   # puertos 80 y 443
$ sudo ufw enable
$ sudo ufw status
Regla de oro. Habilita siempre OpenSSH antes de ufw enable. Si activas el firewall sin permitir SSH, perderás el acceso y tendrás que usar la consola de recuperación del panel.
Cloud Firewall (gratis). Además de UFW, DO ofrece un firewall en el panel (Networking → Firewalls) que filtra antes de llegar al Droplet. Puedes usar ambos.

05Dominios y subdominios (DNS)

Aquí conectas tus dominios con el servidor. La idea central: un registro A asocia un nombre (dominio o subdominio) con la IP de tu Droplet. Un solo servidor puede responder a decenas de subdominios.

Un Droplet con una IP sirviendo varios subdominios mediante Nginx Droplet Nginx · 159.65.XX.XX DNS · registros A app.tema.com.pe api.tema.com.pe Django · Gunicorn Next.js · :3000 React · estático Subdominios (entran) Apps (Nginx reparte)
Una IP · un Droplet · muchos subdominios, cada uno enrutado por Nginx a la app correcta

Paso 1 · Apunta el dominio a los nameservers de DO

En el panel de donde compraste el dominio (Namecheap, GoDaddy, Hostinger…), cambia los nameservers:

nameservers de DigitalOcean
ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com
¿Qué hace esto? Le dice a internet: "quien administra las direcciones de este dominio es DigitalOcean". La propagación tarda de minutos a 24–48 h.

Paso 2 · Crea los registros en DigitalOcean

Panel → Networking → Domains → añade tema.com.pe y crea los registros:

TipoHostnameValorResultado
A@159.65.XX.XXtema.com.pe
Awww159.65.XX.XXwww.tema.com.pe
Aapp159.65.XX.XXSubdominio app.tema.com.pe
Aapi159.65.XX.XXSubdominio api.tema.com.pe
Subdominios = un registro A cada uno. Cada subdominio nuevo apunta a la misma IP. Luego, en Nginx, decides qué app responde a cada uno. Así alojas muchas apps en un solo Droplet.
tu-máquina · comprobar propagación
$ dig +short app.tema.com.pe
159.65.XX.XX
# En Windows PowerShell:
> Resolve-DnsName tema.com.pe

06Instalar el stack

Con el servidor asegurado y el DNS apuntando, instalamos las piezas. Nginx será el portero que recibe todo el tráfico web y lo reparte a cada app.

Nginx (servidor web / reverse proxy)

servidor · deploy
$ sudo apt install -y nginx
$ systemctl status nginx    # debe verse 'active (running)'

Visita http://159.65.XX.XX: verás "Welcome to nginx". Eso confirma firewall y web server.

Python (Django) y Node (React/Next)

servidor · deploy
# Python + compilación (Django + psycopg2)
$ sudo apt install -y python3 python3-venv python3-pip build-essential libpq-dev

# Node.js LTS (repositorio oficial)
$ curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
$ sudo apt install -y nodejs
$ node --version && npm --version
v22.x.x   10.x.x

PostgreSQL (opción autogestionada)

servidor · deploy
$ sudo apt install -y postgresql postgresql-contrib
$ sudo -u postgres psql    # consola de Postgres
postgres=# · crear base y usuario
CREATE DATABASE miapp;
CREATE USER miapp_user WITH PASSWORD 'una-clave-fuerte';
ALTER ROLE miapp_user SET client_encoding TO 'utf8';
ALTER ROLE miapp_user SET timezone TO 'America/Lima';
GRANT ALL PRIVILEGES ON DATABASE miapp TO miapp_user;
\q

07Desplegar Django en producción

Arquitectura estándar: Nginx recibe HTTP → Gunicorn ejecuta Django → PostgreSQL guarda los datos. Nginx sirve los estáticos y systemd mantiene todo vivo.

1 · Sube el código y crea el entorno

servidor · deploy
$ cd /home/deploy
$ git clone https://github.com/tu-usuario/mi-django-app.git
$ cd mi-django-app
$ python3 -m venv venv && source venv/bin/activate
(venv) $ pip install -r requirements.txt
(venv) $ pip install gunicorn psycopg2-binary

2 · Ajusta settings.py y migra

settings.py · producción
ALLOWED_HOSTS = ['app.tema.com.pe', '159.65.XX.XX']
DEBUG = False
DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': 'miapp', 'USER': 'miapp_user',
    'PASSWORD': 'una-clave-fuerte',   # usa variables de entorno
    'HOST': 'localhost', 'PORT': '5432',
  }
}
STATIC_ROOT = '/home/deploy/mi-django-app/staticfiles'
servidor · (venv) deploy
(venv) $ python manage.py migrate
(venv) $ python manage.py collectstatic --noinput
(venv) $ python manage.py createsuperuser

3 · Servicio systemd para Gunicorn

/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon para mi-django-app
After=network.target

[Service]
User=deploy
Group=www-data
WorkingDirectory=/home/deploy/mi-django-app
ExecStart=/home/deploy/mi-django-app/venv/bin/gunicorn \
          --workers 3 \
          --bind unix:/home/deploy/mi-django-app/app.sock \
          miproyecto.wsgi:application

[Install]
WantedBy=multi-user.target
servidor · deploy
$ sudo systemctl start gunicorn
$ sudo systemctl enable gunicorn   # arranca solo al reiniciar
$ sudo systemctl status gunicorn

4 · Bloque de Nginx para el subdominio

/etc/nginx/sites-available/app.tema.com.pe
server {
    listen 80;
    server_name app.tema.com.pe;

    location /static/ {
        alias /home/deploy/mi-django-app/staticfiles/;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/deploy/mi-django-app/app.sock;
    }
}
servidor · activar el sitio
$ sudo ln -s /etc/nginx/sites-available/app.tema.com.pe /etc/nginx/sites-enabled/
$ sudo nginx -t          # debe decir: test is successful
$ sudo systemctl restart nginx
Ya sirve. http://app.tema.com.pe muestra tu Django. Falta el HTTPS (sección 10). Tras cada cambio de código: git pullpip installmigratecollectstaticsudo systemctl restart gunicorn.

08Desplegar React y Next.js

Se despliegan distinto porque son cosas distintas: React (Vite/CRA) compila a archivos estáticos que Nginx sirve directo; Next.js corre un servidor Node vivo (SSR/API), gestionado con PM2.

Caso A · React — sitio estático

servidor · deploy
$ cd /home/deploy
$ git clone https://github.com/tu-usuario/mi-react-app.git
$ cd mi-react-app && npm install && npm run build
/etc/nginx/sites-available/web.tema.com.pe
server {
    listen 80;
    server_name web.tema.com.pe;
    root /home/deploy/mi-react-app/dist;
    index index.html;
    location / {
        try_files $uri $uri/ /index.html;   # clave para React Router (SPA)
    }
}
El truco de try_files. En una SPA, toda ruta (/panel, /perfil) debe servir index.html para que React Router se encargue. Sin esa línea, recargar una ruta interna da 404.

Caso B · Next.js — servidor Node con PM2

servidor · deploy
$ sudo npm install -g pm2
$ cd /home/deploy/mi-next-app
$ npm install && npm run build
$ pm2 start npm --name 'next-app' -- start   # Next en :3000
$ pm2 save
$ pm2 startup     # ejecuta la línea que imprime
/etc/nginx/sites-available/next.tema.com.pe
server {
    listen 80;
    server_name next.tema.com.pe;
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Varias apps, un Droplet. Cada app corre en su puerto (Django en su socket, Next en :3000, otra en :3001…) y cada subdominio tiene su bloque de Nginx apuntando a la app correcta. Así conviven Django, React y Next en el mismo servidor.
Comando PM2Para qué
pm2 listVer todas las apps y su estado
pm2 logs next-appLogs en vivo
pm2 restart next-appReiniciar tras un despliegue
pm2 monitMonitor de CPU/RAM por proceso

09PostgreSQL: gestionado vs. autogestionado

Postgres en el mismo Droplet es lo más barato para empezar. Cuando el proyecto es serio, la Managed Database ahorra dolores de cabeza: backups automáticos, parches y failover.

En el DropletManaged Database
CostoIncluido en el DropletDesde ~USD 15/mes aparte
Backups automáticosLos configuras túIncluidos (point-in-time)
Parches / actualizacionesManualesAutomáticos
Alta disponibilidadNoNodos de reserva opcionales
Ideal paraPrototipos, presupuesto ajustadoProducción real, datos críticos
settings.py · Managed Database (SSL)
DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': 'defaultdb', 'USER': 'doadmin',
    'PASSWORD': 'xxxxxxxx',
    'HOST': 'db-postgresql-nyc1-xxxx.ondigitalocean.com',
    'PORT': '25060',
    'OPTIONS': {'sslmode': 'require'},
  }
}
No pongas contraseñas en el código. Usa variables de entorno (.env con python-dotenv) y añade ese archivo a .gitignore. En Settings → Trusted Sources de la Managed DB, permite solo tu Droplet.

10HTTPS gratis con Let's Encrypt

Sin candado, los navegadores marcan el sitio como "no seguro". Certbot instala un certificado gratuito y lo renueva solo.

servidor · deploy
$ sudo apt install -y certbot python3-certbot-nginx
$ sudo certbot --nginx -d app.tema.com.pe -d www.tema.com.pe
# Pide correo, aceptas términos y eliges redirigir HTTP → HTTPS
$ sudo certbot renew --dry-run   # prueba la renovación automática
Congratulations! ... https://app.tema.com.pe
Un subdominio nuevo = un certbot más. Repite sudo certbot --nginx -d nuevo.tema.com.pe, o incluye varios -d en un solo comando. Certbot edita Nginx y programa la renovación por ti.

11App Platform: desplegar sin servidor

Si prefieres velocidad sobre control, App Platform es lo más parecido a Vercel/Heroku dentro de DO: conectas GitHub y cada git push despliega solo. Sin SSH, sin Nginx, sin Certbot.

  1. Create → Apps

    Conecta GitHub/GitLab y elige repositorio y rama (main).

  2. DO detecta el tipo

    Reconoce Django, Node/Next, React… Confirma los comandos de build y run.

  3. Variables de entorno

    Agrega SECRET_KEY, DATABASE_URL… como encrypted env vars. Vincula una Managed DB con un clic.

  4. Dominio

    Da una URL *.ondigitalocean.app con HTTPS. Añade tu dominio en Settings → Domains y crea el CNAME indicado.

  5. Deploy

    Cada push reconstruye y redespliega automáticamente.

Estrategia mixta muy común. Front (React/Next) en App Platform + backend Django y PostgreSQL en un Droplet o Managed Database. No estás obligado a elegir uno solo.

12Administrar, monitorear y escalar

Backups y snapshots

Automático

Droplet Backups

~20% del costo. Copias semanales automáticas para restaurar todo el servidor.

Manual

Snapshots

Foto puntual del Droplet. Úsalo antes de cambios grandes o para clonar.

Base de datos

Managed backups

Backups diarios con restauración point-in-time, sin que hagas nada.

Monitoreo

La pestaña Monitoring muestra CPU, memoria, disco y red. Crea alertas (Monitoring → Create Alert Policy). Dentro del servidor:

servidor · diagnóstico
$ htop            # procesos, CPU y RAM en vivo
$ df -h           # espacio en disco
$ free -h         # memoria disponible
$ sudo journalctl -u gunicorn -n 50 --no-pager   # logs de Django
$ sudo tail -f /var/log/nginx/error.log          # errores de Nginx

Escalar cuando crezcas

NecesidadSolución en DO
Más CPU/RAMResize del Droplet (el de solo CPU/RAM es reversible; el de disco no)
Más almacenamientoConectar un Volume (disco adicional)
Mucho tráficoVarios Droplets tras un Load Balancer
Archivos / mediaSpaces (S3) + CDN
IP fija reasignableReserved IP para migrar sin tocar el DNS

Actualizar una app ya desplegada

servidor · flujo de actualización
# Django
$ cd /home/deploy/mi-django-app && source venv/bin/activate
$ git pull && pip install -r requirements.txt
$ python manage.py migrate && python manage.py collectstatic --noinput
$ sudo systemctl restart gunicorn

# Next.js
$ cd /home/deploy/mi-next-app
$ git pull && npm install && npm run build
$ pm2 restart next-app

13Checklist de seguridad

Marca esto en cada servidor nuevo. Son las prácticas que separan un servidor sano de uno comprometido.

  • Acceso solo por llave SSH. Desactiva contraseñas en /etc/ssh/sshd_config (PasswordAuthentication no).
  • No usar root a diario. Trabaja con deploy y sudo.
  • Firewall activo (UFW y/o Cloud Firewall): solo 22, 80 y 443.
  • Base de datos no expuesta. Postgres en localhost, o Managed DB restringida a Trusted Sources.
  • HTTPS en todo con Certbot y redirección de HTTP a HTTPS.
  • Secretos fuera de Git: SECRET_KEY, contraseñas y tokens en variables de entorno.
  • DEBUG = False en producción, con ALLOWED_HOSTS bien definido.
  • Actualizaciones regulares; considera unattended-upgrades y fail2ban.
  • Backups probados: actívalos y verifica que sabes restaurarlos.
Lo más olvidado. Subir .env o settings.py con la SECRET_KEY a un repositorio. Revisa tu .gitignore antes del primer push.

14Costos estimados

Precios orientativos para planificar. Verifica siempre los valores actuales en el panel.

RecursoEspecificaciónPrecio aprox.Para qué
Droplet básico1 GB · 1 vCPU · 25 GBUSD 6/mesPruebas, 1 app pequeña
Droplet recomendado2 GB · 1 vCPU · 50 GBUSD 12/mes1–2 apps + Postgres local
Droplet mediano4 GB · 2 vCPU · 80 GBUSD 24/mesVarias apps y subdominios
Managed PostgreSQL1 GB · nodo único~USD 15/mesBD en producción
Backups del Droplet~20% del Droplet+USD 1.20–2.40/mesCopias automáticas
Spaces250 GB + CDN~USD 5/mesImágenes y archivos
App PlatformBasic por componentedesde ~USD 5/mesDeploy sin servidor
Arranque económico sugerido. Un Droplet de USD 12 con Postgres local + Certbot gratis + varios subdominios aloja tus primeras apps de Django, React y Next por ~USD 13/mes. Migras a Managed Database cuando el proyecto lo justifique.

15Referencia rápida de comandos

chuleta · comandos frecuentes
# ── Conexión ──
ssh deploy@IP

# ── Sistema ──
sudo apt update && sudo apt upgrade -y
df -h ; free -h ; htop

# ── Nginx ──
sudo nginx -t
sudo systemctl restart nginx
sudo tail -f /var/log/nginx/error.log

# ── Django / Gunicorn ──
sudo systemctl restart gunicorn
sudo journalctl -u gunicorn -n 50 --no-pager
source venv/bin/activate

# ── Next / PM2 ──
pm2 list ; pm2 logs ; pm2 restart next-app ; pm2 monit

# ── Firewall / HTTPS ──
sudo ufw status
sudo certbot --nginx -d sub.tema.com.pe
sudo certbot renew --dry-run

# ── PostgreSQL ──
sudo -u postgres psql   #  \l listar   \du usuarios   \q salir

Listos para montar la nube de TEMA

Sigue las secciones en orden para tu primer Droplet, o salta directo a App Platform si quieres desplegar un prototipo hoy. Cuando quieras, personalizamos esta guía con los dominios, regiones y repositorios reales del equipo.