Server cloud per SaaS: dimensionare CPU, RAM, NVMe e backup

Server cloud per SaaS: dimensionare CPU, RAM, NVMe e backup

Server cloud per SaaS: dimensionare CPU, RAM, NVMe e backup

Per dimensionare un server cloud per un'applicazione SaaS, non partire dal numero di utenti. Parti dalla memoria di ogni processo, poi dalla CPU di ogni container, quindi dal disco per dati, WAL e backup, e verifica ogni ipotesi con un test di carico. Questa guida lo fa su un esempio reale: API e worker Node.js, PostgreSQL, Redis e nginx in Docker Compose, provati su una sola macchina. I profili qui sotto sono ipotesi di partenza; per intervalli iniziali semplici vedi la guida al dimensionamento.

Lo stack dell'esempio

Stack SaaS di esempio in Docker con limiti di CPU e memoria per container

L'esempio è un'API per la gestione di attività: un proxy nginx, due repliche dell'API Node.js, un worker che svuota una coda Redis, PostgreSQL 17 e Redis 7. Solo il proxy pubblica una porta, e solo su loopback. I segreti stanno in un file .env non committato, ogni servizio ha un healthcheck e un limite di risorse, e i log ruotano. Il monitoraggio qui è docker stats, i contatori cgroup e pg_stat_statements. Per il solo lato Node.js vedi Server Cloud per Node.js. I file completi sono in fondo.

Perché gli utenti non si convertono in vCPU

  • Concorrenza, non numero di persone - richieste in corso = frequenza di arrivo x tempo per richiesta (legge di Little). 1000 utenti che cliccano una volta al minuto sono circa 17 richieste al secondo; uno script che interroga ogni secondo genera lo stesso carico di 60 di quegli utenti.
  • Costo dell'SQL e modello di esecuzione - nella nostra prova la query del report impiegava in media 1,07 ms in pg_stat_statements e quella dell'elenco 0,07 ms, circa 15 volte meno. Un processo Node.js usa circa un core, quindi le vCPU dell'API corrispondono al numero di processi, non di utenti.
  • Socket, job e picchi - un WebSocket aperto trattiene memoria per tutta la sua vita, un job in background contende gli stessi core alle richieste, e si dimensiona per l'ora più carica, non per la media.

Tre profili di partenza

Ipotesi, non misure. I prezzi sono importi mensili per Praga, ricalcolati dal listino il 2026-10-14.

Profilo Specifica iniziale Prezzo mensile, base
Dev / staging 2 vCPU, 4 GB di RAM, 40 GB NVMe (Small) EUR 15.00, 1 backup
Piccola produzione 4 vCPU, 8 GB di RAM, 80 GB NVMe (Medium), l'esempio come pubblicato EUR 18.43, 1 backup
SaaS in crescita, un server 8 vCPU, 16 GB di RAM, 160 GB NVMe (Large) EUR 36.88, 1 backup
SaaS in crescita, separato server applicativo Medium più un server database da 4 vCPU, 16 GB di RAM, 160 GB NVMe EUR 18.43 (1 backup) + EUR 39.05 (3 backup) = EUR 57.48

L'aritmetica di memoria, disco e backup

I limiti qui sotto sono quelli del file compose; l'ultima colonna è la memoria residente mostrata da docker stats durante i nostri gradini di carico, su tutte le prove.

Container Limite Impostazione Sotto carico
proxy 64 MB nginx, un worker 3-18 MB
api (x2) 320 MB ciascuno --max-old-space-size=192, pool da 10 21-34 MB ciascuno
worker 256 MB heap 128 MB, pool da 3 19-34 MB
db 2 GB shared_buffers 512 MB, work_mem 8 MB 207-252 MB
redis 256 MB maxmemory 128 MB, senza eviction 4-7 MB

I limiti sommano 3,2 GB, quindi 4,8 GB degli 8 GB della VM restano per il sistema operativo e la cache di pagine. Tre regole producono i numeri. Prima, shared_buffers parte dal 25% della memoria di un server database dedicato (documentazione PostgreSQL, verificata il 2026-10-14): il 25% dei 2 GB del container sono 512 MB. Seconda, work_mem vale per ogni operazione di ordinamento o hash, non per connessione, quindi il totale può essere molte volte il valore impostato: 23 connessioni applicative a 8 MB con due operazioni di questo tipo ciascuna danno un caso peggiore di 368 MB. Terza, i pool moltiplicati per i processi (2 x 10 + 3 = 23) devono restare sotto max_connections (50).

