Як підібрати хмарний сервер для SaaS: CPU, RAM, NVMe, бекапи

Як підібрати хмарний сервер для SaaS: CPU, RAM, NVMe, бекапи

Як підібрати хмарний сервер для SaaS: CPU, RAM, NVMe, бекапи

Щоб підібрати хмарний сервер для SaaS-застосунку, не відштовхуйтеся від кількості користувачів. Почніть із пам'яті на процес, потім визначте CPU на контейнер, далі диск для даних, WAL і бекапів, а кожне припущення перевірте навантажувальним тестом. Цей посібник робить це на одному реальному прикладі: API і воркер на Node.js, PostgreSQL, Redis та nginx у Docker Compose, перевірені на одній машині. Профілі нижче є стартовими гіпотезами; прості стартові діапазони дивіться в посібнику з підбору.

Приклад стеку

Приклад SaaS-стеку в Docker з лімітами CPU і пам'яті для кожного контейнера

Приклад - це API для трекера завдань: проксі nginx, дві репліки API на Node.js, воркер, що розбирає чергу Redis, PostgreSQL 17 і Redis 7. Порт назовні відкриває лише проксі, і тільки на loopback. Секрети лежать у файлі .env, який не потрапляє до git, кожен сервіс має healthcheck і ліміт ресурсів, а логи ротуються. Моніторинг тут - це docker stats, лічильники cgroup і pg_stat_statements. Про сторону Node.js окремо дивіться Хмарний сервер для Node.js. Повні файли наведено наприкінці.

Чому користувачі не перетворюються на vCPU

  • Паралелізм, а не кількість людей - запити в обробці = інтенсивність надходження x час на запит (закон Літтла). 1000 користувачів, що клацають раз на хвилину, дають близько 17 запитів на секунду; один скрипт, що опитує щосекунди, створює таке саме навантаження, як 60 таких користувачів.
  • Вартість SQL і модель виконання - у нашому прогоні запит звіту в pg_stat_statements виконувався в середньому 1,07 мс, а запит списку 0,07 мс, тобто різниця близько 15 разів. Один процес Node.js використовує приблизно одне ядро, тому vCPU для API - це кількість процесів, а не користувачів.
  • Сокети, завдання і піки - відкритий WebSocket тримає пам'ять увесь свій час життя, фонове завдання ділить ядра із запитами, а розраховувати треба на найзавантаженішу годину, а не на середню.

Три стартові профілі

Це гіпотези, а не виміри. Ціни - місячні суми для Праги, перераховані за прайсом 2026-10-14.

Профіль Стартова специфікація Місячна ціна, база
Dev / staging 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe (Small) EUR 15.00, 1 бекап
Мала production 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe (Medium), приклад у опублікованому вигляді EUR 18.43, 1 бекап
SaaS, що росте, один сервер 8 vCPU, 16 ГБ RAM, 160 ГБ NVMe (Large) EUR 36.88, 1 бекап
SaaS, що росте, розділений сервер застосунку Medium плюс сервер БД: 4 vCPU, 16 ГБ RAM, 160 ГБ NVMe EUR 18.43 (1 бекап) + EUR 39.05 (3 бекапи) = EUR 57.48

Арифметика пам'яті, диска і бекапів

Ліміти нижче задає файл compose, а в останній колонці - резидентна пам'ять, яку показував docker stats під час наших кроків навантаження, за всі прогони.

Контейнер Ліміт Налаштування Під навантаженням
proxy 64 МБ nginx, один воркер 3-18 МБ
api (x2) по 320 МБ --max-old-space-size=192, пул 10 по 21-34 МБ
worker 256 МБ купа 128 МБ, пул 3 19-34 МБ
db 2 ГБ shared_buffers 512 МБ, work_mem 8 МБ 207-252 МБ
redis 256 МБ maxmemory 128 МБ, без витіснення 4-7 МБ

Ліміти разом дають 3,2 ГБ, тож 4,8 ГБ із 8 ГБ віртуальної машини лишаються ОС і кешу сторінок. Числа дають три правила. По-перше, shared_buffers починають із 25% пам'яті виділеної бази даних (документація PostgreSQL, перевірено 2026-10-14): 25% від 2 ГБ контейнера - це 512 МБ. По-друге, work_mem діє на кожну операцію сортування чи хешування, а не на з'єднання, тож сума може бути в багато разів більшою за задане значення: 23 з'єднання застосунку по 8 МБ із двома такими операціями кожне дають найгірший випадок 368 МБ. По-третє, пули помножені на процеси (2 x 10 + 3 = 23) мають лишатися нижче max_connections (50).

