Cómo dimensionar un servidor cloud para SaaS: CPU, RAM, NVMe

Cómo dimensionar un servidor cloud para SaaS: CPU, RAM, NVMe

Cómo dimensionar un servidor cloud para SaaS: CPU, RAM, NVMe

Para dimensionar un servidor cloud para una aplicación SaaS, no partas del número de usuarios. Empieza por la memoria de cada proceso, sigue con la CPU de cada contenedor, después calcula el disco para datos, WAL y copias de seguridad, y comprueba cada suposición con una prueba de carga. Esta guía lo hace con un ejemplo real: API y worker en Node.js, PostgreSQL, Redis y nginx con Docker Compose, probados en una sola máquina. Los perfiles de abajo son hipótesis de partida; para rangos iniciales sencillos consulta la guía de dimensionamiento.

El stack del ejemplo

Stack SaaS de ejemplo en Docker con límites de CPU y memoria por contenedor

El ejemplo es una API de gestión de tareas: un proxy nginx, dos réplicas de la API en Node.js, un worker que vacía una cola de Redis, PostgreSQL 17 y Redis 7. Solo el proxy publica un puerto, y lo hace en loopback. Los secretos están en un archivo .env que no se sube al repositorio, cada servicio tiene un healthcheck y un límite de recursos, y los logs rotan. La monitorización aquí es docker stats, los contadores de cgroup y pg_stat_statements. Para la parte de Node.js por separado consulta Servidor Cloud para Node.js. Los archivos completos están al final.

Por qué los usuarios no se convierten en vCPU

  • Concurrencia, no número de personas - solicitudes en curso = tasa de llegada x tiempo por solicitud (ley de Little). 1000 usuarios que hacen clic una vez por minuto son unas 17 solicitudes por segundo; un script que consulta cada segundo genera la misma carga que 60 de esos usuarios.
  • Coste del SQL y modelo de ejecución - en nuestra prueba la consulta del informe tardó de media 1,07 ms en pg_stat_statements y la del listado 0,07 ms, unas 15 veces más. Un proceso de Node.js usa aproximadamente un núcleo, así que las vCPU de la API son el número de procesos, no de usuarios.
  • Sockets, tareas y picos - un WebSocket abierto retiene memoria durante toda su vida, una tarea en segundo plano compite con las solicitudes por los mismos núcleos, y se dimensiona para la hora más cargada, no para la media.

Tres perfiles de partida

Hipótesis, no mediciones. Los precios son importes mensuales para Praga, recalculados con la tarifa el 2026-10-14.

Perfil Especificación inicial Precio mensual, base
Dev / staging 2 vCPU, 4 GB de RAM, 40 GB NVMe (Small) EUR 15.00, 1 copia
Producción pequeña 4 vCPU, 8 GB de RAM, 80 GB NVMe (Medium), el ejemplo tal como se publica EUR 18.43, 1 copia
SaaS en crecimiento, un servidor 8 vCPU, 16 GB de RAM, 160 GB NVMe (Large) EUR 36.88, 1 copia
SaaS en crecimiento, dividido servidor de aplicación Medium más un servidor de base de datos de 4 vCPU, 16 GB de RAM, 160 GB NVMe EUR 18.43 (1 copia) + EUR 39.05 (3 copias) = EUR 57.48

La aritmética de memoria, disco y copias

Los límites de abajo los fija el archivo compose; la última columna es la memoria residente que mostró docker stats durante nuestros escalones de carga, en todas las pruebas.

Contenedor Límite Ajuste Bajo carga
proxy 64 MB nginx, un worker 3-18 MB
api (x2) 320 MB cada uno --max-old-space-size=192, pool de 10 21-34 MB cada uno
worker 256 MB heap 128 MB, pool de 3 19-34 MB
db 2 GB shared_buffers 512 MB, work_mem 8 MB 207-252 MB
redis 256 MB maxmemory 128 MB, sin expulsión 4-7 MB

