Amazon EC2 — Elastic Compute Cloud
Amazon EC2 — Elastic Compute Cloud

Що таке EC2 і навіщо він вам потрібен
Уявіть, що вам потрібен комп'ютер — але не фізичний, який треба купувати, встановлювати в стійку, підключати кабелі та обслуговувати. Ви хочете просто замовити комп'ютер через інтернет, отримати до нього доступ через кілька хвилин і платити лише поки він працює. Саме це і є Amazon EC2 (Elastic Compute Cloud).
EC2 надає віртуальні сервери (офіційна назва — instances) у хмарі AWS. Кожен instance — це повноцінний комп'ютер з процесором, оперативною пам'яттю, дисковим простором та мережевим інтерфейсом. Ви можете запустити від одного до тисяч instances за лічені хвилини — і зупинити їх так само швидко.
Чому це важливо для .NET розробника?
Класичний шлях деплою .NET додатку: купуємо або орендуємо фізичний сервер → встановлюємо Windows Server або Linux → налаштовуємо IIS або nginx → деплоїмо застосунок. Цей процес займає дні або тижні і коштує фіксовану суму незалежно від навантаження.
З EC2: запускаємо instance з готовим образом операційної системи → встановлюємо .NET та IIS → деплоїмо → і сервер вже у production. Весь процес — кілька годин. Якщо навантаження зросло — запускаємо ще instances. Якщо впало — зупиняємо зайві. Платимо лише за фактичний час роботи.

EC2 Instance Types — вибір правильного сервера
Instance Type — це конфігурація hardware вашого віртуального сервера: скільки ядер CPU, скільки RAM, який тип мережевого з'єднання. AWS пропонує 600+ типів instances, згрупованих у сімейства за призначенням.
Формат назви: [сімейство][покоління].[розмір]
Наприклад: t3.micro — сімейство T (General Purpose), 3-тє покоління, розмір micro.
General Purpose (Загального призначення)
Найпопулярніша категорія — збалансоване співвідношення CPU та RAM. Ідеально для більшості .NET Web API, веб-сайтів, мікросервісів.
Сімейство T (Burstable Performance): t3.nano, t3.micro, t3.small, t3.medium, t3.large
Особливість T-instances: CPU Credits. В тихі моменти instance накопичує «кредити» CPU. При піковому навантаженні витрачає їх для короткочасного використання більш ніж базового % CPU. Це дозволяє мати дешевий instance, який справляється з рідкісними піками.
t3.micro— 2 vCPU, 1 GB RAM ← входить у Free Tier на 12 місяцівt3.small— 2 vCPU, 2 GB RAMt3.medium— 2 vCPU, 4 GB RAM ← мінімум для .NET 10 API з реальним навантаженнямt3.large— 2 vCPU, 8 GB RAM
Сімейство M (Fixed Performance): m6i.large, m6i.xlarge, m6i.2xlarge
Фіксований (не burstable) рівень CPU. Для production .NET застосунків зі стабільним навантаженням.
Compute Optimized (Оптимізовані під CPU)
Сімейство C: c6i.large, c6i.xlarge. Вище співвідношення CPU до RAM. Для CPU-інтенсивних задач: обробка зображень, відеотранскодування, ML inference, складні обчислення.
Memory Optimized (Оптимізовані під RAM)
Сімейство R: r6i.large, r6i.xlarge. Більше RAM відносно CPU. Для in-memory кешування (Redis/Memcached на тому ж instance), великих баз даних в пам'яті, .NET застосунків з великими Dataset.
Storage Optimized
Сімейство I та D: надвисока швидкість роботи з диском (NVMe SSD). Для баз даних з інтенсивним I/O, Elasticsearch, аналітичних задач.
t3.micro (Free Tier) для навчання, t3.medium для перших production застосунків. Тип завжди можна змінити — зупинити instance, змінити тип, запустити знову.T — Burstable (Free Tier)
t3.micro — Free Tier. Ідеально для розробки, навчання, низьконавантажених API.M — General Purpose
m6i.large — production .NET API зі стабільним навантаженням.C — Compute Optimized
c6i.large — CPU-інтенсивні задачі: обробка зображень, ML inference, відеотранскодування.R — Memory Optimized
r6i.large — in-memory кешування, великі Dataset, аналітика в пам'яті.EC2 Instance Lifecycle — стани та переходи
Кожен EC2 instance проходить через певні стани (states) протягом свого існування. Розуміння цих станів критично важливе: від них залежить тарифікація, збереження даних та IP-адреса після рестарту.
Стан stopped — зупинений, але не видалений
Stop — аналог «вимкнути комп'ютер». Instance зупинений, але існує: EBS томи зберігають усі дані, Security Groups залишаються, Instance ID не змінюється. Обчислення не тарифікуються, проте EBS-диски тарифікуються далі (~$0.08/GB/місяць для gp3).
Що відбувається при Stop → Start:
- AWS може перемістити instance на інший фізичний хост у тій самій AZ
- Публічна IP-адреса змінюється — якщо не прикріплений Elastic IP, DNS запис на старий IP перестане працювати
- Приватна IP (всередині VPC) — залишається незмінною
- Дані на всіх EBS томах — збережені
Коли використовувати Stop: dev-сервери, які не потрібні вночі або у вихідні — зупиняєте ввечері, запускаєте вранці. Платите лише за EBS (~$1.6/місяць за 20 GB gp3), не за EC2.
Стан terminated — незворотнє видалення
Terminate — «видалити комп'ютер назавжди». Після переходу в shutting-down → terminated instance неможливо відновити. За замовчуванням root EBS том також видаляється (параметр «Delete on termination»). Додаткові EBS томи можна налаштувати на збереження.
Стан rebooting — перезавантаження без зміни хосту
На відміну від Stop → Start, Reboot залишає instance на тому самому фізичному хості. Публічна IP-адреса не змінюється. Тарифікація не переривається. Рекомендований для застосування оновлень ОС, що вимагають перезапуску.
Hibernate — збереження RAM на диск
Hibernate — особливий режим зупинки: вміст оперативної пам'яті зберігається на root EBS томі. При наступному запуску instance відновлюється з точного стану: всі процеси продовжуються, з'єднання відновлюються — схоже на режим сну ноутбука.
Вимоги: instance type підтримує Hibernate (T3, M5, C5, R5 та ін.), root EBS обов'язково зашифрований, RAM ≤ 150 GB, тривалість Hibernate ≤ 60 днів.
| Дія | CPU тарифікація | Публічний IP | Дані на EBS | Відновлення |
|---|---|---|---|---|
| Stop | Ні | Змінюється | Збережені | Start (~1-2 хв) |
| Hibernate | Ні | Змінюється | Збережені + RAM | Start (~30 сек) |
| Reboot | Так (без перерви) | Не змінюється | Збережені | Авто (~30 сек) |
| Terminate | Ні | Звільняється | Видаляються (root) | Неможливо |
t3.micro у Free Tier — 750 годин на місяць у стані running. У стані stopped Free Tier-ліміт не витрачається, але EBS у Free Tier обмежений — 30 GB загалом.
AMI — Amazon Machine Image
AMI (Amazon Machine Image) — це готовий «шаблон» операційної системи з попередньо встановленим програмним забезпеченням. Коли ви запускаєте EC2 instance — ви вказуєте AMI, і instance «клонується» з цього шаблону.
Думайте про AMI як про знімок жорсткого диска (snapshot): включає ОС, всі встановлені програми, конфігурацію. Запуск instance з AMI — це як розгортання готового диска на новому комп'ютері.
Типи AMI
AWS Managed AMI — офіційні образи від Amazon та партнерів:
- Amazon Linux 2023 — власний дистрибутив AWS, оптимізований для EC2. Рекомендований для більшості Linux-задач.
- Ubuntu Server 26.04 LTS — популярний серед розробників. Відмінна підтримка .NET.
- Windows Server 2022 — для .NET Framework та IIS. Включає ліцензію Windows у вартість EC2.
- Windows Server 2022 with SQL Server — для застосунків з MS SQL Server.
- Red Hat Enterprise Linux (RHEL) — для корпоративних середовищ.
AWS Marketplace AMI — образи від третіх сторін з попередньо встановленим ПЗ (платні або безкоштовні): Bitnami WordPress, GitLab CE, Nginx Plus тощо.
Community AMI — публічні образи від спільноти. Використовуйте з обережністю — перевіряйте джерело.
Custom AMI (ваші власні) — ви можете створити AMI зі свого налаштованого instance. Зручно для auto scaling: замість того, щоб кожен новий сервер встановлював .NET та конфігурував застосунок — він одразу стартує з готовим середовищем.
AMI та регіони
Важливий нюанс: AMI прив'язані до регіону. AMI, доступна у eu-central-1, недоступна у us-east-1 — потрібно скопіювати. ID однієї й тієї ж ОС різниться між регіонами.
Знайти актуальний AMI ID для Ubuntu 26.04 у вашому регіоні:
aws ec2 describe-images \
--owners 099720109477 \
--filters "Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-resolute-26.04-amd64-server-*" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" \
--output text --region eu-central-1
# ami-0a1b2c3d4e5f67890
Тут 099720109477 — це офіційний AWS Account ID компанії Canonical (розробника Ubuntu). Це гарантує, що ви отримаєте справжній офіційний образ.

EC2 Pricing Models — моделі оплати
Ціна EC2 залежить не лише від типу instance, але і від моделі оплати. Правильний вибір може заощадити 50–90% витрат.
On-Demand — оплата по факту
Принцип: платите за кожну секунду роботи instance. Немає зобов'язань, немає передоплати. Запустили — платите. Зупинили — не платите.
Коли використовувати: навчання, розробка, тестування, нерегулярні задачі, коли ви ще не знаєте, скільки ресурсів потрібно.
Ціна (eu-central-1): t3.micro ≈ $0.0116/год ≈ $8.4/місяць при 24/7 роботі.
Reserved Instances та Savings Plans
Принцип: ви зобов'язуєтесь використовувати певну кількість ресурсів протягом 1 або 3 років і отримуєте знижку 30–75% відносно On-Demand.
Reserved Instances (RI): резервуєте конкретний тип instance (t3.medium) у конкретному регіоні. Якщо вам раптом потрібен більший instance — RI не застосовується.
Savings Plans: гнучкіша альтернатива. Ви зобов'язуєтесь витрачати N доларів на годину (наприклад $0.05/год), а знижка застосовується автоматично до будь-яких EC2 instances та Lambda, навіть якщо ви змінили тип.
Коли використовувати: для production серверів, які працюють 24/7 протягом тривалого часу.
Spot Instances — найдешевші, але переривувані
Принцип: AWS продає невикористані EC2 потужності зі знижкою 60–90% відносно On-Demand. Але якщо ці потужності знадобляться AWS — ваш instance може бути примусово зупинений з попередженням за 2 хвилини.
Коли використовувати: batch-обробка даних, ML-тренування, відеорендеринг, CI/CD pipeline — задачі, які можна перервати і продовжити.
Коли НЕ використовувати: для production web-сервера, де переривання неприпустиме.
On-Demand
Savings Plans
Spot Instances