Disco e backup. Dopo circa 1,04 milioni di righe il database pesava 146 MB, ma la directory dei dati 457 MB, di cui 288 MB di pg_wal: il WAL segue max_wal_size (un limite morbido), non la dimensione dei dati, quindi calcolalo e lascia libero più del 20% del disco. Su questo dataset minuscolo pg_dump -Fc ha impiegato 0,59 s (7 MB) e il ripristino 1,78 s; il tuo tempo di ripristino è il tuo tempo di fermo, quindi misuralo. Ogni prezzo di DCXV Cloud include un backup settimanale del disco: è una copia di sicurezza, non spazio per i tuoi file.

Trova il collo di bottiglia con k6

Fissa prima la condizione di successo (qui p95 sotto 300 ms e meno dell'1% di richieste fallite), usa un modello aperto (constant-arrival-rate, vedi la documentazione di k6), aumenta la frequenza a gradini e osserva insieme questi segnali.

Segnale Comando Cattivo segno
p95, errori, iterazioni scartate riepilogo di k6 p95 sopra l'obiettivo, il server non regge la frequenza di arrivo
Throttling della CPU grep nr_throttled /sys/fs/cgroup/cpu.stat nel container cresce durante il gradino (documentazione del kernel)
CPU steal vmstat 5, colonna st sopra 0 su una VM: l'host è conteso
Pressione sulla memoria docker stats, vmstat colonne si so vicino al limite, o swap

Misurato su una macchina Linux arm64 a 12 core con 14,4 GB di 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, il 2026-10-14, una prova da 40 s per gradino salvo dove sono indicati due valori. Non è DCXV Cloud. k6 condivideva le CPU con lo stack e l'host usava anche lo swap, quindi le latenze sono pessimistiche: per un test reale esegui k6 da una seconda macchina. "Scartate" conta gli arrivi che k6 ha saltato perché tutti i 500 utenti virtuali erano occupati.

Config nginx Richieste/s offerte Richieste/s ottenute p95 Fallite Scartate
A, proxy 0,25 CPU 1000 610 2,11 s 0,03% 15 595
A, proxy 1,0 CPU 1000 994 e 997 150 ms e 51,5 ms 0% 207 e 121
A, proxy 1,0 CPU 2000 941 1,77 s 6,56% 42 356
B, keepalive 1000 999 e 1000 2,66 ms e 2,42 ms 0% 36 e 0
B, keepalive 5000 4995 1,48 ms 0% 206
B, keepalive 8000 7918 23,1 ms 0,02% 2532

La lezione è il metodo, non il throughput. La config A usava proxy_pass con una variabile e senza blocco upstream, quindi nginx apriva una nuova connessione TCP verso l'API a ogni richiesta. Il proxy ha raggiunto per primo il limite di CPU (cpu.stat: con 0,25 CPU 1512 dei 2787 periodi in throttling, e con 1,0 CPU restava un tetto vicino a 940 richieste/s) mentre il database usava molto meno della metà del suo limite. La config B, un upstream con keepalive 32, ha tenuto il proxy attorno a un terzo di una CPU a 8000 richieste/s. I limiti successivi sono poi comparsi negli stessi contatori: il database è andato in throttling in 301 dei 2790 periodi, e il worker da 0,25 CPU quasi in ogni periodo, lasciando 46 982 job nella coda (LLEN jobs). Un dataset di 146 MB sta in memoria, quindi nulla di tutto questo ha toccato il disco. Un controllo con fio su un file temporaneo (fio --name=w --filename=fio.tmp --size=256M --rw=write --bs=8k --fdatasync=1 --ioengine=sync --runtime=15 --time_based) ha misurato 700 scritture sincrone al secondo, da circa 1,4 ms; una prova di lettura casuale (fio --name=r --filename=fio.tmp --size=256M --rw=randread --bs=4k --iodepth=32 --ioengine=libaio --direct=1 --runtime=15 --time_based) ha riportato 399 000 IOPS, che è la cache di pagine e non il disco.

Calcola il prezzo del risultato nel configuratore

  1. Apri la pagina dei server cloud. Non legge i numeri di questo articolo, quindi impostali tu: scegli la riga di piano più vicina al tuo profilo (Small, Medium o Large), poi regola i cursori di CPU (1-96), RAM (1-256 GB) e disco (20-960 GB) sui valori della tua scheda.
  2. Aggiungi copie di backup, indirizzi IPv4 extra e ore di amministrazione, poi leggi il prezzo mensile completo, non il prezzo "da". L'amministrazione gestita parte da EUR 30 per due ore.

Verificato sul listino il 2026-10-14: Medium con 3 backup costa EUR 21.47, e la stessa CPU con 16 GB di RAM EUR 29.95. È la RAM a spostare di più il prezzo.

Configura un server cloud per la tua app

Quando separare il database o passare al dedicato

  • Separa il DB quando richiede più di circa metà della memoria della VM, quando API e DB si contendono la CPU andando in throttling a vicenda o quando vuoi un ritmo di ripristino distinto. Vedi la guida a PostgreSQL.
  • Passa al dedicato quando un carico tiene occupato più del 70% di tutte le vCPU al picco, richiede più delle 96 vCPU o dei 256 GB di RAM di un server cloud o esige una latenza del disco prevedibile. Vedi i server dedicati.

Modello di migrazione e rollback

Provalo prima sul nuovo server.

Passo Azione Rollback
1 Ripristina un dump recente sul nuovo server, avvia l'app e sottoponila a un test di carico elimina il nuovo server
2 Blocca le scritture, fai il dump finale, ripristina, confronta il numero di righe riapri le scritture sul vecchio server
3 Cambia il DNS (TTL abbassato a 300 s con un intero vecchio TTL di anticipo), prova login, ordine, job e posta rimetti il DNS com'era
4 Tieni il vecchio server in sola lettura per almeno una settimana riproduci le nuove scritture sul lato vecchio

Scheda di dimensionamento

Stampala e compila la colonna di destra con le tue misure.

Voce Come ottenerla Il tuo valore
Richieste al secondo al picco analytics o test di carico
p95 obiettivo e tasso di errori il tuo SLO, ad esempio 300 ms e 1%
Processi API uno per vCPU
Limite di memoria del container RSS di picco sotto carico più margine
Connessioni al DB pool x processi, sotto max_connections
Memoria libera mantenuta 20-25% della VM
Disco dati e crescita + WAL + log + immagini + dump temporaneo, poi 20% libero
Backup quante copie, tempo di ripristino misurato
Prezzo mensile totale del configuratore con backup, IPv4, amministrazione e data

Riproducilo

Servono Docker con Compose, curl, openssl e vmstat; l'immagine di k6 viene scaricata al primo avvio. I file sono quelli che abbiamo eseguito, con queste versioni. I tag postgres:17-alpine, redis:7-alpine e node:22-alpine sono mobili e npm install non ha un lockfile, quindi fissa tag e versioni se ti serve lo stesso risultato.

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

I tuoi numeri saranno diversi. Quando lo sono, fidati dei tuoi e non dei nostri, poi configura un server cloud per la tua app oppure scrivi a sales@dcxv.com.

Server cloud per SaaS: dimensionare CPU, RAM, NVMe e backup
cloudinfrastructurepricing

Server cloud per SaaS: dimensionare CPU, RAM, NVMe e backup

Dimensiona un server cloud per SaaS con Docker e Node.js: memoria, limiti CPU, NVMe e backup, test di carico k6, prezzo mensile completo e una scheda più pratica.

Agenti di codice IA su VPS UE: configurazione rinforzata
aicloudhosting

Agenti di codice IA su VPS UE: configurazione rinforzata

Ospita agenti di codice IA su un VPS UE con limiti: workspace usa e getta, uscita consentita, token limitati, codice testato, rischi e costi, più un esempio.

Come comprare IPv4: costi, regole di trasferimento, rischi
ipv4brokerpricingtransferripe-ncc

Come comprare IPv4: costi, regole di trasferimento, rischi

Acquistate IPv4 in sicurezza: acquisto, affitto o BYOIP, costo totale, verifica del blocco, deposito e requisiti del destinatario RIPE NCC, ARIN e APNIC.

Quanto vale un blocco IPv4 /24, /22, /20 o /16 nel 2026?
ipv4networkingpricing

Quanto vale un blocco IPv4 /24, /22, /20 o /16 nel 2026?

Prezzi dei blocchi IPv4 nel 2026: /24, /22, /20 e /16 per IP e per blocco, fattori, prezzo richiesto o chiuso, costi extra e come DCXV valuta un blocco.

Come vendere indirizzi IPv4 nel 2026: RIPE, ARIN e APNIC
ipv4brokerpricingtransfer

Come vendere indirizzi IPv4 nel 2026: RIPE, ARIN e APNIC

Come vendere indirizzi IPv4 in sicurezza nel 2026: idoneità del blocco, regole di trasferimento RIPE, ARIN e APNIC, fattori di prezzo, deposito e costi.