Los límites suman 3,2 GB, de modo que quedan 4,8 GB de los 8 GB de la VM para el sistema operativo y la caché de páginas. Tres reglas producen las cifras. Primera, shared_buffers empieza en el 25% de la memoria de un servidor de base de datos dedicado (documentación de PostgreSQL, comprobada el 2026-10-14): el 25% de los 2 GB del contenedor son 512 MB. Segunda, work_mem se aplica por operación de ordenación o hash, no por conexión, así que el total puede ser muchas veces el valor: 23 conexiones de la aplicación a 8 MB con dos operaciones así cada una dan un peor caso de 368 MB. Tercera, los pools multiplicados por los procesos (2 x 10 + 3 = 23) deben quedar por debajo de max_connections (50).

Disco y copias. Tras unos 1,04 millones de filas la base de datos ocupaba 146 MB, pero el directorio de datos 457 MB, de los que 288 MB eran pg_wal: el WAL sigue a max_wal_size (un límite blando), no al tamaño de los datos, así que presupuéstalo y deja libre más del 20% del disco. Con este conjunto de datos diminuto, pg_dump -Fc tardó 0,59 s (7 MB) y la restauración 1,78 s; tu tiempo de restauración es tu tiempo de caída, así que mídelo. Cada precio de DCXV Cloud incluye una copia semanal del disco: es una copia de seguridad, no espacio para tus archivos.

Encuentra el cuello de botella con k6

Fija primero la condición de éxito (aquí, p95 por debajo de 300 ms y menos del 1% de solicitudes fallidas), usa un modelo abierto (constant-arrival-rate, consulta la documentación de k6), sube la tasa por escalones y vigila estas señales a la vez.

Señal Comando Mala señal
p95, errores, iteraciones descartadas resumen de k6 p95 por encima del objetivo, el servidor no sigue la tasa de llegada
Throttling de CPU grep nr_throttled /sys/fs/cgroup/cpu.stat dentro del contenedor crece durante el escalón (documentación del kernel)
CPU steal vmstat 5, columna st por encima de 0 en una VM: el host está saturado
Presión de memoria docker stats, vmstat columnas si so cerca del límite o con swap

Medido en una máquina Linux arm64 de 12 núcleos con 14,4 GB de RAM, Docker 29.7.2, k6 2.3.0, PostgreSQL 17.11, Node.js 22.23.3, nginx 1.27.5, Redis 7.4.11, el 2026-10-14, una ejecución de 40 s por escalón salvo que se muestren dos valores. No es DCXV Cloud. k6 compartió las CPU con el stack, y el host además usaba swap, así que las latencias son pesimistas: para una prueba real ejecuta k6 desde una segunda máquina. "Descartadas" cuenta las llegadas que k6 omitió porque los 500 usuarios virtuales estaban ocupados.

Config. de nginx Solicitudes/s ofrecidas Solicitudes/s logradas p95 Fallidas Descartadas
A, proxy 0,25 CPU 1000 610 2,11 s 0,03% 15 595
A, proxy 1,0 CPU 1000 994 y 997 150 ms y 51,5 ms 0% 207 y 121
A, proxy 1,0 CPU 2000 941 1,77 s 6,56% 42 356
B, keepalive 1000 999 y 1000 2,66 ms y 2,42 ms 0% 36 y 0
B, keepalive 5000 4995 1,48 ms 0% 206
B, keepalive 8000 7918 23,1 ms 0,02% 2532

La lección es el método, no el rendimiento. La config. A usaba proxy_pass con una variable y sin bloque upstream, así que nginx abría una conexión TCP nueva hacia la API en cada solicitud. El proxy llegó primero a su límite de CPU (cpu.stat: 1512 de 2787 periodos con throttling con 0,25 CPU, y con 1,0 CPU seguía habiendo un tope cerca de 940 solicitudes/s) mientras la base de datos usaba bastante menos de la mitad de su límite. La config. B, un upstream con keepalive 32, mantuvo el proxy en cerca de un tercio de una CPU a 8000 solicitudes/s. Los siguientes límites aparecieron entonces en los mismos contadores: la base de datos tuvo throttling en 301 de 2790 periodos, y el worker de 0,25 CPU lo tuvo casi en todos los periodos y dejó 46 982 trabajos en la cola (LLEN jobs). Un conjunto de datos de 146 MB cabe en memoria, por lo que nada de esto tocó el disco. Una comprobación con fio sobre un archivo temporal (fio --name=w --filename=fio.tmp --size=256M --rw=write --bs=8k --fdatasync=1 --ioengine=sync --runtime=15 --time_based) midió 700 escrituras síncronas por segundo, de unos 1,4 ms; una ejecución de lectura aleatoria (fio --name=r --filename=fio.tmp --size=256M --rw=randread --bs=4k --iodepth=32 --ioengine=libaio --direct=1 --runtime=15 --time_based) informó 399 000 IOPS, que es la caché de páginas y no el disco.