EBS — Elastic Block Store (диски для EC2)
EBS (Elastic Block Store) — це мережеві диски (аналог жорстких дисків), які підключаються до EC2 instances. Кожен EC2 instance має щонайменше один EBS том — root volume з операційною системою.
Ключова особливість EBS: дані зберігаються незалежно від EC2 instance. Якщо зупинити або навіть видалити instance — EBS том залишається і дані не втрачаються (якщо не увімкнено «Delete on termination»).
Типи EBS томів
gp3 (General Purpose SSD) — рекомендований для більшості задач. 3000 IOPS та 125 MB/s за замовчуванням (можна збільшити незалежно від розміру). Ціна: ~$0.08/GB/місяць.
gp2 (застарілий General Purpose SSD) — попереднє покоління. IOPS прив'язані до розміру (3 IOPS/GB). Уникайте для нових проєктів.
io2 (Provisioned IOPS SSD) — для баз даних з інтенсивним I/O. До 64,000 IOPS. Дорожче.
st1 (Throughput Optimized HDD) — для великих об'ємів послідовного читання/запису. Дешевший за SSD, але повільніший.
EBS Snapshots — резервні копії
Snapshot — це точкова копія EBS тому, збережена в S3. Використовується для:
- Резервного копіювання даних
- Переміщення даних між регіонами
- Створення AMI з поточного стану instance
- Відновлення instance до попереднього стану
Instance Store — надшвидке тимчасове сховище
Поряд з EBS існує інший тип сховища — Instance Store (ephemeral storage). Це фізично вбудовані NVMe SSD диски на тому самому хості, де запущений instance. Доступний лише для певних типів instances: сімейства i4i, i3, d3, m5d, c5d, r5d та ін.
Характеристики Instance Store:
- Надзвичайна швидкість: без мережевого hop до окремого сховища — затримка менше 0.1 мс, IOPS до мільйонів.
i4i.xlargeдає до 625,000 IOPS проти ~16,000 у gp3 EBS - Тимчасовий (ephemeral): дані повністю знищуються при Stop, Terminate або апаратному збої хоста. При Reboot — зберігаються
- Включений у вартість: Instance Store не тарифікується окремо — ціна входить у cost instance type
| Характеристика | EBS gp3 | Instance Store |
|---|---|---|
| Persistence | Зберігається при Stop | Знищується при Stop |
| IOPS | до 16,000 | до 3.3 млн |
| Latency | 0.5–4 мс | < 0.1 мс |
| Ціна | ~$0.08/GB/місяць | Включена в instance |
| EBS Snapshot | Так | Ні |
| Зміна розміру | Так (без зупинки) | Ні (фіксований) |
| Призначення | Основне сховище | Кеш, буфери, scratch |
Типові сценарії: кеш Elasticsearch (дані є в основному сховищі), буфер черги повідомлень із реплікацією, проміжні файли при обробці відео або ML-пайплайні, scratch space для великих обчислень.

Security Groups — файрвол для EC2
Security Group — це віртуальний файрвол, який контролює вхідний (inbound) і вихідний (outbound) мережевий трафік для EC2 instance. Думайте про нього як про список правил: «дозволити трафік з порту 80» або «заборонити все, крім SSH з нашого IP».
Ключові властивості Security Groups:
- Stateful (з відстеженням стану): якщо дозволено вхідне з'єднання — відповідний вихідний трафік дозволяється автоматично, і навпаки. Вам не потрібно додавати окреме правило для «відповідь на запит».
- Дозвільні, не забороняючі: у Security Groups можна лише дозволяти трафік. Не можна написати «заборонити з IP 1.2.3.4». Для заборони — використовуйте NACL.
- Можна призначити кілька Security Groups одному instance.
- За замовчуванням: весь вхідний трафік заборонений, весь вихідний — дозволений.
Правила Security Group
Кожне правило описує:
| Поле | Приклад | Опис |
|---|---|---|
| Type | HTTP, SSH, Custom TCP | Тип трафіку (HTTP автоматично ставить порт 80) |
| Protocol | TCP, UDP, ICMP | Протокол |
| Port Range | 80, 443, 8080, 22 | Порт або діапазон портів |
| Source | 0.0.0.0/0, 203.0.113.5/32, sg-xxx | Звідки дозволений трафік |
Source 0.0.0.0/0 — означає «з будь-якого IP у світі». Використовуйте лише для публічних портів (80, 443).
Source 203.0.113.5/32 — лише з конкретного IP (наприклад, ваш домашній IP). /32 означає один конкретний IP. Ідеально для SSH — не відкривайте 22 порт для всього світу!
Source sg-0a1b2c3d — лише від інших EC2 instances з цим Security Group. Зручно для мікросервісної архітектури: API може звертатись до БД лише якщо знаходиться в тій самій Security Group.
Security Groups vs NACLs
Студенти часто плутають ці два механізми. Ось принципова різниця:
| Характеристика | Security Group | Network ACL (NACL) |
|---|---|---|
| Рівень застосування | EC2 Instance | Subnet |
| Тип правил | Лише Allow | Allow та Deny |
| Stateful/Stateless | Stateful | Stateless |
| Порядок правил | Усі правила перевіряються | Правила нумеровані, першe спрацьоване |
| Типове використання | Щоденне управління доступом | Блокування діапазонів IP |
Для більшості задач достатньо Security Groups. NACLs — додатковий шар захисту для специфічних сценаріїв (наприклад, заблокувати країну або діапазон IP після DDoS атаки).
VPC — Virtual Private Cloud та мережева топологія EC2
Кожен EC2 instance запускається всередині VPC (Virtual Private Cloud) — ізольованої приватної мережі у хмарі AWS. Розуміння VPC необхідне для проєктування безпечної архітектури: саме VPC визначає, хто може звертатись до вашого instance і куди сам instance може ходити в мережі.
AWS автоматично створює Default VPC у кожному регіоні з готовими публічними підмережами та Internet Gateway. Для навчання та простих проєктів Default VPC цілком підходить — саме його ми використовуємо у практичних прикладах цього розділу.
Public Subnet vs Private Subnet
Public Subnet (публічна підмережа) — підмережа, таблиця маршрутизації якої містить маршрут 0.0.0.0/0 → igw-xxx до Internet Gateway. Instances тут мають публічний IP і доступні з інтернету (якщо дозволяє Security Group). Сюди розміщують: Application Load Balancer, Bastion Host, публічні API, Elastic IP.
Private Subnet (приватна підмережа) — підмережа без маршруту до IGW. Instances недоступні з інтернету напряму — навіть якщо у них є публічний IP (він є, але маршрут відсутній). Ідеальне місце для: RDS, ElastiCache, backend-сервісів, черг повідомлень.
Internet Gateway та NAT Gateway
Internet Gateway (IGW) забезпечує двонаправлений трафік між instances у public subnet та інтернетом. Один на VPC, горизонтально масштабований, завжди доступний. Безкоштовний.
NAT Gateway дозволяє instances у private subnet ініціювати вихідні з'єднання (завантажувати оновлення, пакети, звертатись до AWS API), але не дає зовнішнім клієнтам ініціювати вхідні з'єднання. Тобто App Server у private subnet може apt-get update, проте підключитись до нього ззовні неможливо. NAT Gateway платний: $0.045/год ($32/місяць) + трафік ~$0.045/GB.
CIDR — запис діапазонів IP-адрес
CIDR (Classless Inter-Domain Routing) — формат IP/prefix, де prefix — кількість фіксованих бітів:
10.0.0.0/16→ 65,536 адрес (10.0.0.0 – 10.0.255.255) — типово для VPC10.0.1.0/24→ 256 адрес (10.0.1.0 – 10.0.1.255) — типово для subnet203.0.113.5/32→ одна конкретна адреса — для SSH правила у Security Group0.0.0.0/0→ будь-яка адреса у світі — для публічних HTTP/HTTPS правил
Зони доступності та відмовостійкість
Підмережа прив'язана до однієї Availability Zone. Best practice для production: мінімум дві підмережі (public + private) у різних AZ. Тоді збій однієї фізичної зони AWS не вимикає весь застосунок — Application Load Balancer автоматично перенаправляє трафік до instances в іншій AZ.

Elastic IP — стала публічна IP-адреса
За замовчуванням кожен раз, коли ви зупиняєте і запускаєте EC2 instance — він отримує нову публічну IP-адресу. Це проблема для production: DNS запис вказує на стару IP, і після рестарту сервер «зникає» з інтернету.
Elastic IP (EIP) — це стала публічна IP-адреса, яку ви можете прикріпити до будь-якого EC2 instance. При зупинці/запуску instance — EIP залишається незмінним.
Важливо про ціну: Elastic IP безкоштовний, поки він прикріплений до запущеного instance. Але якщо EIP виділений але не прикріплений (або прикріплений до зупиненого instance) — він коштує $0.005/год ($3.6/місяць). AWS стягує плату за невикористані IP, щоб не допустити вичерпання пулу публічних адрес.
CloudWatch та моніторинг EC2
Запустити застосунок — лише половина роботи. Щоб впевнено керувати production-сервером, потрібно спостерігати за ним: знати завантаження CPU та пам'яті, стежити за здоров'ям instance, отримувати сповіщення до того, як про проблему повідомить користувач. Amazon CloudWatch — сервіс моніторингу AWS, який автоматично збирає метрики з EC2, зберігає логи та надсилає сповіщення.
Стандартні метрики EC2 (без налаштувань, безкоштовно)
AWS автоматично збирає метрики на рівні гіпервізора кожні 5 хвилин. При Detailed Monitoring (~$0.01/метрика/місяць) — кожну хвилину:
| Метрика | Що вимірює | Рекомендований поріг |
|---|---|---|
CPUUtilization | % використання CPU | Alarm при > 80% |
NetworkIn / NetworkOut | Байти мережевого трафіку | Аналіз тренду |
DiskReadOps / DiskWriteOps | IOPS операцій до EBS | < 3000 для gp3 baseline |
StatusCheckFailed_Instance | Збій перевірки всередині ОС | Alarm при > 0 |
StatusCheckFailed_System | Збій апаратного хосту | Alarm при > 0 |
Критична відсутність: стандартні метрики не включають MemoryUtilization та заповненість диска — ці дані недоступні на рівні гіпервізора. Для них потрібен CloudWatch Agent.
CloudWatch Agent — RAM, диск та логи застосунку
CloudWatch Agent — легкий демон, що збирає метрики ОС та надсилає логи застосунку у CloudWatch. Встановлення на Ubuntu:
# Встановлення агента
sudo apt-get install -y amazon-cloudwatch-agent
# Мінімальна конфігурація: RAM + диск + логи застосунку
sudo tee /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json > /dev/null <<'EOF'
{
"metrics": {
"append_dimensions": { "InstanceId": "${aws:InstanceId}" },
"metrics_collected": {
"mem": { "measurement": ["mem_used_percent"], "metrics_collection_interval": 60 },
"disk": { "measurement": ["disk_used_percent"], "resources": ["/"], "metrics_collection_interval": 60 }
}
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [{
"file_path": "/var/app/logs/app.log",
"log_group_name": "/ec2/dotnet-api",
"log_stream_name": "{instance_id}"
}]
}
}
}
}
EOF
# Запуск агента
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config -m ec2 \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s
CloudWatchAgentServerPolicy — додайте її до ролі, прикріпленої до EC2 instance. Без цього дозволу агент не зможе надсилати метрики та логи.CloudWatch Alarms — автоматичні сповіщення
Alarm спрацьовує коли метрика порушує поріг і надсилає сповіщення через SNS (email, Slack, PagerDuty) або запускає Auto Scaling:
# Alarm: CPU > 80% протягом 5 хвилин
aws cloudwatch put-metric-alarm \
--alarm-name "high-cpu-dotnet-api" \
--metric-name CPUUtilization \
--namespace AWS/EC2 \
--dimensions Name=InstanceId,Value=$INSTANCE_ID \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:eu-central-1:123456789012:alert-topic \
--region eu-central-1
# Alarm: instance health check failed → негайне сповіщення
aws cloudwatch put-metric-alarm \
--alarm-name "instance-status-failed" \
--metric-name StatusCheckFailed_Instance \
--namespace AWS/EC2 \
--dimensions Name=InstanceId,Value=$INSTANCE_ID \
--statistic Maximum \
--period 60 \
--threshold 0 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:eu-central-1:123456789012:alert-topic \
--region eu-central-1
CPUUtilization > 80% (перевантаження), StatusCheckFailed_Instance > 0 (instance недоступний), disk_used_percent > 85% (через CloudWatch Agent — диск майже повний). Ці три алерми покривають найпоширеніші аварійні ситуації.
EC2 User Data — автоматизація при запуску
User Data — це скрипт (bash або PowerShell), який виконується один раз при першому запуску EC2 instance. Це механізм автоматичного налаштування сервера без ручного SSH-підключення.
Приклад User Data для Ubuntu з автоматичним встановленням .NET 10:
#!/bin/bash
# Цей скрипт виконається автоматично при першому запуску instance
# Оновлюємо список пакетів (аналог "перевірити оновлення" у Windows)
apt-get update -y
# .NET 10 входить до стандартних репозиторіїв Ubuntu 26.04 —
# додатковий репозиторій Microsoft не потрібен
# Встановлюємо .NET 10 Runtime (лише для запуску, не розробки)
apt-get install -y dotnet-runtime-10.0
# Створюємо директорію для застосунку
mkdir -p /var/app
# Записуємо лог — щоб переконатись, що скрипт виконався
echo "Setup completed at $(date)" >> /var/app/setup.log
User Data для Windows Server (PowerShell):
<powershell>
# Встановити .NET 10 Hosting Bundle (включає Runtime і IIS модуль)
$url = "https://download.microsoft.com/download/dotnet/10.0/aspnetcore-runtime-10.0.0-win-x64.exe"
$installer = "C:\aspnetcore-installer.exe"
Invoke-WebRequest -Uri $url -OutFile $installer
Start-Process -FilePath $installer -ArgumentList "/quiet /norestart" -Wait
# Встановити IIS та необхідні компоненти
Install-WindowsFeature -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console -IncludeManagementTools
# Записати лог
"Setup completed at $(Get-Date)" | Out-File C:\setup.log
</powershell>