Диск і бекапи. Після приблизно 1,04 млн рядків база займала 146 МБ, а каталог даних - 457 МБ, із них 288 МБ - pg_wal: WAL залежить від max_wal_size (м'яке обмеження), а не від розміру даних, тому закладайте його окремо й залишайте вільними понад 20% диска. На цьому крихітному наборі даних pg_dump -Fc зайняв 0,59 с (7 МБ), а відновлення - 1,78 с; ваш час відновлення - це ваш простій, тож виміряйте його. У кожну ціну DCXV Cloud входить один тижневий бекап диска: це страхова копія, а не місце для ваших файлів.

Шукаємо вузьке місце за допомогою k6

Спершу зафіксуйте умову успіху (тут p95 нижче 300 мс і менше 1% невдалих запитів), використовуйте відкриту модель (constant-arrival-rate, див. документацію k6), піднімайте інтенсивність кроками й одночасно стежте за сигналами нижче.

Сигнал Команда Погана ознака
p95, помилки, пропущені ітерації підсумок k6 p95 понад ціль, сервер не встигає за інтенсивністю надходження
Тротлінг CPU grep nr_throttled /sys/fs/cgroup/cpu.stat у контейнері зростає під час кроку (документація ядра)
CPU steal vmstat 5, стовпець st вище 0 на VM: хост перевантажений
Тиск на пам'ять docker stats, vmstat, стовпці si so поблизу ліміту або свопінг

Виміряно на 12-ядерній машині arm64 з Linux і 14,4 ГБ 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, 2026-10-14, один прогін по 40 с на крок, якщо не наведено два значення. Це не DCXV Cloud. k6 ділив ядра CPU зі стеком, а хост ще й використовував своп, тож затримки завищені: для реального тесту запускайте k6 з другої машини. "Пропущено" - це надходження, які k6 пропустив, бо всі 500 віртуальних користувачів були зайняті.

Конфіг nginx Подано запитів/с Досягнуто запитів/с p95 Невдалі Пропущено
A, proxy 0,25 CPU 1000 610 2,11 с 0,03% 15 595
A, proxy 1,0 CPU 1000 994 і 997 150 мс і 51,5 мс 0% 207 і 121
A, proxy 1,0 CPU 2000 941 1,77 с 6,56% 42 356
B, keepalive 1000 999 і 1000 2,66 мс і 2,42 мс 0% 36 і 0
B, keepalive 5000 4995 1,48 мс 0% 206
B, keepalive 8000 7918 23,1 мс 0,02% 2532

Урок - у методі, а не в пропускній здатності. Конфіг A використовував proxy_pass зі змінною без блоку upstream, тож nginx відкривав нове TCP-з'єднання до API на кожен запит. Першим у ліміт CPU впирався проксі (cpu.stat: 1512 із 2787 періодів із тротлінгом при 0,25 CPU, а при 1,0 CPU стеля все одно близько 940 запитів/с), тоді як база використовувала значно менше половини свого ліміту. Конфіг B, upstream із keepalive 32, тримав проксі близько третини одного CPU на 8000 запитів/с. Наступні обмеження одразу проявилися в тих самих лічильниках: база мала тротлінг у 301 із 2790 періодів, а воркер із лімітом 0,25 CPU тротлився майже в кожному періоді й залишив у черзі 46 982 завдання (LLEN jobs). Набір даних 146 МБ вміщується в пам'ять, тож диска це не торкалося. Перевірка fio на тимчасовому файлі (fio --name=w --filename=fio.tmp --size=256M --rw=write --bs=8k --fdatasync=1 --ioengine=sync --runtime=15 --time_based) показала 700 синхронних записів на секунду, приблизно по 1,4 мс; прогін довільного читання (fio --name=r --filename=fio.tmp --size=256M --rw=randread --bs=4k --iodepth=32 --ioengine=libaio --direct=1 --runtime=15 --time_based) повідомив 399 000 IOPS - це кеш сторінок, а не диск.

Рахуємо ціну результату в конфігураторі

  1. Відкрийте сторінку хмарних серверів. Вона не зчитує числа з цієї статті, тож задайте їх самі: оберіть рядок плану, найближчий до вашого профілю (Small, Medium чи Large), потім підлаштуйте повзунки CPU (1-96), RAM (1-256 ГБ) і диска (20-960 ГБ) під значення з вашого аркуша.
  2. Додайте копії бекапу, додаткові адреси IPv4 і години адміністрування та дивіться повну місячну ціну, а не ціну "від". Кероване адміністрування починається від EUR 30 за дві години.

Перевірено за прайсом 2026-10-14: Medium із 3 бекапами - EUR 21.47, а той самий CPU із 16 ГБ RAM - EUR 29.95. Найбільше ціну змінює RAM.

Налаштувати хмарний сервер для вашого застосунку

Коли виносити базу даних або переходити на dedicated

  • Виносьте БД, коли їй потрібно понад половину пам'яті VM, коли API та БД тротлять одна одну за CPU або коли потрібен окремий ритм відновлення. Див. посібник із PostgreSQL.
  • Переходьте на dedicated, коли одне навантаження в пік тримає зайнятими понад 70% усіх vCPU, потребує більше за 96 vCPU чи 256 ГБ RAM, які дає хмарний сервер, або вимагає передбачуваної затримки диска. Див. виділені сервери.

Шаблон міграції та відкату

Спершу відрепетируйте його на новому сервері.

Крок Дія Відкат
1 Відновіть свіжий дамп на новому сервері, запустіть застосунок і проженіть навантажувальний тест видаліть новий сервер
2 Заморозьте запис, зробіть фінальний дамп, відновіть, порівняйте кількість рядків знову відкрийте запис на старому сервері
3 Перемкніть DNS (TTL знижено до 300 с за повний старий TTL наперед), перевірте вхід, замовлення, завдання й пошту поверніть DNS назад
4 Тримайте старий сервер у режимі читання щонайменше тиждень відтворіть нові записи на старому боці

Аркуш підбору ресурсів

Роздрукуйте його й заповніть праву колонку власними вимірами.

Пункт Як отримати Ваше значення
Пікові запити за секунду аналітика або навантажувальний тест
Цільовий p95 і частка помилок ваш SLO, наприклад 300 мс і 1%
Процеси API по одному на vCPU
Ліміт пам'яті контейнера піковий RSS під навантаженням плюс запас
З'єднання з БД пули x процеси, нижче max_connections
Вільна пам'ять 20-25% VM
Диск дані та ріст + WAL + логи + образи + тимчасовий дамп, потім 20% вільного
Бекапи скільки копій, виміряний час відновлення
Місячна ціна підсумок конфігуратора з бекапами, IPv4, адмін-годинами, дата

Відтворіть самі

Потрібні Docker із Compose, curl, openssl і vmstat; образ k6 завантажується під час першого запуску. Файли - ті самі, що ми запускали, із зазначеними версіями. Теги postgres:17-alpine, redis:7-alpine і node:22-alpine плаваючі, а npm install не має lock-файлу, тож зафіксуйте теги й версії, якщо потрібен той самий результат.

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

Ваші числа відрізнятимуться. Тоді довіряйте їм, а не нашим, і налаштуйте хмарний сервер під свій застосунок або напишіть на sales@dcxv.com.

Як підібрати хмарний сервер для SaaS: CPU, RAM, NVMe, бекапи
cloudinfrastructurepricing

Як підібрати хмарний сервер для SaaS: CPU, RAM, NVMe, бекапи

Підбір хмарного сервера для SaaS у Docker і Node.js: бюджет пам'яті, ліміти CPU, NVMe та бекапи, навантажувальний тест k6, повна місячна ціна й аркуш підбору.

AI-агенти для коду на VPS у ЄС: посилене налаштування
aicloudhosting

AI-агенти для коду на VPS у ЄС: посилене налаштування

Запускайте AI-агентів для коду на VPS у ЄС з обмеженнями: одноразові каталоги, білий список виходу, токени, ліміти, перевірений код, ризики та ціна сервера.

Як купити IPv4-адреси: вартість, правила трансферу, ризики
ipv4brokerpricingtransferripe-ncc

Як купити IPv4-адреси: вартість, правила трансферу, ризики

Купівля IPv4-адрес: оберіть купівлю, оренду чи BYOIP, оцініть повну вартість, перевірте блок, використайте ескроу та виконайте вимоги RIPE NCC, ARIN і APNIC.

Скільки коштує блок IPv4 /24, /22, /20 або /16 у 2026 році?
ipv4networkingpricing

Скільки коштує блок IPv4 /24, /22, /20 або /16 у 2026 році?

Ціни на блоки IPv4 у 2026 році: /24, /22, /20 і /16 за IP та за блок, що впливає на ціну, ask проти реальної угоди, додаткові витрати та оцінка блоку в DCXV.

Як продати IPv4-адреси у 2026: правила RIPE, ARIN, APNIC
ipv4brokerpricingtransfer

Як продати IPv4-адреси у 2026: правила RIPE, ARIN, APNIC

Як безпечно продати IPv4-адреси у 2026: придатність блоку, правила трансферу RIPE, ARIN і APNIC, чинники ціни, ескроу, документи та витрати на брокера.