Calcula el precio del resultado en el configurador

  1. Abre la página de servidores cloud. No lee cifras de este artículo, así que ajústalas tú: elige la fila de plan más cercana a tu perfil (Small, Medium o Large) y ajusta después los controles deslizantes de CPU (1-96), RAM (1-256 GB) y disco (20-960 GB) a los valores de tu hoja de trabajo.
  2. Añade copias de seguridad, direcciones IPv4 adicionales y horas de administración, y lee el precio mensual completo, no el precio "desde". La administración gestionada empieza en EUR 30 por dos horas.

Comprobado con la tarifa el 2026-10-14: Medium con 3 copias cuesta EUR 21.47, y la misma CPU con 16 GB de RAM, EUR 29.95. La RAM es lo que más mueve el precio.

Configura un servidor cloud para tu aplicación

Cuándo separar la base de datos o pasar a dedicado

  • Separa la BD cuando necesite más de la mitad de la memoria de la VM, cuando API y BD entren en throttling mutuo por la CPU o cuando quieras un ritmo propio de restauración. Consulta la guía de PostgreSQL.
  • Pasa a dedicado cuando una carga mantenga ocupadas más del 70% de todas las vCPU en el pico, necesite más de las 96 vCPU o 256 GB de RAM de un servidor cloud o requiera una latencia de disco predecible. Consulta los servidores dedicados.

Plantilla de migración y reversión

Ensáyala primero en el servidor nuevo.

Paso Acción Reversión
1 Restaura un volcado reciente en el servidor nuevo, arranca la app y pásale una prueba de carga elimina el servidor nuevo
2 Congela las escrituras, haz el volcado final, restáuralo y compara el número de filas reabre las escrituras en el servidor antiguo
3 Cambia el DNS (TTL bajado a 300 s con un TTL antiguo completo de antelación) y prueba el inicio de sesión, el pedido, la tarea y el correo devuelve el DNS al origen
4 Mantén el servidor antiguo en solo lectura al menos una semana reproduce las escrituras nuevas en el lado antiguo

Hoja de trabajo de dimensionamiento

Imprímela y rellena la columna derecha con tus propias mediciones.

Concepto Cómo obtenerlo Tu valor
Solicitudes por segundo en el pico analítica o prueba de carga
p95 objetivo y tasa de fallos tu SLO, por ejemplo 300 ms y 1%
Procesos de API uno por vCPU
Límite de memoria del contenedor RSS pico bajo carga más margen
Conexiones a la BD pools x procesos, por debajo de max_connections
Memoria libre 20-25% de la VM
Disco datos y crecimiento + WAL + logs + imágenes + volcado temporal, y 20% libre
Copias cuántas se conservan, tiempo de restauración medido
Precio mensual total del configurador con copias, IPv4, administración y fecha

Reprodúcelo

Necesitas Docker con Compose, curl, openssl y vmstat; la imagen de k6 se descarga en la primera ejecución. Los archivos son los que ejecutamos, con estas versiones. Las etiquetas postgres:17-alpine, redis:7-alpine y node:22-alpine son flotantes y npm install no tiene archivo de bloqueo, así que fija etiquetas y versiones si necesitas el mismo resultado.

compose.yaml

# "Small production" starting hypothesis for a 4 vCPU / 8 GB VM: limits sum to 4.0 CPU and 3.2 GB
name: saas-sizing

x-logging: &logging
  driver: json-file
  options: { max-size: 10m, max-file: "3" }   # logs cannot fill the disk