EC2 Instance Metadata Service (IMDS)
Instance Metadata Service (IMDS) — це внутрішній HTTP-сервіс, доступний з будь-якого EC2 instance за адресою http://169.254.169.254. Він надає інформацію про сам instance: ID, тип, регіон, IAM Role, публічний IP тощо.
Ця адреса (169.254.169.254) — спеціальна «link-local» адреса, доступна лише зсередини instance. Жоден зовнішній комп'ютер не може звернутись до IMDS ззовні — це внутрішній сервіс EC2.
Навіщо IMDS .NET розробнику:
- AWS SDK for .NET автоматично звертається до IMDS для отримання IAM Role credentials — саме завдяки цьому ваш код на EC2 не потребує Access Keys
- Можна отримати публічний IP instance прямо зсередині коду — без зовнішніх запитів
- Визначити, в якому регіоні запущений instance
curl http://169.254.169.254/latest/meta-data/instance-id
# i-1234567890abcdef0
curl http://169.254.169.254/latest/meta-data/public-ipv4
# 3.64.185.42
curl http://169.254.169.254/latest/meta-data/instance-type
# t3.medium
curl -s http://169.254.169.254/latest/meta-data/placement/region
# eu-central-1
IMDSv2 — безпечніша версія: AWS рекомендує використовувати IMDSv2, яка вимагає спочатку отримати токен, а потім використовувати його для запитів. Це захищає від Server-Side Request Forgery (SSRF) атак.
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id
# i-1234567890abcdef0
IAM Role для EC2 — безпечний доступ без хардкоду ключів
Коли .NET код на EC2 звертається до AWS-сервісів (S3, DynamoDB, SQS, Secrets Manager), йому потрібні облікові дані (credentials) — щоб AWS міг верифікувати, від чийого імені виконуються запити і чи є на це дозвіл. Початківці часто допускають критичну помилку безпеки: хардкодять AWS_ACCESS_KEY_ID та AWS_SECRET_ACCESS_KEY прямо у appsettings.json або .env файл на сервері. Якщо такий файл потрапить у публічний Git-репозиторій — автоматичні сканери знайдуть і використають ці ключі за лічені хвилини.
Правильне рішення — IAM Role, прикріплена до EC2 instance. AWS SDK отримує тимчасові автоматично-ротовані credentials через IMDS. Жодного хардкоду. Жодного ризику витоку ключів.
Як це працює технічно
- Адміністратор створює IAM Role з двома складовими:
- Trust Policy — хто може «взяти» (assume) цю роль. Для EC2:
"Service": "ec2.amazonaws.com" - Permission Policy — що ця роль може робити (наприклад
s3:GetObjectна конкретний bucket)
- Trust Policy — хто може «взяти» (assume) цю роль. Для EC2:
- Роль прикріплюється до EC2 через Instance Profile (контейнер для ролі — створюється автоматично через Console)
- AWS STS (Security Token Service) видає тимчасові credentials (AccessKeyId + SecretAccessKey + SessionToken) з TTL ~1 година, розміщуючи їх у IMDS за адресою
/latest/meta-data/iam/security-credentials/{role-name} - AWS SDK for .NET автоматично запитує ці credentials з IMDS і оновлює їх до закінчення TTL — без жодного коду з вашого боку
Приклад: надати EC2 доступ до S3
- IAM → Roles → Create role
- Trusted entity: AWS service → EC2 → Next
- Permissions: знайдіть і оберіть
AmazonS3ReadOnlyAccess→ Next - Role name:
ec2-s3-readonly-role→ Create role - EC2 → Instances → ваш instance → Actions → Security → Modify IAM role
- Оберіть
ec2-s3-readonly-role→ Update IAM role
# 1. Створити роль з Trust Policy для EC2
aws iam create-role \
--role-name ec2-s3-readonly-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# 2. Прикріпити managed policy (S3 read-only)
aws iam attach-role-policy \
--role-name ec2-s3-readonly-role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 3. Створити Instance Profile та додати роль
aws iam create-instance-profile \
--instance-profile-name ec2-s3-readonly-profile
aws iam add-role-to-instance-profile \
--instance-profile-name ec2-s3-readonly-profile \
--role-name ec2-s3-readonly-role
# 4. Прикріпити до запущеного instance
aws ec2 associate-iam-instance-profile \
--instance-id $INSTANCE_ID \
--iam-instance-profile Name=ec2-s3-readonly-profile \
--region eu-central-1
Використання у .NET коді
З прикріпленою IAM Role AWS SDK for .NET автоматично знаходить credentials — жодного конфігурування не потрібно:
// Нічого конфігурувати! SDK сам знайде credentials через ланцюжок провайдерів:
// 1. Змінні середовища → 2. ~/.aws/credentials → 3. IAM Role через IMDS ← спрацює на EC2
var s3Client = new AmazonS3Client(RegionEndpoint.EUCentral1);
// Читання конфігу зі S3 замість хардкоду у репозиторії
var response = await s3Client.GetObjectAsync("my-config-bucket", "appsettings.Production.json");
using var reader = new StreamReader(response.ResponseStream);
var configJson = await reader.ReadToEndAsync();
SDK автоматично оновлює тимчасові credentials до закінчення TTL — ваш код не зупиняється при ротації.
AmazonS3FullAccess. Натомість — власна policy з s3:GetObject та s3:ListBucket на arn:aws:s3:::my-bucket/*. Це мінімізує збитки у разі компрометації instance.
EC2 Instance Connect — підключення без SSH ключів
EC2 Instance Connect — це сервіс AWS, який дозволяє підключитись до EC2 через браузер або CLI без збереження SSH приватних ключів локально. AWS тимчасово завантажує ваш публічний ключ у instance на 60 секунд.
Через Console: EC2 → Instances → оберіть instance → Connect → вкладка EC2 Instance Connect → Connect. Відкриється термінал прямо у браузері.
Через CLI:
SSH Key Pair та PEM — аутентифікація без пароля
Коли ви підключаєтесь до EC2 через SSH — AWS не просить ввести пароль. Замість цього використовується асиметрична криптографія: пара математично пов'язаних ключів. Для студентів, які звикли до логін/пароль — це принципово інший підхід, і важливо зрозуміти, як він працює.
Асиметрична криптографія: дві половини одного ключа
Звичайна (симетрична) криптографія: один ключ, яким і шифрують, і розшифровують. Якщо цей ключ вкрасти — система компрометована.
Асиметрична криптографія (Public-Key Cryptography) використовує дві математично пов'язані частини:
Публічний ключ (Public Key)
Приватний ключ (Private Key)
Математична властивість: пара генерується так, що з публічного ключа практично неможливо відновити приватний — навіть за необмеженого часу та потужності комп'ютерів сучасної ери. Алгоритм RSA базується на задачі факторизації великих чисел (1024–4096 біт), Ed25519 — на математиці еліптичних кривих.
Що таке .pem файл?
PEM (Privacy Enhanced Mail) — текстовий формат для зберігання криптографічних об'єктів: ключів, сертифікатів. Назва застаріла (формат виник в email-стандартах 1990-х), але використовується досі.
PEM-файл — це Base64-закодований двійковий об'єкт між текстовими маркерами:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0Z3VS5JJcds3xHn/ygWep4AyHgMZJmANwNdGv4VWBWCA
...кілька сотень символів Base64...
tQJ5LMzKvOkzjJHJHAIDAQABAoIBAC5RgZ+hBx7xHNaMpPgwGALBSa9BFKQR
-----END RSA PRIVATE KEY-----
Файл .pem — це лише контейнер. Він може містити:
- RSA приватний ключ (що й відбувається при створенні EC2 Key Pair)
- Сертифікат X.509 (HTTPS-сертифікат вашого сайту — теж у PEM-форматі)
- Ланцюжок сертифікатів (Certificate Authority chain)
.pem, .key, .crt — часто лише різні розширення для одного й того ж Base64-формату. Відрізнити можна лише за -----BEGIN ...----- маркером всередині.Як EC2 Key Pair працює: від генерації до входу
При натисканні Create key pair у AWS Console відбувається наступне:
1. AWS генерує пару RSA-2048 або Ed25519 ключів на своїх серверах
2. Публічний ключ → зберігається в AWS, записується в EC2 instance при запуску
(у файл /home/ubuntu/.ssh/authorized_keys)
3. Приватний ключ → завантажується вам у вигляді .pem файлу і ВИДАЛЯЄТЬСЯ з AWS
4. AWS більше не має вашого приватного ключа — лише ви
Тому якщо ви втратили .pem файл — підключитись до цього instance вже неможливо (лише через EC2 Instance Connect або монтування EBS-тому до іншого instance).
Порівняння: пароль vs ключ
| Критерій | Пароль | SSH Key Pair |
|---|---|---|
| Передача по мережі | Пароль/хеш передається | Приватний ключ ніколи не передається |
| Brute-force | Вразливий (можна перебрати) | Неможливий (2048-бітний ключ) |
| Фішинг | Можна обманом отримати | Не допоможе без файлу |
| Зручність | Потрібно пам'ятати | Потрібен доступ до файлу |
| Зберігання на сервері | Хеш паролю у /etc/shadow | Публічний ключ у authorized_keys |
| Відкликання | Змінити пароль | Видалити рядок з authorized_keys |
Формати ключів: .pem vs .ppk
Mac / Linux — SSH вбудований у систему і підтримує .pem напряму:
ssh -i ~/.ssh/ec2-lab-key.pem ubuntu@1.2.3.4
Windows — старіші версії використовують PuTTY, який має власний формат .ppk. При створенні ключа в AWS Console для Windows потрібно обирати .ppk. Якщо у вас .pem, конвертуйте через PuTTYgen.
ssh -i працює так само, як на Mac/Linux. .ppk потрібен лише якщо ви використовуєте PuTTY свідомо.Безпека: chmod 400 та зберігання ключа
Коли SSH-клієнт бачить, що файл ключа доступний не лише власнику — він відмовляється його використовувати і видає помилку:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'ec2-lab-key.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Команда chmod 400 ~/.ssh/ec2-lab-key.pem встановлює права -r--------: читання дозволено лише власнику, нікому більше.
400 = 4 (read) + 0 (---) + 0 (---) = власник може читати, група і всі інші — нічого
Де зберігати .pem файл:
- ✅
~/.ssh/— стандартна директорія для SSH-ключів - ✅ Менеджер паролів з можливістю зберігання файлів (1Password, Bitwarden)
- ✅ Зашифрований архів у хмарному сховищі
- ❌ Робочий стіл, папка Downloads, будь-яке синхронізоване сховище без шифрування
- ❌ Git-репозиторій (навіть приватний)
.pem файл у Git — негайно видаліть Key Pair в AWS Console і створіть новий. Навіть якщо репозиторій приватний — він міг бути вже прочитаний до видалення.
Практичний приклад: .NET 10 API на Linux (Ubuntu) від А до Я
У цьому прикладі ми запустимо EC2 instance з Ubuntu, встановимо .NET 10, задеплоїмо ASP.NET Core API і налаштуємо його як системний сервіс, що автоматично стартує при перезапуску сервера.
Крок 1: Запуск EC2 instance
- Відкрийте EC2 у AWS Console → Instances → Launch instances
- Name:
dotnet-api-server - Application and OS Images (AMI):
- Натисніть Ubuntu у Quick Start
- Оберіть Ubuntu Server 26.04 LTS (HVM), SSD Volume Type
- Architecture: 64-bit (x86)
- Instance type:
t3.micro(Free Tier) абоt3.mediumдля реального навантаження - Key pair (login):
- Натисніть Create new key pair
- Key pair name:
ec2-lab-key - Key pair type: RSA
- Private key file format: .pem (для Mac/Linux) або .ppk (для Windows з PuTTY)
- Натисніть Create key pair — файл
.pemавтоматично завантажиться - Збережіть цей файл! Його неможливо завантажити повторно.
- Network settings:
- Натисніть Edit
- VPC: залиште default
- Subnet: залиште default
- Auto-assign public IP: Enable
- Firewall (security groups): Create security group
- Security group name:
dotnet-api-sg - ✅ Allow SSH traffic from: My IP (AWS автоматично визначить ваш поточний IP)
- ✅ Allow HTTP traffic from the internet (порт 80)
- Security group name:
- Configure storage: 20 GB gp3 (достатньо)
- Натисніть Launch instance
# Крок 1a: Знайдіть актуальний Ubuntu 26.04 AMI ID у вашому регіоні
AMI_ID=$(aws ec2 describe-images \
--owners 099720109477 \
--filters "Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-resolute-26.04-amd64-server-*" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" \
--output text --region eu-central-1)
echo "AMI ID: $AMI_ID"
# Крок 1b: Знайдіть ваш default VPC ID
VPC_ID=$(aws ec2 describe-vpcs \
--filters "Name=isDefault,Values=true" \
--query "Vpcs[0].VpcId" --output text --region eu-central-1)
# Крок 1c: Створіть Security Group
SG_ID=$(aws ec2 create-security-group \
--group-name dotnet-api-sg \
--description "Security group for .NET API" \
--vpc-id $VPC_ID \
--region eu-central-1 \
--query GroupId --output text)
# Крок 1d: Дозвольте SSH лише з вашого поточного IP
MY_IP=$(curl -s https://checkip.amazonaws.com)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--protocol tcp --port 22 \
--cidr "${MY_IP}/32" --region eu-central-1
# Крок 1e: Дозвольте HTTP з будь-якого IP
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--protocol tcp --port 80 \
--cidr 0.0.0.0/0 --region eu-central-1
# Крок 1f: Дозвольте port 5000 (для тестування .NET без reverse proxy)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--protocol tcp --port 5000 \
--cidr 0.0.0.0/0 --region eu-central-1
# Крок 1g: Створіть SSH key pair
aws ec2 create-key-pair \
--key-name ec2-lab-key \
--region eu-central-1 \
--query "KeyMaterial" --output text > ~/.ssh/ec2-lab-key.pem
# Встановіть правильні права на файл ключа (обов'язково!)
chmod 400 ~/.ssh/ec2-lab-key.pem
# Крок 1h: Запустіть instance
INSTANCE_ID=$(aws ec2 run-instances \
--image-id $AMI_ID \
--instance-type t3.micro \
--key-name ec2-lab-key \
--security-group-ids $SG_ID \
--region eu-central-1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=dotnet-api-server}]' \
--query "Instances[0].InstanceId" --output text)
echo "Instance ID: $INSTANCE_ID"
Зачекайте ~2 хвилини поки instance запуститься. Стан зміниться з pending на running.
Крок 2: Підключення до сервера через SSH
SSH (Secure Shell) — це протокол для безпечного підключення до віддаленого комп'ютера через термінал. Це як «Remote Desktop» але текстовий. Для Linux серверів SSH — стандартний спосіб роботи.
Спочатку знайдіть публічну IP-адресу вашого instance:
- EC2 → Instances → оберіть
dotnet-api-server - У вкладці Details знайдіть Public IPv4 address
- Скопіюйте цей IP (наприклад:
3.64.185.42)
# ЗАМІНІТЬ i-1234567890abcdef0 на ваш реальний Instance ID
aws ec2 describe-instances \
--instance-ids $INSTANCE_ID \
--query "Reservations[0].Instances[0].PublicIpAddress" \
--output text --region eu-central-1
Тепер підключіться через SSH:
Пояснення команди SSH:
ssh— команда для підключення-i ~/.ssh/ec2-lab-key.pem— прапорець-iвказує файл ключа автентифікації.~означає вашу домашню директорію (/Users/yournameна Mac,C:\Users\yournameна Windows)ubuntu@3.64.185.42— ім'я користувача (ubuntuдля Ubuntu AMI) та IP-адреса сервера
Після підключення ви побачите запрошення командного рядка (ubuntu@ip-172-31-10-25:~$) — це означає, що ви знаходитесь всередині сервера. Всі наступні команди виконуються на сервері, не на вашому комп'ютері.
Permission denied (publickey) — переконайтесь, що файл ключа має права 400: chmod 400 ~/.ssh/ec2-lab-key.pemКрок 3: Встановлення .NET 10 на Ubuntu
Ви вже підключені до сервера через SSH. Виконайте наступні команди одну за одною.
Що таке apt-get? Це менеджер пакетів Ubuntu — аналог Chocolatey для Windows або Homebrew для Mac. Командою apt-get install ви встановлюєте програми, командою apt-get update — оновлюєте список доступних пакетів.
# Оновлюємо список доступних пакетів у менеджері
# -y означає "погоджуватись автоматично" без підтвердження
sudo apt-get update -y
Що таке sudo? На Linux більшість системних команд вимагають прав адміністратора. sudo (Super User DO) дозволяє виконати команду з правами адміністратора. Без sudo ви отримаєте помилку Permission denied.
dotnet-sdk-10.0 доступний безпосередньо у стандартних репозиторіях (resolute-updates). Додаткові репозиторії Microsoft (packages-microsoft-prod) більше не потрібні.# Перевірте встановлення
dotnet --version
Крок 4: Створення та публікація .NET Web API
На вашому локальному комп'ютері (відкрийте новий термінал, не SSH-сесію) створіть проєкт:
# Створюємо новий Web API проєкт
dotnet new webapi -n Ec2LabApi --no-openapi
cd Ec2LabApi
Замінимо вміст Program.cs на наступний:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Відображаємо інформацію про сервер — корисно для перевірки
app.MapGet("/", () => new
{
message = "Hello from EC2!",
server = Environment.MachineName,
dotnetVersion = Environment.Version.ToString(),
timestamp = DateTime.UtcNow
});
app.MapGet("/health", () => Results.Ok("Healthy"));
app.Run();
Опублікуємо додаток для Linux (навіть якщо ви на Mac або Windows):
# Публікуємо для Linux x64
# -r linux-x64 вказує цільову платформу
# --self-contained false означає що на сервері має бути .NET Runtime (ми його вже встановили)
# -o ./publish вказує куди зберегти результат
dotnet publish -c Release -r linux-x64 --self-contained false -o ./publish
Крок 5: Копіювання файлів на сервер через SCP
SCP (Secure Copy Protocol) — утиліта для копіювання файлів між комп'ютерами через SSH. Синтаксис: scp [файл-звідки] [куди].
На вашому локальному комп'ютері (в директорії Ec2LabApi):
# Копіюємо папку publish на сервер
# -r означає рекурсивно (разом зі всіма підпапками)
# -i вказує SSH ключ (той самий, що для ssh)
# ЗАМІНІТЬ 3.64.185.42 на ваш реальний Public IP
scp -r -i ~/.ssh/ec2-lab-key.pem ./publish ubuntu@3.64.185.42:/tmp/ec2lab-publish
Поверніться до SSH-сесії (термінал де ви підключені до сервера). Перемістіть файли:
# Переміщуємо з тимчасової директорії у постійну
sudo mv /tmp/ec2lab-publish /var/app
# Перевіримо, що файли є
ls -la /var/app/
Крок 6: Запуск і тестування
# Переходимо в директорію додатку
cd /var/app
# Запускаємо .NET API
# ASPNETCORE_URLS вказує на якому порту слухати
# & в кінці запускає процес у фоновому режимі
ASPNETCORE_URLS="http://+:5000" dotnet Ec2LabApi.dll &
Перевіримо прямо на сервері:
# curl — консольний HTTP клієнт
# Виконуємо HTTP запит до нашого API (який слухає на localhost:5000)
curl http://localhost:5000/
Тепер перевіримо з вашого локального комп'ютера (замініть IP на ваш):
# ЗАМІНІТЬ 3.64.185.42 на ваш реальний Public IP
curl http://3.64.185.42:5000/
# {"message":"Hello from EC2!","server":"ip-172-31-10-25","dotnetVersion":"10.0.7","timestamp":"2026-01-15T10:35:05Z"}
API працює у хмарі! Можна відкрити у браузері: http://3.64.185.42:5000

Крок 7: Налаштування Systemd Service — автозапуск після рестарту
Запуск через & — тимчасовий. Якщо сервер перезавантажиться — API не запуститься автоматично. Systemd — це система управління сервісами на Linux. Вона запускає сервіси при старті ОС, перезапускає їх при збоях, збирає логи.
Зупиніть поточний процес:
# Знайдіть PID (Process ID) запущеного dotnet процесу
# ps aux — показати всі запущені процеси
# grep dotnet — відфільтрувати лише рядки зі словом "dotnet"
ps aux | grep dotnet
# Виведе: ubuntu 12345 ... dotnet Ec2LabApi.dll
# Завершіть процес за PID
kill 12345
Створіть файл unit для systemd:
# nano — простий текстовий редактор у терміналі
# Ctrl+O — зберегти, Ctrl+X — вийти
sudo nano /etc/systemd/system/ec2lab-api.service
У відкритому редакторі вставте наступний вміст:
[Unit]
Description=EC2 Lab .NET API
# Запускати після того, як мережа буде готова
After=network.target
[Service]
# Користувач під яким запускається процес
User=ubuntu
# Робоча директорія
WorkingDirectory=/var/app
# Команда запуску
ExecStart=/usr/bin/dotnet /var/app/Ec2LabApi.dll
# Автоматично перезапускати якщо процес впав
Restart=always
# Чекати 10 секунд перед перезапуском
RestartSec=10
# Змінні середовища
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://+:5000
[Install]
# Запускати у стандартному multi-user режимі
WantedBy=multi-user.target
Збережіть: натисніть Ctrl+O (підтвердіть Enter) → Ctrl+X для виходу.
# Перечитати конфігурацію systemd (потрібно після кожної зміни .service файлу)
sudo systemctl daemon-reload
# Увімкнути автозапуск при старті системи
sudo systemctl enable ec2lab-api
# Запустити сервіс прямо зараз
sudo systemctl start ec2lab-api
# Перевірити статус
sudo systemctl status ec2lab-api
# Переглянути логи сервісу
sudo journalctl -u ec2lab-api -n 50 --no-pager
# Слідкувати за логами в реальному часі (Ctrl+C щоб вийти)
sudo journalctl -u ec2lab-api -f
Перезавантажте сервер і переконайтесь, що API стартує автоматично:
sudo reboot
# Підключення закриється. Зачекайте 1-2 хвилини і підключіться знову через SSH.
# Потім перевірте: curl http://localhost:5000/

Крок 8 (бонус): Підключення безкоштовного домену pp.ua до EC2
Зараз ваш API доступний за IP-адресою (http://3.64.185.42:5000). Але IP-адреса — це незручно: вона може змінитись, її важко запам'ятати. Підключимо безкоштовний домен pp.ua.
Загальна схема:
myapi.pp.ua
↓ A record (DNS)
3.64.185.42 (Elastic IP вашого EC2)
↓
EC2 instance → .NET API (порт 80 через nginx)
8a: Виділення та прив'язка Elastic IP
- EC2 → Elastic IPs → Allocate Elastic IP address → Allocate
- Оберіть щойно виділений IP → Actions → Associate Elastic IP address
- Instance: оберіть ваш
dotnet-api-server→ Associate - Запишіть Elastic IP (наприклад
3.64.185.42) — саме цю адресу вкажете у DNS
# Виділити Elastic IP
ALLOC_ID=$(aws ec2 allocate-address \
--domain vpc --region eu-central-1 \
--query AllocationId --output text)
ELASTIC_IP=$(aws ec2 describe-addresses \
--allocation-ids $ALLOC_ID \
--query "Addresses[0].PublicIp" --output text --region eu-central-1)
echo "Elastic IP: $ELASTIC_IP"
# Прив'язати до instance (ЗАМІНІТЬ $INSTANCE_ID на ваш)
aws ec2 associate-address \
--instance-id $INSTANCE_ID \
--allocation-id $ALLOC_ID \
--region eu-central-1
8b: Встановлення nginx як reverse proxy (порт 80)
.NET API слухає на порті 5000. Відкривати 5000 публічно — незручно (користувачам доведеться вводити myapi.pp.ua:5000). Краще поставити nginx — lightweight веб-сервер, який приймає запити на порту 80 і проксіює їх на 5000.
На сервері (через SSH):
# Встановити nginx
sudo apt-get install -y nginx
# Створити конфігурацію для нашого API
sudo nano /etc/nginx/sites-available/ec2lab-api
Вставте в редакторі (Ctrl+O зберегти, Ctrl+X вийти):
server {
listen 80;
# ЗАМІНІТЬ myapi.pp.ua на ваш реальний субдомен
server_name myapi.pp.ua;
location / {
# Проксіювати запити до .NET API на порту 5000
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
# Передати реальний IP клієнта до .NET API
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
}
# Увімкнути конфігурацію (створити symbolic link)
sudo ln -s /etc/nginx/sites-available/ec2lab-api /etc/nginx/sites-enabled/
# Видалити дефолтну конфігурацію nginx
sudo rm /etc/nginx/sites-enabled/default
# Перевірити синтаксис конфігурації
sudo nginx -t
# Перезапустити nginx
sudo systemctl restart nginx
sudo systemctl enable nginx
Також переконайтесь, що Security Group дозволяє HTTP (порт 80) — він вже мав бути відкритий при створенні instance.
8c: Реєстрація субдомену на pp.ua через nic.ua
Що таке pp.ua? Це безкоштовна зона субдоменів в українському домені .ua. Зона .pp.ua (Personal Page) дозволяє кожному отримати безкоштовний домен виду yourname.pp.ua без оплати і без прив'язки до хостинг-провайдера. Реєстрація та DNS-управління здійснюється через nic.ua — офіційний реєстр доменних імен України.
Крок 1: Створення акаунту на nic.ua
- Перейдіть на https://nic.ua
- Натисніть «Реєстрація» (або «Увійти» → «Зареєструватися»)
- Заповніть форму реєстрації:
- Email — ваша поштова адреса (важлива, підтвердження прийде сюди)
- Пароль — мінімум 8 символів
- Ім'я та прізвище — ваші реальні дані (потрібні для домену)
- Телефон — може знадобитись для верифікації
- Натисніть «Зареєструватись»
- Перейдіть у свою пошту → відкрийте лист від nic.ua → натисніть посилання підтвердження
.pp.ua доменів.Крок 2: Пошук та реєстрація домену
- Після входу в акаунт — у пошуковому рядку на головній сторінці введіть бажаний субдомен:
myapi.pp.ua - Натисніть «Перевірити» або клавішу Enter
- Якщо домен вільний — ви побачите статус «Доступний» та кнопку «Замовити»
- Натисніть «Замовити» → додасться в корзину
- Ціна: 0 грн —
pp.uaдомени безкоштовні - Натисніть «Оформити замовлення»
- Підтвердіть дані реєстранта (власника домену) — вони підтягнуться з вашого профілю
- Натисніть «Підтвердити» або «Зареєструвати»
myapi, dotnet-lab, ec2-demo.Крок 3: Перехід до DNS Management
Після реєстрації домен з'явиться у вашому особистому кабінеті:
- Натисніть «Мої домени» або перейдіть до розділу «Домени» в боковому меню
- Знайдіть ваш
myapi.pp.uaу списку - Натисніть на назву домену → відкриється сторінка управління
- Перейдіть на вкладку «DNS» або «Управління DNS»
8d: Додавання A record у DNS панелі nic.ua
У розділі «DNS» вашого домену натисніть «Додати запис» або «Add Record» і заповніть:
| Поле | Значення |
|---|---|
| Тип / Type | A |
| Ім'я / Name | @ (або залиште порожнім — для кореневого myapi.pp.ua) |
| Значення / IP | 3.64.185.42 (ваш Elastic IP) |
| TTL | 300 |
Натисніть «Зберегти» або «Додати».
Що таке A record? DNS запис типу A (Address) вказує браузеру яку IP-адресу використовувати для домену. Коли браузер відкриває myapi.pp.ua — він спочатку запитує DNS: «яка IP-адреса у myapi.pp.ua?» → отримує 3.64.185.42 → підключається до цього IP.
myapi.pp.ua, а ви хочете налаштувати саме цей домен (не підсубдомен виду www.myapi.pp.ua) — вводьте @ або залишайте порожнім. Якщо хочете www.myapi.pp.ua — введіть www.Зачекайте 1–10 хвилин поки DNS оновиться. Перевірка:
Відкрийте http://myapi.pp.ua у браузері — ваш .NET API доступний через зручний домен!
8e: HTTPS через Let's Encrypt та Certbot
Що таке Let's Encrypt? Це безкоштовний, автоматизований та відкритий центр сертифікації (CA), що видає TLS/SSL сертифікати. Сертифікати дійсні 90 днів і оновлюються автоматично. Certbot — офіційний клієнт Let's Encrypt, який автоматично отримує сертифікат і налаштовує nginx.
Як Let's Encrypt перевіряє що ви власник домену? Через HTTP-01 challenge: Certbot створює тимчасовий файл на сервері за адресою http://myapi.pp.ua/.well-known/acme-challenge/..., сервери Let's Encrypt перевіряють його доступність через HTTP (порт 80) → якщо файл доступний — ви підтверджуєте права на домен → видається сертифікат.
- Ваш домен
myapi.pp.uaвже вказує на Elastic IP вашого EC2 (A record налаштований, DNS розповсюдився) - nginx запущений і відповідає на HTTP запити (
curl http://myapi.pp.ua) - У Security Group відкриті порти 80 (HTTP) та 443 (HTTPS) — перевірте зараз
Крок 1: Відкрити порт 443 у Security Group
Перейдіть: EC2 → Instances → ваш instance → Security → Security groups → Edit inbound rules → Add rule:
| Type | Protocol | Port | Source |
|---|---|---|---|
| HTTPS | TCP | 443 | 0.0.0.0/0 |
Або через AWS CLI:
# Отримати ID вашої Security Group
aws ec2 describe-instances \
--instance-ids i-0abc123def456789 \
--query "Reservations[0].Instances[0].SecurityGroups[0].GroupId" \
--output text
# Додати правило для HTTPS
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0
Крок 2: Встановити Certbot з плагіном nginx
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
Крок 3: Отримати SSL сертифікат
# ЗАМІНІТЬ myapi.pp.ua на ваш реальний домен
sudo certbot --nginx -d myapi.pp.ua
Certbot задасть вам кілька запитань в інтерактивному режимі:
Що Certbot зробив автоматично? Він модифікував ваш файл /etc/nginx/sites-available/ec2lab-api — додав SSL директиви та редирект з HTTP на HTTPS:
server {
# Certbot додав: слухати порт 443 з SSL
listen 443 ssl;
server_name myapi.pp.ua;
# Certbot додав: шляхи до сертифікатів
ssl_certificate /etc/letsencrypt/live/myapi.pp.ua/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapi.pp.ua/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
}
# Certbot додав: редирект HTTP → HTTPS
server {
listen 80;
server_name myapi.pp.ua;
return 301 https://$host$request_uri;
}
Крок 4: Перевірити що HTTPS працює
# Перевірити що nginx запущений після змін Certbot
sudo systemctl status nginx
# Перевірити відповідь через HTTPS
curl -I https://myapi.pp.ua/
# Перевірити деталі сертифікату
curl -v https://myapi.pp.ua/ 2>&1 | grep -A5 "SSL connection"
https://myapi.pp.ua у браузері — ви побачите замочок у адресному рядку. Клацніть на замочок → «Connection is secure» → «Certificate is valid» → там буде вказано «Let's Encrypt» як видавця і дата закінчення дії.Крок 5: Перевірити автоматичне оновлення сертифікатів
Let's Encrypt сертифікати дійсні 90 днів. Certbot при встановленні автоматично налаштовує systemd timer для щоденної перевірки і оновлення (якщо залишилось менше 30 днів).
# Перевірити що timer активний
sudo systemctl status certbot.timer
# Перевірити коли наступне оновлення
sudo systemctl list-timers certbot.timer
# Протестувати оновлення без реальних змін (dry run)
sudo certbot renew --dry-run
Де зберігаються сертифікати?
ls -la /etc/letsencrypt/live/myapi.pp.ua/
| Файл | Призначення |
|---|---|
fullchain.pem | Ваш сертифікат + проміжний ланцюжок CA (для nginx/Apache) |
privkey.pem | Приватний ключ (тримайте в секреті, не передавайте) |
cert.pem | Лише ваш сертифікат (без ланцюжка) |
chain.pem | Лише проміжний ланцюжок Let's Encrypt |
/etc/letsencrypt/live/ — це симлінки на актуальні версії. Ніколи не копіюйте і не переміщуйте їх вручну. При оновленні сертифікату Certbot автоматично оновлює файли, на які вказують ці симлінки.Типові помилки та рішення:
| Помилка | Причина | Рішення |
|---|---|---|
Connection refused / Timeout during connect | Порт 80 закритий у Security Group | Додайте inbound rule HTTP (80) для 0.0.0.0/0 |
DNS problem: NXDOMAIN looking up A for myapi.pp.ua | DNS ще не розповсюдився або A record неправильний | Перевірте nslookup myapi.pp.ua, зачекайте 5-10 хвилин |
too many certificates already issued for pp.ua | Rate limit Let's Encrypt (5 сертифікатів/тиждень на домен) | Зачекайте тиждень або використайте --staging для тестів |
Error: The requested nginx plugin does not appear to be installed | Не встановлено python3-certbot-nginx | sudo apt-get install python3-certbot-nginx |

Практичний приклад: ASP.NET Core з IIS на Windows Server
Windows Server EC2 підходить для випадків, коли потрібен IIS (Internet Information Services) — веб-сервер Microsoft, або для legacy .NET Framework додатків.
Крок 1: Запуск Windows Server EC2
- EC2 → Launch instances
- Name:
windows-iis-server - AMI: У пошуку введіть
Windows Server 2022→ оберіть Microsoft Windows Server 2022 Base- Увага: Windows AMI позначені як Paid — вартість Windows-ліцензії включена в ціну instance (~$0.05/год для
t3.medium)
- Увага: Windows AMI позначені як Paid — вартість Windows-ліцензії включена в ціну instance (~$0.05/год для
- Instance type:
t3.medium(мінімум для Windows Server + IIS + .NET) - Key pair: оберіть існуючий
ec2-lab-keyабо створіть новий у форматі.pem - Network settings → Create security group:
- ✅ Allow RDP traffic from: My IP (порт 3389 — Remote Desktop Protocol)
- ✅ Allow HTTP traffic from the internet (порт 80)
- Configure storage: 50 GB gp3 (Windows займає більше місця)
- Launch instance
# Знайдіть актуальний Windows Server 2022 AMI
WIN_AMI=$(aws ec2 describe-images \
--owners amazon \
--filters \
"Name=name,Values=Windows_Server-2022-English-Full-Base-*" \
"Name=state,Values=available" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" \
--output text --region eu-central-1)
echo "Windows AMI: $WIN_AMI"
# Створіть Security Group для Windows
WIN_SG=$(aws ec2 create-security-group \
--group-name windows-iis-sg \
--description "Windows IIS Security Group" \
--vpc-id $VPC_ID \
--region eu-central-1 \
--query GroupId --output text)
# RDP тільки з вашого IP
MY_IP=$(curl -s https://checkip.amazonaws.com)
aws ec2 authorize-security-group-ingress \
--group-id $WIN_SG --protocol tcp --port 3389 \
--cidr "${MY_IP}/32" --region eu-central-1
# HTTP публічно
aws ec2 authorize-security-group-ingress \
--group-id $WIN_SG --protocol tcp --port 80 \
--cidr 0.0.0.0/0 --region eu-central-1
# Запуск Windows instance
WIN_INSTANCE=$(aws ec2 run-instances \
--image-id $WIN_AMI \
--instance-type t3.medium \
--key-name ec2-lab-key \
--security-group-ids $WIN_SG \
--region eu-central-1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=windows-iis-server}]' \
--query "Instances[0].InstanceId" --output text)
echo "Windows Instance: $WIN_INSTANCE"
Крок 2: Отримання пароля адміністратора та підключення через RDP
Windows EC2 використовує RDP (Remote Desktop Protocol) замість SSH. Пароль адміністратора генерується автоматично і шифрується вашим SSH ключем.
Важливо: пароль стає доступним лише через 4–15 хвилин після запуску instance (Windows завершує ініціалізацію).
- EC2 → Instances →
windows-iis-server→ Actions → Security → Get Windows password - Натисніть Upload private key file → завантажте ваш
ec2-lab-key.pem - Натисніть Decrypt password → скопіюйте пароль
- Connect → вкладка RDP client → Download remote desktop file (завантажить
.rdpфайл) - Відкрийте
.rdpфайл → введіть пароль (логін:Administrator)
# Отримати зашифрований пароль (ЗАМІНІТЬ Instance ID)
ENCRYPTED_PASS=$(aws ec2 get-password-data \
--instance-id $WIN_INSTANCE \
--region eu-central-1 \
--query "PasswordData" --output text)
# Розшифрувати пароль за допомогою приватного ключа
echo "$ENCRYPTED_PASS" | base64 -d | openssl rsautl \
-decrypt -inkey ~/.ssh/ec2-lab-key.pem
# Отримати публічний IP для підключення
WIN_IP=$(aws ec2 describe-instances \
--instance-ids $WIN_INSTANCE \
--query "Reservations[0].Instances[0].PublicIpAddress" \
--output text --region eu-central-1)
echo "Windows Server IP: $WIN_IP"
Підключення через RDP (замініть IP та пароль):
- Windows: відкрийте «Remote Desktop Connection» → введіть IP
- Mac: встановіть «Microsoft Remote Desktop» з App Store → New Connection
::
::
Крок 3: Встановлення IIS та .NET 10 Hosting Bundle на Windows Server
Після підключення через RDP ви бачите звичайний робочий стіл Windows Server. Відкрийте PowerShell від імені адміністратора:
# Встановити IIS (Internet Information Services) — веб-сервер Microsoft
# Web-Server — базовий IIS
# Web-Asp-Net45 — підтримка ASP.NET
# Web-Mgmt-Console — графічний менеджер IIS
Install-WindowsFeature -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console `
-IncludeManagementTools -Restart:$false
# Завантажити та встановити .NET 10 ASP.NET Core Hosting Bundle
# Hosting Bundle включає: .NET Runtime + ASP.NET Core Runtime + IIS Module
$url = "https://download.microsoft.com/download/dotnet/10.0/dotnet-hosting-10.0.0-win.exe"
$installer = "$env:TEMP\dotnet-hosting-10.0.0-win.exe"
Write-Host "Завантажуємо .NET 10 Hosting Bundle..."
Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing
Write-Host "Встановлюємо..."
# /quiet — без GUI, /norestart — без автоматичного рестарту
Start-Process -FilePath $installer -ArgumentList "/quiet /norestart" -Wait
Write-Host "Перезапускаємо IIS..."
net stop was /y
net start w3svc
Write-Host "Перевірка встановлення:"
dotnet --version
Крок 4: Публікація та деплой на IIS
На вашому локальному комп'ютері (створіть або використайте той самий проєкт):
# Публікуємо для Windows
dotnet publish -c Release -r win-x64 --self-contained false -o ./publish-win
Скопіюйте папку publish-win на Windows Server. Варіанти:
- Через RDP — просто перетягніть папку у вікно RDP (якщо включено clipboard)
- Через S3: завантажте в S3 bucket і завантажте через PowerShell на сервері
Через S3 (рекомендовано):
# На локальному комп'ютері — завантажте в S3
# ЗАМІНІТЬ your-bucket-name на ваш S3 bucket (або створіть через Console)
aws s3 sync ./publish-win s3://your-bucket-name/ec2lab-api/
На Windows Server (PowerShell):
# Завантажити з S3 (AWS SDK вбудований у PowerShell на Amazon AMI)
# ЗАМІНІТЬ your-bucket-name
$destPath = "C:\inetpub\ec2lab-api"
New-Item -ItemType Directory -Path $destPath -Force
# Якщо немає AWS CLI — встановіть
# Invoke-WebRequest "https://awscli.amazonaws.com/AWSCLIV2.msi" -OutFile "$env:TEMP\AWSCLIV2.msi"
# Start-Process msiexec.exe -Wait -ArgumentList "/I $env:TEMP\AWSCLIV2.msi /quiet"
aws s3 sync s3://your-bucket-name/ec2lab-api/ $destPath
Налаштуйте сайт у IIS через PowerShell:
Import-Module WebAdministration
# Створіть Application Pool для .NET 10
New-WebAppPool -Name "Ec2LabApiPool"
$pool = Get-Item "IIS:\AppPools\Ec2LabApiPool"
$pool.managedRuntimeVersion = "" # No Managed Code (для .NET Core/10)
$pool | Set-Item
# Видаліть Default Web Site (якщо є)
Remove-Website -Name "Default Web Site" -ErrorAction SilentlyContinue
# Створіть новий сайт
New-Website -Name "Ec2LabApi" `
-Port 80 `
-PhysicalPath "C:\inetpub\ec2lab-api" `
-ApplicationPool "Ec2LabApiPool"
# Запустіть сайт
Start-Website -Name "Ec2LabApi"
Write-Host "Сайт запущено! Перейдіть: http://localhost"
Перевірте у браузері на вашому комп'ютері: http://WINDOWS_IP/
Крок 5: Створення Custom AMI
Тепер, коли сервер налаштований (встановлений .NET, IIS, задеплоєний додаток) — створимо AMI. Це дозволить у майбутньому запускати новий сервер з тим самим станом без повторного встановлення.
- EC2 → Instances → оберіть instance → Actions → Image and templates → Create image
- Image name:
dotnet-iis-ready-v1 - Image description:
Windows Server 2022 + IIS + .NET 10 Hosting Bundle - No reboot: можна залишити unchecked (перезавантаження гарантує консистентність)
- Create image
- Прогрес: EC2 → AMIs → ваша AMI буде у стані
pending→ за 5–15 хвилин станеavailable
# ЗАМІНІТЬ Instance ID на ваш реальний
aws ec2 create-image \
--instance-id i-1234567890abcdef0 \
--name "dotnet-iis-ready-v1" \
--description "Windows Server 2022 + IIS + .NET 10 Hosting Bundle" \
--region eu-central-1
# Перевірити статус AMI (виконайте через кілька хвилин)
aws ec2 describe-images \
--owners self \
--filters "Name=name,Values=dotnet-iis-ready-v1" \
--query "Images[0].{ID:ImageId,State:State}" \
--output table --region eu-central-1
Крок 6: ОБОВ'ЯЗКОВО — Очищення ресурсів
t3.medium) коштує ~$0.065/год без зупинки — це ~$47/місяць. Зупиніть або видаліть instance після завершення роботи!- EC2 → Instances → оберіть instance → Instance state → Terminate instance
- Або Stop instance якщо плануєте продовжити пізніше (за зупинений instance EBS ще тарифікується, але менше)
- Якщо створювали Elastic IP — EC2 → Elastic IPs → Release Elastic IP address
- AMI: EC2 → AMIs → ваша AMI → Actions → Deregister AMI (опціонально)
- EBS Snapshots від AMI: EC2 → Snapshots → видаліть пов'язані
REGION="eu-central-1"
# ЗАМІНІТЬ на ваші реальні ID
# Зупинити (платите лише за EBS)
aws ec2 stop-instances --instance-ids $INSTANCE_ID --region $REGION
# Або видалити повністю
aws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION
# Звільнити Elastic IP (якщо виділяли)
# aws ec2 release-address --allocation-id eipalloc-xxx --region $REGION

Практичний приклад: Dokploy — власна PaaS-платформа на EC2
Попередні приклади показали «класичний» підхід деплою: SSH-підключення, ручне копіювання файлів через SCP, налаштування systemd-сервісів. Цей підхід прозорий і надійний, але вимагає значної ручної роботи при кожному оновленні застосунку — ви повинні перебудувати проєкт, скопіювати файли на сервер, перезапустити сервіс. З ростом кількості застосунків це перетворюється на рутинну операцію, яка займає час і відволікає від розробки.
Dokploy — це безкоштовна open-source PaaS-платформа (Platform as a Service), яку ви встановлюєте на власний EC2 instance. Після встановлення вона надає зручний веб-інтерфейс для деплою застосунків — схожий за концепцією на Heroku або Railway, але повністю під вашим контролем, без абонентської плати за платформу і без залежності від стороннього сервісу.
Ключові можливості Dokploy:
- Автоматичний деплой з GitHub — після кожного
git pushзастосунок автоматично перебудовується і перезапускається без вашої участі - SSL-сертифікати через Let's Encrypt — Traefik автоматично отримує та оновлює сертифікати, жодних скриптів не потрібно
- Веб-інтерфейс для логів — переглядайте логи контейнерів прямо у браузері в реальному часі
- Docker та Docker Compose — підтримка будь-якого стека: .NET, Node.js, Python, Go, PHP
- Нульовий downtime — новий контейнер запускається до зупинки старого (rolling deploy)
- Управління змінними середовища — зберігайте секрети та конфігурацію окремо від коду
- Rollback одним кліком — повернення до будь-якої попередньої версії з повною історією деплоїв
У цьому прикладі ми встановимо Dokploy на Ubuntu EC2, задеплоїмо ASP.NET Core API через GitHub repository та налаштуємо автоматичний CI/CD.
Крок 1: Запуск EC2 instance для Dokploy
Dokploy запускає кілька Docker-контейнерів власної інфраструктури (застосунок, Traefik, PostgreSQL, Redis) ще до того, як ви задеплоїте перший сервіс. Тому мінімальні вимоги вищі, ніж для звичайного застосунку.
t3.micro (1 GB RAM) недостатньо для Dokploy. Під час встановлення або після нього система почне використовувати swap, контейнери зависатимуть. Мінімум — t3.small (2 GB RAM) для одного-двох застосунків. Для комфортної роботи з кількома сервісами використовуйте t3.medium (4 GB RAM).- EC2 → Launch instances
- Name:
dokploy-server - Application and OS Images (AMI):
- Натисніть Ubuntu у Quick Start
- Оберіть Ubuntu Server 26.04 LTS (HVM), SSD Volume Type
- Architecture: 64-bit (x86)
- Instance type:
t3.medium(рекомендовано; мінімумt3.smallдля тестування) - Key pair: оберіть існуючий
ec2-lab-keyабо створіть новий у форматі.pem - Network settings → Edit → Create security group:
- Security group name:
dokploy-sg - Правило 1 — SSH:
- Type: SSH, Port: 22, Source: My IP (лише ви)
- Правило 2 — HTTP:
- Type: HTTP, Port: 80, Source: Anywhere (потрібно для Let's Encrypt верифікації та HTTP→HTTPS редиректу)
- Правило 3 — HTTPS:
- Type: HTTPS, Port: 443, Source: Anywhere (основний трафік застосунків)
- Правило 4 — Dokploy UI:
- Type: Custom TCP, Port: 3000, Source: My IP (веб-інтерфейс лише для адміністратора)
- Security group name:
- Configure storage: 30 GB gp3 (Docker образи .NET займають ~2–3 GB кожен; 20 GB мінімум, 30 GB рекомендовано)
- Натисніть Launch instance
# Знайдіть Ubuntu 26.04 AMI
AMI_ID=$(aws ec2 describe-images \
--owners 099720109477 \
--filters "Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-resolute-26.04-amd64-server-*" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" \
--output text --region eu-central-1)
echo "AMI: $AMI_ID"
# Отримайте default VPC
VPC_ID=$(aws ec2 describe-vpcs \
--filters "Name=isDefault,Values=true" \
--query "Vpcs[0].VpcId" --output text --region eu-central-1)
# Створіть Security Group
SG_ID=$(aws ec2 create-security-group \
--group-name dokploy-sg \
--description "Dokploy PaaS Security Group" \
--vpc-id $VPC_ID \
--region eu-central-1 \
--query GroupId --output text)
# Ваш поточний IP
MY_IP=$(curl -s https://checkip.amazonaws.com)
# SSH лише з вашого IP
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID --protocol tcp --port 22 \
--cidr "${MY_IP}/32" --region eu-central-1
# HTTP публічно (Let's Encrypt + редирект)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID --protocol tcp --port 80 \
--cidr 0.0.0.0/0 --region eu-central-1
# HTTPS публічно (трафік застосунків)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID --protocol tcp --port 443 \
--cidr 0.0.0.0/0 --region eu-central-1
# Dokploy UI лише з вашого IP
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID --protocol tcp --port 3000 \
--cidr "${MY_IP}/32" --region eu-central-1
# Запуск instance з 30 GB диском
INSTANCE_ID=$(aws ec2 run-instances \
--image-id $AMI_ID \
--instance-type t3.medium \
--key-name ec2-lab-key \
--security-group-ids $SG_ID \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
--region eu-central-1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=dokploy-server}]' \
--query "Instances[0].InstanceId" --output text)
echo "Instance: $INSTANCE_ID"
::
::
Крок 2: Виділення Elastic IP та налаштування DNS
Dokploy використовує Traefik для автоматичного отримання SSL-сертифікатів від Let's Encrypt. Let's Encrypt верифікує, що ви дійсно контролюєте домен, звернувшись до вашого сервера через порт 80. Для цього потрібна стала IP-адреса, яка не змінюється після рестартів, — саме таку надає Elastic IP.
- EC2 → Elastic IPs → Allocate Elastic IP address
- Network Border Group:
eu-central-1 - Натисніть Allocate
- Network Border Group:
- Оберіть щойно виділений IP → Actions → Associate Elastic IP address
- Resource type: Instance
- Instance: оберіть
dokploy-server - Натисніть Associate
- Запишіть виділений IP (далі у прикладах —
3.64.185.42)
# Виділити Elastic IP
ALLOC_ID=$(aws ec2 allocate-address \
--domain vpc \
--region eu-central-1 \
--query AllocationId --output text)
# Прив'язати до instance
aws ec2 associate-address \
--instance-id $INSTANCE_ID \
--allocation-id $ALLOC_ID \
--region eu-central-1
# Дізнатись виділений IP
EIP=$(aws ec2 describe-addresses \
--allocation-ids $ALLOC_ID \
--query "Addresses[0].PublicIp" \
--output text --region eu-central-1)
echo "Elastic IP: $EIP"
Налаштування DNS: зайдіть у панель вашого реєстратора доменів та додайте A-запис:
| Поле | Значення | Пояснення |
|---|---|---|
| Ім'я | dokploy | Субдомен для самого Dokploy UI |
| Тип | A | Прямий запис IP-адреси |
| Значення | 3.64.185.42 | Ваш Elastic IP |
| TTL | 300 | Час кешування (5 хв) |
Якщо ваш домен — pp.ua, а ім'я — dokploy, то Dokploy UI буде доступний за https://dokploy.pp.ua. Для застосунків додайте окремий A-запис або wildcard-запис * → 3.64.185.42, щоб субдомени на кшталт myapi.pp.ua теж вказували на сервер.
nslookup dokploy.pp.ua або сервісом whatsmydns.net. DNS-зміни набирають чинності від кількох хвилин до 48 годин, але зазвичай — менш ніж 5–15 хвилин.Крок 3: Встановлення Dokploy
Підключіться до сервера через SSH та виконайте встановлення:
Dokploy встановлюється однією командою. Інсталятор автоматично завантажить Docker, Docker Compose та всі необхідні образи. Жодних попередніх налаштувань не потрібно:
docker: not found або E: Unable to locate package docker-ceЦе трапляється, коли ваша Ubuntu має нестандартну кодову назву (наприклад, resolute) — офіційний репозиторій Docker не містить пакетів для такої назви, тому встановлення Docker збоїть, і наступний крок ініціалізації Docker Swarm видає docker: not found.Діагностика: якщо у логах ви бачите рядок на кшталт:https://download.docker.com/linux/ubuntu resolute stable
E: Unable to locate package — ви зіткнулись саме з цим.Крок 1: Встановіть Docker вручну# 1. Видаліть зіпсований файл репозиторію, який створив скрипт
sudo rm -f /etc/apt/sources.list.d/docker.list
# 2. Додайте офіційний репозиторій Docker зі стабільною кодовою назвою jammy
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list
# 3. Оновіть списки пакетів
sudo apt-get update
# 4. Встановіть Docker
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo docker version
not found.Крок 3: Ініціалізуйте Docker Swarm вручнуDokploy базується на Docker Swarm. Скрипт впав саме на цьому кроці, тому ініціалізуємо Swarm самостійно. Підставте IP-адресу вашого instance (вона видна у логах скрипта або у AWS Console):# ЗАМІНІТЬ на вашу реальну приватну IP-адресу instance
sudo docker swarm init --advertise-addr 172.31.41.246
curl -sSL https://dokploy.com/install.sh | sudo sh
Перевірте, що всі чотири контейнери Dokploy запущені та здорові:
Що робить кожен контейнер:
dokploy-app— основний застосунок: веб-інтерфейс, REST API, управління деплоямиdokploy-traefik— reverse proxy: приймає HTTP/HTTPS трафік, термінує TLS, маршрутизує до контейнерів застосунківdokploy-postgres— реляційна база даних Dokploy (конфігурація, проєкти, деплої)dokploy-redis— кеш та черга задач (асинхронні деплої, WebSocket для логів)
Крок 4: Перше налаштування у веб-інтерфейсі
Відкрийте у браузері: http://3.64.185.42:3000
Ви побачите сторінку реєстрації першого адміністратора. Ця форма відображається лише один раз — при першому відкритті після чистого встановлення. Якщо цю сторінку побачить сторонній — він зможе стати адміністратором. Тому важливо виконати цей крок одразу після встановлення.
Заповніть форму реєстрації:
- Email: ваша email-адреса (буде логіном для входу)
- Password: надійний пароль (мінімум 8 символів; рекомендується 16+)
- Confirm Password: повторіть пароль
Натисніть Create Account. Ви автоматично увійдете в Dokploy і побачите порожній Dashboard.
Огляд головних розділів інтерфейсу:
| Розділ | Призначення |
|---|---|
| Dashboard | Загальна статистика: кількість проєктів, сервісів, стан сервера (CPU, RAM, диск) |
| Projects | Список проєктів — кожен проєкт містить один або кілька сервісів |
| Settings → Server | Домен Dokploy UI, Let's Encrypt email, SSH-ключі для GitHub |
| Settings → Certificates | Перегляд виданих SSL-сертифікатів та їх статусу |
| Settings → Users | Управління командою: додавання користувачів з різними правами |
| Settings → Notifications | Налаштування сповіщень (Slack, Discord, Email, Telegram) |
Налаштування серверного домену та SSL:
- Перейдіть у Settings → Server
- У полі Domain введіть ваш домен для Dokploy UI:
dokploy.pp.ua - У полі Let's Encrypt Email введіть вашу email-адресу (на неї Let's Encrypt надсилає сповіщення про закінчення сертифікату)
- Натисніть Save
Після збереження Dokploy передає налаштування Traefik, який автоматично звертається до Let's Encrypt, проходить HTTP-01 верифікацію та отримує сертифікат. Зачекайте 1–2 хвилини — потім Dokploy UI буде доступний за адресою https://dokploy.pp.ua.
dokploy.pp.ua вже вказує на ваш Elastic IP (nslookup dokploy.pp.ua); 2) порт 80 відкритий у Security Group (Let's Encrypt потребує його для верифікації).Крок 5: Підготовка .NET застосунку до деплою через Docker
Dokploy будує ваш застосунок з Dockerfile у корені репозиторію. Якщо Dockerfile відсутній — Dokploy може спробувати автовизначення стека через Nixpacks, але для .NET рекомендується явний Dockerfile.
Ключовий момент при написанні Dockerfile для Dokploy: застосунок повинен слухати на порту, який ви потім вкажете в налаштуваннях домену. Традиційно для контейнерів використовують порт 8080.
# Файл: Dockerfile (у корені репозиторію)
# Стадія 1: збірка
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Копіюємо файл проєкту окремо для кешування шару відновлення пакетів
COPY MyApi.csproj .
RUN dotnet restore
# Копіюємо решту коду та публікуємо
COPY . .
RUN dotnet publish -c Release -o /app/publish --no-restore
# Стадія 2: runtime образ (менший розмір — лише runtime, без SDK)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
# Налаштовуємо порт: 8080 — стандарт для контейнерів (не 5000/5001)
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApi.dll"]
build + runtime) критично важлива для зменшення розміру образу: образ SDK важить ~800 MB, образ лише runtime — ~200 MB. Продакшн-образ буде вчетверо меншим, що прискорює деплой.Переконайтесь, що репозиторій містить .dockerignore для виключення зайвих файлів:
# .dockerignore
bin/
obj/
*.user
.git/
.vs/
**/*.md
Крок 6: Деплой .NET застосунку через Dokploy
Крок 6a: Створення проєкту
- Перейдіть у Projects → Create Project
- Name:
my-dotnet-api - Description: опціонально
- Натисніть Create
Крок 6b: Додавання сервісу
- Всередині проєкту натисніть + Create Service → оберіть Application
- Name:
api - Натисніть Create
Крок 6c: Налаштування джерела коду
- У налаштуваннях сервісу знайдіть секцію Source
- Оберіть GitHub
- Натисніть Connect with GitHub → авторизуйте Dokploy у вашому GitHub акаунті (Dokploy отримає право читати репозиторії)
- Оберіть Repository:
username/my-dotnet-api - Оберіть Branch:
main - Build Type: оберіть Dockerfile
- Натисніть Save
Крок 6d: Налаштування домену
- Перейдіть на вкладку Domains у налаштуваннях сервісу
- Натисніть Add Domain
- Заповніть форму:
- Host:
myapi.pp.ua - Port:
8080(порт, на якому слухає ваш застосунок всередині контейнера) - HTTPS: увімкніть — Traefik автоматично отримає сертифікат
- HTTP to HTTPS Redirect: увімкніть
- Host:
- Натисніть Save
Крок 6e: Перший деплой
- Перейдіть на вкладку Deployments
- Натисніть Deploy
- З'явиться вікно з живими логами збірки
Після успішного деплою перевірте застосунок:
Крок 7: Автоматичний CI/CD через GitHub Webhook
Webhook — це HTTP-запит, який GitHub надсилає на вашу адресу при кожному git push. Dokploy приймає цей запит та автоматично запускає новий деплой. Після налаштування процес розгортання повністю автоматичний: ви пишете код, виконуєте git push — сервер оновлюється сам.
Отримання Webhook URL у Dokploy:
- Перейдіть у налаштування вашого сервісу (вкладка General)
- Знайдіть секцію Webhook — там відображається унікальний URL вигляду
https://dokploy.pp.ua/api/deploy/webhook/abc123xyz456 - Скопіюйте цей URL
Додавання Webhook у GitHub:
- Відкрийте GitHub repository → Settings → Webhooks → Add webhook
- Payload URL: вставте скопійований Webhook URL
- Content type:
application/json - Which events would you like to trigger this webhook? → Just the push event
- Переконайтесь, що Active увімкнено
- Натисніть Add webhook
GitHub відразу надішле тестовий ping запит. У Dokploy у вкладці Deployments ви побачите, що запит отримано (але деплой не запустився — ping це не push).
Крок 8: Управління змінними середовища
Environment Variables — стандартний спосіб зберігання конфігурацій, чутливих до оточення: рядки підключення до баз даних, API-ключі, секретні ключі JWT тощо. Зберігати їх у коді або у файлах конфігурації у Git-репозиторії — небезпечно.
- У налаштуваннях сервісу перейдіть на вкладку Environment
- Натисніть Add Variable для кожної змінної:
ASPNETCORE_ENVIRONMENT=Production
ConnectionStrings__DefaultConnection=Host=...;Database=...;Username=...;Password=...
JwtSettings__Secret=your-very-long-secret-key-here
AllowedOrigins=https://myapp.pp.ua,https://www.myapp.pp.ua
SENTRY_DSN=https://...@sentry.io/123456
- Натисніть Save — Dokploy автоматично перезапустить контейнер з новими змінними
appsettings.json або в Git-репозиторії. Якщо такі дані потрапили у публічний репозиторій — негайно скасуйте всі ключі та змініть паролі. Для production використовуйте Environment Variables у Dokploy або AWS Secrets Manager.Перегляд логів у реальному часі через вкладку Logs вашого сервісу. Це еквівалент docker logs -f — ви бачите все, що застосунок виводить у stdout/stderr. Логи оновлюються у реальному часі через WebSocket.
Крок 9: ОБОВ'ЯЗКОВО — Очищення ресурсів
t3.medium коштує ~$0.052/год без зупинки — це ~$37/місяць. Зупиніть або видаліть instance після завершення роботи з лабораторною роботою!- EC2 → Instances →
dokploy-server→ Instance state → Terminate instance - EC2 → Elastic IPs → оберіть виділений IP → Actions → Release Elastic IP address
- Увага: спочатку instance має бути видалений (або від'єднайте IP перед видаленням через Disassociate Elastic IP address)
REGION="eu-central-1"
# Від'єднати Elastic IP від instance
ASSOC_ID=$(aws ec2 describe-addresses \
--allocation-ids $ALLOC_ID \
--query "Addresses[0].AssociationId" \
--output text --region $REGION)
aws ec2 disassociate-address --association-id $ASSOC_ID --region $REGION
# Звільнити Elastic IP (перестати платити за нього)
aws ec2 release-address --allocation-id $ALLOC_ID --region $REGION
# Видалити instance
aws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION

Резюме
EC2 Instances
- EC2 — віртуальні сервери у хмарі. Платите лише за час роботи.
- Instance Types: T (burstable, Free Tier
t3.micro), M (стабільний), C (CPU), R (RAM), I (Storage). - Тип завжди можна змінити: зупинити instance → змінити тип → запустити.
Storage
- AMI — шаблон ОС. Перевіряйте актуальний ID для регіону. Custom AMI для Auto Scaling.
- EBS — мережеві диски.
gp3для більшості задач. Snapshots для резервних копій.
Networking & Security
- Security Groups: stateful файрвол. SSH лише з вашого IP. Ніколи
0.0.0.0/0для порту 22! - Elastic IP: стала публічна адреса. Безкоштовна при прикріпленому запущеному instance.
Pricing
- On-Demand: гнучко, без контракту.
- Savings Plans: знижка 30–75% на 1-3 роки.
- Spot: 60–90% знижка, переривувані. Для batch-задач та CI/CD.
Automation
- User Data: bash/PowerShell скрипт при першому запуску — автоматизація встановлення ПЗ.
- IMDS (
169.254.169.254): отримання метаданих та IAM credentials без Access Keys.
Deployment
- Linux: SSH + SCP → systemd service (
Restart=always) → nginx reverse proxy. - Windows: RDP підключення → IIS + .NET 10 Hosting Bundle →
New-Websiteу PowerShell.

Практичні завдання
Рівень 1 (Базовий)
Завдання 1. Поясніть різницю між t3.micro та m6i.large. Коли ви б обрали кожен? Що таке CPU Credits у T-instances?
Завдання 2. Чому небезпечно відкривати SSH порт (22) для 0.0.0.0/0? Як правильно налаштувати Security Group для SSH?
Рівень 2 (Практичний)
Завдання 3. Задеплойте ASP.NET Core API на Linux EC2. Налаштуйте systemd service з Restart=always. Перевірте, що після sudo reboot API автоматично запускається.
Завдання 4. Напишіть User Data скрипт для Ubuntu EC2, який автоматично встановлює .NET 10 та копіює з S3 і запускає ваш API. Протестуйте: запустіть instance і без SSH підключення перевірте, що API відповідає.
Рівень 3 (Архітектура)
Завдання 5. Спроектуйте EC2-архітектуру для .NET API з наступними вимогами: Auto Scaling Group (мін. 2, макс. 10 instances), ALB для балансування, окремий EBS том для логів, custom AMI з встановленим .NET, Health Check через /health endpoint, Spot Instances для економії. Намалюйте схему у PlantUML.
AWS ECR / ECS CLI — Довідник команд
Повний довідник AWS CLI команд для ECR та ECS — аутентифікація, репозиторії, кластери, сервіси, мережа, балансувальник, автомасштабування, логи. Усі важливі команди з прикладами та очікуваним виводом.
AWS EC2 CLI — Довідник команд
Повний довідник AWS CLI команд для Amazon EC2 — instances, AMI, Key Pairs, Security Groups, Elastic IP, EBS, snapshots, IAM Instance Profile, tags. Усі важливі команди з прикладами та очікуваним виводом.