services:
  proxy:
    build: { context: ., dockerfile: Dockerfile.proxy }
    ports: ["127.0.0.1:8080:80"]        # the only published port, loopback only
    depends_on:
      api: { condition: service_healthy }
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1/healthz"]
      interval: 10s
      timeout: 3s
      retries: 3
    deploy: { resources: { limits: { cpus: "1.0", memory: 64M } } }
    logging: *logging
    restart: unless-stopped

  api:
    build: .
    command: ["node", "--max-old-space-size=192", "src/api.js"]
    env_file: [.env]
    environment:
      PG_POOL: "10"
    expose: ["3000"]
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_healthy }
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/readyz"]
      interval: 10s
      timeout: 3s
      retries: 3
    deploy:
      replicas: 2
      resources: { limits: { cpus: "0.5", memory: 320M } }
    logging: *logging
    restart: unless-stopped

  worker:
    build: .
    command: ["node", "--max-old-space-size=128", "src/worker.js"]
    env_file: [.env]
    environment:
      PG_POOL: "3"
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_healthy }
    healthcheck:
      test: ["CMD-SHELL", "pgrep -f src/worker.js >/dev/null"]
      interval: 15s
      timeout: 3s
      retries: 3
    deploy: { resources: { limits: { cpus: "0.25", memory: 256M } } }
    logging: *logging
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    env_file: [.env]
    command: [postgres,
      -c, shared_buffers=512MB, -c, effective_cache_size=1536MB,
      -c, work_mem=8MB, -c, maintenance_work_mem=128MB,
      -c, max_connections=50, -c, max_wal_size=1GB,
      -c, shared_preload_libraries=pg_stat_statements,
      -c, log_min_duration_statement=250, -c, track_io_timing=on]
    volumes: ["pgdata:/var/lib/postgresql/data"]
    # no "ports": reachable only from the compose network
    shm_size: 256m
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 10s
      timeout: 3s
      retries: 5
    deploy: { resources: { limits: { cpus: "1.5", memory: 2G } } }
    logging: *logging
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    env_file: [.env]
    command: ["sh", "-c", "exec redis-server --requirepass \"$$REDIS_PASSWORD\" --maxmemory 128mb --maxmemory-policy noeviction --appendonly yes"]
    volumes: ["redisdata:/data"]
    healthcheck:
      test: ["CMD-SHELL", "REDISCLI_AUTH=\"$$REDIS_PASSWORD\" redis-cli ping | grep -q PONG"]
      interval: 10s
      timeout: 3s
      retries: 5
    deploy: { resources: { limits: { cpus: "0.25", memory: 256M } } }
    logging: *logging
    restart: unless-stopped

volumes:
  pgdata:
  redisdata:

Dockerfile

FROM node:22-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --omit=dev --no-audit --no-fund
COPY src ./src
USER node

Dockerfile.proxy

FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/nginx.conf

nginx.conf

worker_processes 1;
events { worker_connections 1024; }
http {
  access_log off;
  # resolved once at start: restart the proxy if the api containers get new addresses
  upstream api {
    server api:3000;
    keepalive 32;   # reuse upstream connections instead of one TCP connect per request
  }
  server {
    listen 80;
    location = /healthz { return 200 "ok\n"; }
    location / {
      proxy_pass http://api;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_set_header Host $host;
      proxy_read_timeout 10s;
    }
  }
}

package.json

{
  "name": "saas-sizing-example",
  "private": true,
  "type": "module",
  "dependencies": {
    "ioredis": "5.4.1",
    "pg": "8.13.1"
  }
}

src/db.js

import pg from 'pg'
import Redis from 'ioredis'

// pool size x processes must stay under Postgres max_connections (see the budget table)
export const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
  max: Number(process.env.PG_POOL || 10),
  statement_timeout: 5000,
})
export const redis = new Redis(process.env.REDIS_URL, { maxRetriesPerRequest: 2 })

src/api.js

import http from 'node:http'
import { pool, redis } from './db.js'

const json = (res, code, body) => {
  res.writeHead(code, { 'content-type': 'application/json' })
  res.end(JSON.stringify(body))
}
const readBody = req => new Promise((ok, fail) => {
  let s = ''
  req.on('data', c => { s += c; if (s.length > 4096) req.destroy() })
  req.on('end', () => ok(s))
  req.on('error', fail)
})

const routes = {
  'GET /healthz': (req, res) => json(res, 200, { ok: true }),
  // readiness touches both stores; the container healthcheck uses it
  'GET /readyz': async (req, res) => {
    await pool.query('select 1')
    await redis.ping()
    json(res, 200, { ok: true })
  },
  'GET /api/tasks': async (req, res, url) => {
    const account = Number(url.searchParams.get('account'))
    if (!Number.isInteger(account) || account < 1) return json(res, 400, { error: 'account' })
    const { rows } = await pool.query(
      'select id, title, status from tasks where account_id = $1 order by id desc limit 20', [account])
    json(res, 200, rows)
  },
  'GET /api/report': async (req, res, url) => {
    const account = Number(url.searchParams.get('account'))
    if (!Number.isInteger(account) || account < 1) return json(res, 400, { error: 'account' })
    const { rows } = await pool.query(
      'select status, count(*)::int as n from tasks where account_id = $1 group by status', [account])
    json(res, 200, rows)
  },
  'POST /api/tasks': async (req, res) => {
    let b
    try { b = JSON.parse(await readBody(req)) } catch { return json(res, 400, { error: 'json' }) }
    const account = Number(b.account)
    if (!Number.isInteger(account) || account < 1 || typeof b.title !== 'string' || b.title.length > 200) {
      return json(res, 400, { error: 'input' })
    }
    const { rows } = await pool.query(
      "insert into tasks (account_id, title) values ($1, $2) returning id", [account, b.title])
    await redis.lpush('jobs', String(rows[0].id))
    json(res, 201, { id: rows[0].id })
  },
}

const server = http.createServer(async (req, res) => {
  const url = new URL(req.url, 'http://x')
  const h = routes[`${req.method} ${url.pathname}`]
  if (!h) return json(res, 404, { error: 'not found' })
  try { await h(req, res, url) } catch (e) {
    console.error(e.message)
    json(res, 503, { error: 'unavailable' })
  }
})
server.listen(3000, () => console.log('api up'))

// compose sends SIGTERM on stop: finish in-flight requests, then close the stores
process.on('SIGTERM', () => server.close(async () => { await pool.end(); redis.disconnect(); process.exit(0) }))

src/worker.js

import { createHash } from 'node:crypto'
import { pool, redis } from './db.js'

let stop = false
process.on('SIGTERM', () => { stop = true })

// stands in for real background work (mail, PDF, webhook): a little CPU, then one UPDATE
const work = title => {
  let h = title
  for (let i = 0; i < 2000; i++) h = createHash('sha256').update(h).digest('hex')
  return h.slice(0, 16)
}

console.log('worker up')
while (!stop) {
  const r = await redis.brpop('jobs', 2)
  if (!r) continue
  const id = Number(r[1])
  const { rows } = await pool.query('select title from tasks where id = $1', [id])
  if (!rows.length) continue
  await pool.query("update tasks set status = 'done', result = $2 where id = $1", [id, work(rows[0].title)])
}
await pool.end()
redis.disconnect()

init.sql

create extension if not exists pg_stat_statements;
create table tasks (
  id bigserial primary key,
  account_id int not null,
  title text not null,
  status text not null default 'open',
  result text,
  created_at timestamptz not null default now()
);
create index tasks_account_id_idx on tasks (account_id, id desc);

seed.sql

-- 1,000,000 tasks for 2,000 accounts (about 500 each), 70% done
insert into tasks (account_id, title, status)
select 1 + (g % 2000), 'task ' || g, case when g % 10 < 7 then 'done' else 'open' end
from generate_series(1, 1000000) g;
analyze tasks;

make-env.sh

#!/bin/sh
# writes .env with random secrets; never commit it, and never reuse these values elsewhere
set -eu
[ -e .env ] && { echo ".env exists, not overwriting"; exit 1; }
PG=$(openssl rand -hex 24)
RD=$(openssl rand -hex 24)
umask 077
cat > .env <<EOF
POSTGRES_USER=app
POSTGRES_PASSWORD=$PG
POSTGRES_DB=app
REDIS_PASSWORD=$RD
DATABASE_URL=postgres://app:$PG@db:5432/app
REDIS_URL=redis://:$RD@redis:6379
EOF

k6.js

import http from 'k6/http'
import { check } from 'k6'

const BASE = __ENV.BASE || 'http://proxy'
const RATE = Number(__ENV.RATE || 100)

// open model: requests arrive at RATE per second whether or not the server keeps up,
// which is how real users behave (closed-loop VUs hide overload)
export const options = {
  scenarios: {
    mixed: {
      executor: 'constant-arrival-rate',
      rate: RATE,
      timeUnit: '1s',
      duration: __ENV.DURATION || '30s',
      preAllocatedVUs: 50,
      maxVUs: 500,
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(95)<300'],
  },
  summaryTrendStats: ['avg', 'med', 'p(90)', 'p(95)', 'p(99)', 'max'],
}

export default function () {
  const account = 1 + Math.floor(Math.random() * 2000)
  const r = Math.random()
  let res
  if (r < 0.80) res = http.get(`${BASE}/api/tasks?account=${account}`)
  else if (r < 0.90) res = http.get(`${BASE}/api/report?account=${account}`)
  else res = http.post(`${BASE}/api/tasks`, JSON.stringify({ account, title: 'k6 task' }),
    { headers: { 'content-type': 'application/json' } })
  check(res, { 'status 200/201': x => x.status === 200 || x.status === 201 })
}

bench.sh

#!/bin/sh
# usage: ./bench.sh 200 500 1000   (requests per second, one 40 s step each)
set -eu
NET=$(docker compose ps -q proxy | xargs docker inspect --format '{{range $k, $v := .NetworkSettings.Networks}}{{$k}}{{end}}')
for RATE in "$@"; do
  echo "=== ${RATE} req/s"
  # mid-run snapshot of container CPU / memory and host CPU steal ("st") and swap ("si so")
  ( sleep 20; docker stats --no-stream --format '{{.Name}} cpu={{.CPUPerc}} mem={{.MemUsage}}' $(docker compose ps -q); vmstat 5 2 | tail -1 ) &
  docker run --rm -i --network "$NET" -e RATE="$RATE" -e DURATION=40s \
    grafana/k6 run --quiet - < k6.js 2>&1 | grep -E 'http_req_duration\.|http_req_failed\.|http_reqs|dropped_iterations|vus_max'
  wait
done
sh make-env.sh
docker compose up -d --build
docker compose exec -T db sh -c 'psql -v ON_ERROR_STOP=1 -q -U $POSTGRES_USER -d $POSTGRES_DB' < init.sql
docker compose exec -T db sh -c 'psql -v ON_ERROR_STOP=1 -q -U $POSTGRES_USER -d $POSTGRES_DB' < seed.sql
curl -s http://127.0.0.1:8080/readyz
./bench.sh 500 1000
docker compose down -v

Tus cifras serán distintas. Cuando lo sean, confía en ellas antes que en las nuestras, y después configura un servidor cloud para tu aplicación o escribe a sales@dcxv.com.

Cómo dimensionar un servidor cloud para SaaS: CPU, RAM, NVMe
cloudinfrastructurepricing

Cómo dimensionar un servidor cloud para SaaS: CPU, RAM, NVMe

Dimensiona un servidor cloud para SaaS con Docker y Node.js: presupuesto de memoria, límites de CPU, NVMe y copias, prueba de carga k6, precio mensual y hoja.

Agentes de código con IA en VPS de la UE: setup reforzado
aicloudhosting

Agentes de código con IA en VPS de la UE: setup reforzado

Aloja agentes de código con IA en un VPS de la UE con límites: espacios desechables, salida permitida, tokens acotados, topes, código probado, riesgos y coste.

Cómo comprar direcciones IPv4: costes, reglas y riesgos
ipv4brokerpricingtransferripe-ncc

Cómo comprar direcciones IPv4: costes, reglas y riesgos

Compre direcciones IPv4 con seguridad: compra, alquiler o BYOIP, coste total, verificación del bloque, depósito y requisitos de RIPE NCC, ARIN y APNIC.

¿Cuánto vale un bloque IPv4 /24, /22, /20 o /16 en 2026?
ipv4networkingpricing

¿Cuánto vale un bloque IPv4 /24, /22, /20 o /16 en 2026?

Precios de bloques IPv4 en 2026: /24, /22, /20 y /16 por IP y por bloque, factores, precio pedido o cerrado, costes extra y cómo valora DCXV un bloque.

Cómo vender direcciones IPv4 en 2026: RIPE, ARIN y APNIC
ipv4brokerpricingtransfer

Cómo vender direcciones IPv4 en 2026: RIPE, ARIN y APNIC

Cómo vender direcciones IPv4 con seguridad en 2026: elegibilidad del bloque, reglas de transferencia de RIPE, ARIN y APNIC, precio, depósito y costes.