[{"data":1,"prerenderedAt":18111},["ShallowReactive",2],{"navigation_docs":3,"-aws-ec2":3338,"-aws-ec2-surround":18106},[4,1707,1904,2358,2539,2608,2815,2937,2987,3044,3078,3204,3281,3334],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1905,"icon":1906,"path":1907,"stem":1908,"children":1909,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1910,1936,1990,2012,2316,2354],{"title":1911,"icon":1912,"path":1913,"stem":1914,"children":1915,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1916,1920,1924,1928,1932],{"title":1917,"path":1918,"stem":1919},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1921,"path":1922,"stem":1923},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1925,"path":1926,"stem":1927},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1929,"path":1930,"stem":1931},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1933,"path":1934,"stem":1935},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1937,"icon":1938,"path":1939,"stem":1940,"children":1941,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1942,1946,1950,1954,1958,1962,1966,1970,1974,1978,1982,1986],{"title":1943,"path":1944,"stem":1945},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1947,"path":1948,"stem":1949},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1951,"path":1952,"stem":1953},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1955,"path":1956,"stem":1957},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1959,"path":1960,"stem":1961},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1963,"path":1964,"stem":1965},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1967,"path":1968,"stem":1969},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1971,"path":1972,"stem":1973},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1975,"path":1976,"stem":1977},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1979,"path":1980,"stem":1981},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1983,"path":1984,"stem":1985},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1987,"path":1988,"stem":1989},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1991,"icon":1992,"path":1993,"stem":1994,"children":1995,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[1996,2000,2004,2008],{"title":1997,"path":1998,"stem":1999},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2001,"path":2002,"stem":2003},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2005,"path":2006,"stem":2007},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2009,"path":2010,"stem":2011},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2013,"icon":2014,"path":2015,"stem":2016,"children":2017},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2018,2019,2023,2027,2031,2035,2098,2133,2285],{"title":2013,"path":2015,"stem":2016},{"title":2020,"path":2021,"stem":2022},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2024,"path":2025,"stem":2026},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2028,"path":2029,"stem":2030},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2032,"path":2033,"stem":2034},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2036,"icon":132,"path":2037,"stem":2038,"children":2039},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2040,2042,2046,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094],{"title":2041,"path":2037,"stem":2038},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2043,"path":2044,"stem":2045},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2047,"path":2048,"stem":2049},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2051,"path":2052,"stem":2053},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2055,"path":2056,"stem":2057},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2059,"path":2060,"stem":2061},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2063,"path":2064,"stem":2065},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2067,"path":2068,"stem":2069},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2071,"path":2072,"stem":2073},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2075,"path":2076,"stem":2077},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2079,"path":2080,"stem":2081},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2083,"path":2084,"stem":2085},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2087,"path":2088,"stem":2089},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2091,"path":2092,"stem":2093},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2095,"path":2096,"stem":2097},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2099,"icon":2014,"path":2100,"stem":2101,"children":2102},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2103,2105,2109,2113,2117,2121,2125,2129],{"title":2104,"path":2100,"stem":2101},"React Router: Навігаційна система сучасного вебу",{"title":2106,"path":2107,"stem":2108},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2110,"path":2111,"stem":2112},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2114,"path":2115,"stem":2116},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2118,"path":2119,"stem":2120},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2122,"path":2123,"stem":2124},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2126,"path":2127,"stem":2128},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2130,"path":2131,"stem":2132},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2134,"icon":132,"path":2135,"stem":2136,"children":2137},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2138,2140,2156,2185,2194,2215,2231,2260],{"title":2139,"path":2135,"stem":2136},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2141,"stem":2142,"children":2143,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2144,2148,2152],{"title":2145,"path":2146,"stem":2147},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2149,"path":2150,"stem":2151},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2153,"path":2154,"stem":2155},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2157,"icon":132,"path":2158,"stem":2159,"children":2160,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2161,2165,2169,2173,2177,2181],{"title":2162,"path":2163,"stem":2164},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2166,"path":2167,"stem":2168},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2170,"path":2171,"stem":2172},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2174,"path":2175,"stem":2176},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2178,"path":2179,"stem":2180},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2182,"path":2183,"stem":2184},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2186,"icon":132,"path":2187,"stem":2188,"children":2189,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2190],{"title":2191,"path":2192,"stem":2193},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2195,"icon":132,"path":2196,"stem":2197,"children":2198,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2199,2203,2207,2211],{"title":2200,"path":2201,"stem":2202},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2204,"path":2205,"stem":2206},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2208,"path":2209,"stem":2210},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2212,"path":2213,"stem":2214},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2216,"icon":92,"path":2217,"stem":2218,"children":2219,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2220,2224,2228],{"title":2221,"path":2222,"stem":2223},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2225,"path":2226,"stem":2227},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2075,"path":2229,"stem":2230},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2232,"icon":132,"path":2233,"stem":2234,"children":2235,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2236,2240,2244,2248,2252,2256],{"title":2237,"path":2238,"stem":2239},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2241,"path":2242,"stem":2243},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2245,"path":2246,"stem":2247},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2249,"path":2250,"stem":2251},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2253,"path":2254,"stem":2255},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2257,"path":2258,"stem":2259},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2261,"icon":132,"path":2262,"stem":2263,"children":2264,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2265,2269,2273,2277,2281],{"title":2266,"path":2267,"stem":2268},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2270,"path":2271,"stem":2272},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2274,"path":2275,"stem":2276},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2278,"path":2279,"stem":2280},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2282,"path":2283,"stem":2284},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2286,"icon":132,"path":2287,"stem":2288,"children":2289},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2290,2292,2296,2300,2304,2308,2312],{"title":2291,"path":2287,"stem":2288},"UI Бібліотеки в React",{"title":2293,"path":2294,"stem":2295},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2297,"path":2298,"stem":2299},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2301,"path":2302,"stem":2303},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2305,"path":2306,"stem":2307},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2309,"path":2310,"stem":2311},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2313,"path":2314,"stem":2315},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2317,"icon":2318,"path":2319,"stem":2320,"children":2321,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2322,2326,2330,2334,2338,2342,2346,2350],{"title":2323,"path":2324,"stem":2325},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2327,"path":2328,"stem":2329},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2331,"path":2332,"stem":2333},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2335,"path":2336,"stem":2337},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2339,"path":2340,"stem":2341},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2343,"path":2344,"stem":2345},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2347,"path":2348,"stem":2349},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2351,"path":2352,"stem":2353},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2355,"path":2356,"stem":2357},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2359,"icon":2360,"path":2361,"stem":2362,"children":2363,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2364,2367,2370,2374,2378,2382,2386],{"title":162,"path":2365,"stem":2366},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2368,"stem":2369},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2371,"path":2372,"stem":2373},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2375,"path":2376,"stem":2377},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2379,"path":2380,"stem":2381},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2383,"path":2384,"stem":2385},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2387,"path":2388,"stem":2389,"children":2390,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2391,2395,2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535],{"title":2392,"path":2393,"stem":2394},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2396,"path":2397,"stem":2398},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2400,"path":2401,"stem":2402},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2404,"path":2405,"stem":2406},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2408,"path":2409,"stem":2410},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2412,"path":2413,"stem":2414},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2416,"path":2417,"stem":2418},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2420,"path":2421,"stem":2422},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2424,"path":2425,"stem":2426},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2428,"path":2429,"stem":2430},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2432,"path":2433,"stem":2434},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2436,"path":2437,"stem":2438},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2440,"path":2441,"stem":2442},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2444,"path":2445,"stem":2446},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2448,"path":2449,"stem":2450},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2452,"path":2453,"stem":2454},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2456,"path":2457,"stem":2458},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2460,"path":2461,"stem":2462},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2464,"path":2465,"stem":2466},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2468,"path":2469,"stem":2470},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2472,"path":2473,"stem":2474},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2476,"path":2477,"stem":2478},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2480,"path":2481,"stem":2482},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2484,"path":2485,"stem":2486},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2488,"path":2489,"stem":2490},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2492,"path":2493,"stem":2494},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2496,"path":2497,"stem":2498},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2500,"path":2501,"stem":2502},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2504,"path":2505,"stem":2506},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2508,"path":2509,"stem":2510},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2512,"path":2513,"stem":2514},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2516,"path":2517,"stem":2518},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2520,"path":2521,"stem":2522},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2524,"path":2525,"stem":2526},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2528,"path":2529,"stem":2530},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2532,"path":2533,"stem":2534},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2536,"path":2537,"stem":2538},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2540,"icon":2541,"path":2542,"stem":2543,"children":2544,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2545,2549,2552,2556,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604],{"title":2546,"path":2547,"stem":2548},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2550,"stem":2551},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2553,"path":2554,"stem":2555},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2557,"path":2558,"stem":2559},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2561,"path":2562,"stem":2563},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2565,"path":2566,"stem":2567},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2569,"path":2570,"stem":2571},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2573,"path":2574,"stem":2575},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2577,"path":2578,"stem":2579},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2581,"path":2582,"stem":2583},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2585,"path":2586,"stem":2587},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2589,"path":2590,"stem":2591},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2593,"path":2594,"stem":2595},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2597,"path":2598,"stem":2599},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2601,"path":2602,"stem":2603},"📦 Повний посібник з модулів, пакетів та віртуальних середовищ у Python","\u002Fpython\u002Flesson_9","05.python\u002Flesson_9",{"title":2605,"path":2606,"stem":2607},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2609,"icon":2610,"path":2611,"stem":2612,"children":2613,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2614,2644,2667,2704,2733,2751,2785,2797,2806],{"title":2615,"icon":2616,"path":2617,"stem":2618,"children":2619,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2620,2624,2628,2632,2636,2640],{"title":2621,"path":2622,"stem":2623},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2625,"path":2626,"stem":2627},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2629,"path":2630,"stem":2631},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2633,"path":2634,"stem":2635},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2637,"path":2638,"stem":2639},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2641,"path":2642,"stem":2643},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2645,"icon":2610,"path":2646,"stem":2647,"children":2648,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2649,2653,2659,2663],{"title":2650,"path":2651,"stem":2652},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2654,"path":2655,"stem":2656,"children":2657},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2658],{"title":2654,"path":2655,"stem":2656},{"title":2660,"path":2661,"stem":2662},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2664,"path":2665,"stem":2666},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2668,"icon":2610,"path":2669,"stem":2670,"children":2671,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2672,2676,2680,2684,2688,2692,2696,2700],{"title":2673,"path":2674,"stem":2675},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2677,"path":2678,"stem":2679},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2681,"path":2682,"stem":2683},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2685,"path":2686,"stem":2687},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2689,"path":2690,"stem":2691},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2693,"path":2694,"stem":2695},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2697,"path":2698,"stem":2699},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2701,"path":2702,"stem":2703},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2705,"icon":2610,"path":2706,"stem":2707,"children":2708,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2709,2713,2717,2721,2725,2729],{"title":2710,"path":2711,"stem":2712},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2714,"path":2715,"stem":2716},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2718,"path":2719,"stem":2720},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2722,"path":2723,"stem":2724},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2726,"path":2727,"stem":2728},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2730,"path":2731,"stem":2732},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2734,"icon":2735,"path":2736,"stem":2737,"children":2738,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2739,2743,2747],{"title":2740,"path":2741,"stem":2742},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2744,"path":2745,"stem":2746},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2748,"path":2749,"stem":2750},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2752,"icon":2753,"path":2754,"stem":2755,"children":2756,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2757,2761,2765,2769,2773,2777,2781],{"title":2758,"path":2759,"stem":2760},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2762,"path":2763,"stem":2764},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2766,"path":2767,"stem":2768},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2770,"path":2771,"stem":2772},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2774,"path":2775,"stem":2776},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2778,"path":2779,"stem":2780},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2782,"path":2783,"stem":2784},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2782,"icon":793,"path":2786,"stem":2787,"children":2788,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2789,2793],{"title":2790,"path":2791,"stem":2792},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2794,"path":2795,"stem":2796},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2798,"icon":2799,"path":2800,"stem":2801,"children":2802,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2803],{"title":2798,"path":2804,"stem":2805},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2807,"icon":2808,"path":2809,"stem":2810,"children":2811,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2812],{"title":2807,"path":2813,"stem":2814},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2816,"icon":2817,"path":2818,"stem":2819,"children":2820,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2821,2897],{"title":2822,"icon":2823,"path":2824,"stem":2825,"children":2826},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2827,2829,2833,2837,2841,2845,2849,2853,2857,2861,2865,2869,2873,2877,2881,2885,2889,2893],{"title":2828,"path":2824,"stem":2825},"Docker: від нуля до production",{"title":2830,"path":2831,"stem":2832},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2834,"path":2835,"stem":2836},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2838,"path":2839,"stem":2840},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2842,"path":2843,"stem":2844},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2846,"path":2847,"stem":2848},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2850,"path":2851,"stem":2852},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2854,"path":2855,"stem":2856},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2858,"path":2859,"stem":2860},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2862,"path":2863,"stem":2864},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2866,"path":2867,"stem":2868},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2870,"path":2871,"stem":2872},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2874,"path":2875,"stem":2876},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2878,"path":2879,"stem":2880},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2882,"path":2883,"stem":2884},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2886,"path":2887,"stem":2888},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2890,"path":2891,"stem":2892},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2894,"path":2895,"stem":2896},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2898,"icon":2899,"path":2900,"stem":2901,"children":2902},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2903,2905,2909,2913,2917,2921,2925,2929,2933],{"title":2904,"path":2900,"stem":2901},"Kubernetes: від розробки до production",{"title":2906,"path":2907,"stem":2908},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2910,"path":2911,"stem":2912},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2914,"path":2915,"stem":2916},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2918,"path":2919,"stem":2920},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2922,"path":2923,"stem":2924},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2926,"path":2927,"stem":2928},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2930,"path":2931,"stem":2932},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2934,"path":2935,"stem":2936},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":2938,"icon":2939,"path":2940,"stem":2941,"children":2942,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[2943,2947,2951,2955,2959,2963,2967,2971,2975,2979,2983],{"title":2944,"path":2945,"stem":2946},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":2948,"path":2949,"stem":2950},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":2952,"path":2953,"stem":2954},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":2956,"path":2957,"stem":2958},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":2960,"path":2961,"stem":2962},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":2964,"path":2965,"stem":2966},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":2968,"path":2969,"stem":2970},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":2972,"path":2973,"stem":2974},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":2976,"path":2977,"stem":2978},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":2980,"path":2981,"stem":2982},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":2984,"path":2985,"stem":2986},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":2988,"icon":943,"path":2989,"stem":2990,"children":2991,"page":59},"DDD","\u002Fddd","10.ddd",[2992,2996,3000,3004,3008,3012,3016,3020,3024,3028,3032,3036,3040],{"title":2993,"path":2994,"stem":2995},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":2997,"path":2998,"stem":2999},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3001,"path":3002,"stem":3003},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3005,"path":3006,"stem":3007},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3009,"path":3010,"stem":3011},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3013,"path":3014,"stem":3015},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3017,"path":3018,"stem":3019},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3021,"path":3022,"stem":3023},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3025,"path":3026,"stem":3027},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3029,"path":3030,"stem":3031},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3033,"path":3034,"stem":3035},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3037,"path":3038,"stem":3039},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3041,"path":3042,"stem":3043},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3045,"icon":3046,"path":3047,"stem":3048,"children":3049,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3050,3054,3058,3062,3066,3070,3074],{"title":3051,"path":3052,"stem":3053},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3055,"path":3056,"stem":3057},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3059,"path":3060,"stem":3061},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3063,"path":3064,"stem":3065},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3067,"path":3068,"stem":3069},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3071,"path":3072,"stem":3073},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3075,"path":3076,"stem":3077},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3079,"icon":3080,"path":3081,"stem":3082,"children":3083,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3084,3088,3092,3096,3100,3104,3108,3112,3116,3120,3124,3128,3132,3136,3140,3144,3148,3152,3156,3160,3164,3168,3172,3176,3180,3184,3188,3192,3196,3200],{"title":3085,"path":3086,"stem":3087},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3089,"path":3090,"stem":3091},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3093,"path":3094,"stem":3095},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3097,"path":3098,"stem":3099},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3101,"path":3102,"stem":3103},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3105,"path":3106,"stem":3107},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3109,"path":3110,"stem":3111},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3113,"path":3114,"stem":3115},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3117,"path":3118,"stem":3119},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3121,"path":3122,"stem":3123},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3125,"path":3126,"stem":3127},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3129,"path":3130,"stem":3131},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3133,"path":3134,"stem":3135},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3137,"path":3138,"stem":3139},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3141,"path":3142,"stem":3143},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3145,"path":3146,"stem":3147},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3149,"path":3150,"stem":3151},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3153,"path":3154,"stem":3155},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3157,"path":3158,"stem":3159},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3161,"path":3162,"stem":3163},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3165,"path":3166,"stem":3167},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3169,"path":3170,"stem":3171},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3173,"path":3174,"stem":3175},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3177,"path":3178,"stem":3179},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3181,"path":3182,"stem":3183},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3185,"path":3186,"stem":3187},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3189,"path":3190,"stem":3191},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3193,"path":3194,"stem":3195},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3197,"path":3198,"stem":3199},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3201,"path":3202,"stem":3203},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3205,"path":3206,"stem":3207,"children":3208,"page":59},"AWS","\u002Faws","13.aws",[3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265,3269,3273,3277],{"title":3210,"path":3211,"stem":3212},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3214,"path":3215,"stem":3216},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3218,"path":3219,"stem":3220},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3222,"path":3223,"stem":3224},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3226,"path":3227,"stem":3228},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3230,"path":3231,"stem":3232},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3234,"path":3235,"stem":3236},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3238,"path":3239,"stem":3240},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3242,"path":3243,"stem":3244},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3246,"path":3247,"stem":3248},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3250,"path":3251,"stem":3252},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3254,"path":3255,"stem":3256},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3258,"path":3259,"stem":3260},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3262,"path":3263,"stem":3264},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3266,"path":3267,"stem":3268},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3270,"path":3271,"stem":3272},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3274,"path":3275,"stem":3276},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3278,"path":3279,"stem":3280},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3282,"path":3283,"stem":3284,"children":3285,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330],{"title":3287,"path":3288,"stem":3289},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3291,"path":3292,"stem":3293},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3295,"path":3296,"stem":3297},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3299,"path":3300,"stem":3301},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3303,"path":3304,"stem":3305},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3307,"path":3308,"stem":3309},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3311,"path":3312,"stem":3313},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3315,"path":3316,"stem":3317},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3319,"path":3320,"stem":3321},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3323,"path":3324,"stem":3325},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3327,"path":3328,"stem":3329},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3331,"path":3332,"stem":3333},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3335,"path":3336,"stem":3337},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3339,"title":3234,"body":3340,"description":18100,"extension":18101,"links":18102,"meta":18103,"navigation":3434,"path":3235,"seo":18104,"stem":3236,"__hash__":18105},"docs\u002F13.aws\u002F04.ec2.md",{"type":3341,"value":3342,"toc":18001},"minimark",[3343,3347,3357,3362,3374,3385,3390,3393,3396,3546,3549,3556,3560,3567,3576,3583,3588,3591,3611,3618,3646,3660,3663,3667,3681,3685,3697,3701,3711,3724,3760,3762,3766,3773,3924,3932,3946,3951,3972,3978,3985,4002,4010,4017,4028,4032,4042,4048,4146,4165,4167,4174,4178,4184,4191,4303,4307,4313,4345,4351,4357,4363,4367,4382,4385,4388,4464,4471,4473,4480,4570,4574,4581,4585,4591,4597,4606,4610,4619,4628,4634,4639,4643,4656,4661,4667,4693,4695,4702,4799,4803,4813,4823,4827,4833,4839,4845,4851,4855,4861,4875,5001,5005,5031,5036,5063,5070,5175,5181,5183,5190,5282,5286,5292,5297,5327,5331,5334,5395,5404,5416,5424,5428,5431,5511,5517,5519,5523,5530,5537,5695,5699,5709,5719,5729,5733,5742,5768,5772,5782,5806,5810,5821,5823,5830,5834,5945,5956,5966,5984,5987,5989,5993,6004,6126,6130,6141,6229,6242,6246,6252,6457,6466,6470,6476,6721,6738,6740,6747,6836,6840,6850,6855,6969,6974,7104,7106,7113,7117,7127,7134,7249,7254,7265,7334,7340,7411,7413,7417,7439,7445,7581,7585,7638,7642,7910,7914,7917,8057,8060,8080,8082,8089,8093,8103,8118,8123,8165,8168,8170,8174,8181,8185,8188,8198,8214,8224,8234,8238,8244,8251,8257,8264,8284,8299,8303,8310,8316,8325,8329,8436,8440,8449,8468,8491,8504,8508,8515,8521,8536,8542,8547,8568,8578,8580,8587,8591,8594,8598,9366,9442,9449,9451,9455,9461,9468,9549,9552,9593,9598,9637,9651,9660,9662,9666,9669,9685,9710,9726,9744,9783,9801,9817,9819,9823,9830,9867,9874,10078,10081,10137,10172,10174,10178,10187,10196,10238,10269,10272,10314,10350,10352,10356,10411,10451,10454,10476,10492,10499,10520,10529,10531,10538,10542,10553,10556,10614,10617,10642,10645,10802,10813,10894,10938,10991,10994,11016,11018,11025,11029,11038,11043,11049,11059,11064,11264,11268,11279,11282,11323,11332,11420,11513,11536,11539,11543,11565,11570,11632,11638,11643,11697,11709,11714,11717,11747,11750,11754,11767,11829,11837,11852,11875,11882,11932,11938,11942,11959,11973,11987,12019,12024,12030,12059,12062,12166,12171,12201,12240,12245,12270,12273,12468,12478,12604,12609,12678,12742,12759,12764,12771,12833,12917,12922,12936,12989,12996,13001,13087,13089,13096,13100,13103,13107,13559,13561,13565,13572,13582,13848,13851,13865,13868,13870,13872,13876,13883,13923,13942,14074,14076,14080,14085,14119,14126,14134,14139,14170,14173,14242,14245,14415,14421,14423,14427,14430,14602,14604,14608,14614,14756,14758,14765,14769,14772,14778,14783,14831,14834,14994,14998,15001,15016,15716,15718,15720,15722,15726,15737,15945,15964,15973,16043,16063,16076,16078,16082,16085,16105,16108,16213,16220,16464,16467,16515,16518,16548,16550,16554,16559,16566,16571,16591,16597,16602,16675,16680,16712,16721,16730,16732,16736,16752,16761,16942,16953,16960,16966,16968,16972,16977,17004,17009,17031,17036,17082,17087,17138,17143,17158,17256,17259,17299,17301,17305,17314,17319,17340,17345,17391,17408,17479,17488,17490,17494,17497,17510,17516,17523,17532,17546,17548,17552,17557,17730,17778,17780,17787,17791,17923,17925,17932,17936,17940,17951,17960,17964,17977,17983,17987,17997],[3344,3345,3234],"h1",{"id":3346},"amazon-ec2-elastic-compute-cloud",[3348,3349,3350],"p",{},[3351,3352],"img",{"alt":3353,"className":3354,"src":3356},"Amazon EC2 Elastic Compute Cloud virtual server in the cloud concept",[3355],"diagram-img","\u002Fimages\u002Faws\u002Fec2\u002F01.jpg",[3358,3359,3361],"h2",{"id":3360},"що-таке-ec2-і-навіщо-він-вам-потрібен","Що таке EC2 і навіщо він вам потрібен",[3348,3363,3364,3365,3369,3370,3373],{},"Уявіть, що вам потрібен комп'ютер — але не фізичний, який треба купувати, встановлювати в стійку, підключати кабелі та обслуговувати. Ви хочете просто ",[3366,3367,3368],"strong",{},"замовити комп'ютер через інтернет, отримати до нього доступ через кілька хвилин і платити лише поки він працює",". Саме це і є ",[3366,3371,3372],{},"Amazon EC2 (Elastic Compute Cloud)",".",[3348,3375,3376,3377,3380,3381,3384],{},"EC2 надає ",[3366,3378,3379],{},"віртуальні сервери"," (офіційна назва — ",[3366,3382,3383],{},"instances",") у хмарі AWS. Кожен instance — це повноцінний комп'ютер з процесором, оперативною пам'яттю, дисковим простором та мережевим інтерфейсом. Ви можете запустити від одного до тисяч instances за лічені хвилини — і зупинити їх так само швидко.",[3348,3386,3387],{},[3366,3388,3389],{},"Чому це важливо для .NET розробника?",[3348,3391,3392],{},"Класичний шлях деплою .NET додатку: купуємо або орендуємо фізичний сервер → встановлюємо Windows Server або Linux → налаштовуємо IIS або nginx → деплоїмо застосунок. Цей процес займає дні або тижні і коштує фіксовану суму незалежно від навантаження.",[3348,3394,3395],{},"З EC2: запускаємо instance з готовим образом операційної системи → встановлюємо .NET та IIS → деплоїмо → і сервер вже у production. Весь процес — кілька годин. Якщо навантаження зросло — запускаємо ще instances. Якщо впало — зупиняємо зайві. Платимо лише за фактичний час роботи.",[3397,3398,3399],"plant-uml",{},[3400,3401,3406],"pre",{"className":3402,"code":3403,"language":3404,"meta":3405,"style":3405},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Розробник\" as Dev\ncloud \"AWS Cloud\" as AWS {\n    node \"EC2 Instance\" as EC2 #dbeafe {\n        component \".NET 10 Runtime\" as dotnet\n        component \"ASP.NET Core API\" as api\n        component \"Ubuntu 26.04 LTS\" as os\n    }\n}\n\nrectangle \"Ваш комп\\'ютер\" as Local {\n    component \"Код + .csproj\" as Code\n}\n\ndatabase \"EBS Volume\" as EBS #d1fae5\n\nDev -right-> AWS : ssh ubuntu@IP\nCode -right-> EC2 : dotnet publish → scp\nEC2 -down-> EBS : \u002Fvar\u002Fapp\u002F\n@enduml\n","plantuml","",[3407,3408,3409,3417,3423,3429,3436,3442,3448,3454,3460,3466,3472,3478,3484,3489,3495,3501,3506,3511,3517,3522,3528,3534,3540],"code",{"__ignoreMap":3405},[3410,3411,3414],"span",{"class":3412,"line":3413},"line",1,[3410,3415,3416],{},"@startuml\n",[3410,3418,3420],{"class":3412,"line":3419},2,[3410,3421,3422],{},"skinparam style plain\n",[3410,3424,3426],{"class":3412,"line":3425},3,[3410,3427,3428],{},"skinparam backgroundColor #ffffff\n",[3410,3430,3432],{"class":3412,"line":3431},4,[3410,3433,3435],{"emptyLinePlaceholder":3434},true,"\n",[3410,3437,3439],{"class":3412,"line":3438},5,[3410,3440,3441],{},"actor \"Розробник\" as Dev\n",[3410,3443,3445],{"class":3412,"line":3444},6,[3410,3446,3447],{},"cloud \"AWS Cloud\" as AWS {\n",[3410,3449,3451],{"class":3412,"line":3450},7,[3410,3452,3453],{},"    node \"EC2 Instance\" as EC2 #dbeafe {\n",[3410,3455,3457],{"class":3412,"line":3456},8,[3410,3458,3459],{},"        component \".NET 10 Runtime\" as dotnet\n",[3410,3461,3463],{"class":3412,"line":3462},9,[3410,3464,3465],{},"        component \"ASP.NET Core API\" as api\n",[3410,3467,3469],{"class":3412,"line":3468},10,[3410,3470,3471],{},"        component \"Ubuntu 26.04 LTS\" as os\n",[3410,3473,3475],{"class":3412,"line":3474},11,[3410,3476,3477],{},"    }\n",[3410,3479,3481],{"class":3412,"line":3480},12,[3410,3482,3483],{},"}\n",[3410,3485,3487],{"class":3412,"line":3486},13,[3410,3488,3435],{"emptyLinePlaceholder":3434},[3410,3490,3492],{"class":3412,"line":3491},14,[3410,3493,3494],{},"rectangle \"Ваш комп\\'ютер\" as Local {\n",[3410,3496,3498],{"class":3412,"line":3497},15,[3410,3499,3500],{},"    component \"Код + .csproj\" as Code\n",[3410,3502,3504],{"class":3412,"line":3503},16,[3410,3505,3483],{},[3410,3507,3509],{"class":3412,"line":3508},17,[3410,3510,3435],{"emptyLinePlaceholder":3434},[3410,3512,3514],{"class":3412,"line":3513},18,[3410,3515,3516],{},"database \"EBS Volume\" as EBS #d1fae5\n",[3410,3518,3520],{"class":3412,"line":3519},19,[3410,3521,3435],{"emptyLinePlaceholder":3434},[3410,3523,3525],{"class":3412,"line":3524},20,[3410,3526,3527],{},"Dev -right-> AWS : ssh ubuntu@IP\n",[3410,3529,3531],{"class":3412,"line":3530},21,[3410,3532,3533],{},"Code -right-> EC2 : dotnet publish → scp\n",[3410,3535,3537],{"class":3412,"line":3536},22,[3410,3538,3539],{},"EC2 -down-> EBS : \u002Fvar\u002Fapp\u002F\n",[3410,3541,3543],{"class":3412,"line":3542},23,[3410,3544,3545],{},"@enduml\n",[3547,3548],"hr",{},[3348,3550,3551],{},[3351,3552],{"alt":3553,"className":3554,"src":3555},"EC2 instance types family comparison general purpose compute optimized memory storage",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F02.jpg",[3358,3557,3559],{"id":3558},"ec2-instance-types-вибір-правильного-сервера","EC2 Instance Types — вибір правильного сервера",[3348,3561,3562,3563,3566],{},"Instance Type — це конфігурація hardware вашого віртуального сервера: скільки ядер CPU, скільки RAM, який тип мережевого з'єднання. AWS пропонує ",[3366,3564,3565],{},"600+ типів instances",", згрупованих у сімейства за призначенням.",[3348,3568,3569,3572,3573],{},[3366,3570,3571],{},"Формат назви:"," ",[3407,3574,3575],{},"[сімейство][покоління].[розмір]",[3348,3577,3578,3579,3582],{},"Наприклад: ",[3407,3580,3581],{},"t3.micro"," — сімейство T (General Purpose), 3-тє покоління, розмір micro.",[3584,3585,3587],"h3",{"id":3586},"general-purpose-загального-призначення","General Purpose (Загального призначення)",[3348,3589,3590],{},"Найпопулярніша категорія — збалансоване співвідношення CPU та RAM. Ідеально для більшості .NET Web API, веб-сайтів, мікросервісів.",[3348,3592,3593,3572,3596,3599,3600,3599,3602,3599,3605,3599,3608],{},[3366,3594,3595],{},"Сімейство T (Burstable Performance):",[3407,3597,3598],{},"t3.nano",", ",[3407,3601,3581],{},[3407,3603,3604],{},"t3.small",[3407,3606,3607],{},"t3.medium",[3407,3609,3610],{},"t3.large",[3348,3612,3613,3614,3617],{},"Особливість T-instances: ",[3366,3615,3616],{},"CPU Credits",". В тихі моменти instance накопичує «кредити» CPU. При піковому навантаженні витрачає їх для короткочасного використання більш ніж базового % CPU. Це дозволяє мати дешевий instance, який справляється з рідкісними піками.",[3619,3620,3621,3631,3636,3641],"ul",{},[3622,3623,3624,3626,3627,3630],"li",{},[3407,3625,3581],{}," — 2 vCPU, 1 GB RAM ← входить у ",[3366,3628,3629],{},"Free Tier"," на 12 місяців",[3622,3632,3633,3635],{},[3407,3634,3604],{}," — 2 vCPU, 2 GB RAM",[3622,3637,3638,3640],{},[3407,3639,3607],{}," — 2 vCPU, 4 GB RAM ← мінімум для .NET 10 API з реальним навантаженням",[3622,3642,3643,3645],{},[3407,3644,3610],{}," — 2 vCPU, 8 GB RAM",[3348,3647,3648,3572,3651,3599,3654,3599,3657],{},[3366,3649,3650],{},"Сімейство M (Fixed Performance):",[3407,3652,3653],{},"m6i.large",[3407,3655,3656],{},"m6i.xlarge",[3407,3658,3659],{},"m6i.2xlarge",[3348,3661,3662],{},"Фіксований (не burstable) рівень CPU. Для production .NET застосунків зі стабільним навантаженням.",[3584,3664,3666],{"id":3665},"compute-optimized-оптимізовані-під-cpu","Compute Optimized (Оптимізовані під CPU)",[3348,3668,3669,3670,3673,3674,3599,3677,3680],{},"Сімейство ",[3366,3671,3672],{},"C",": ",[3407,3675,3676],{},"c6i.large",[3407,3678,3679],{},"c6i.xlarge",". Вище співвідношення CPU до RAM. Для CPU-інтенсивних задач: обробка зображень, відеотранскодування, ML inference, складні обчислення.",[3584,3682,3684],{"id":3683},"memory-optimized-оптимізовані-під-ram","Memory Optimized (Оптимізовані під RAM)",[3348,3686,3669,3687,3673,3690,3599,3693,3696],{},[3366,3688,3689],{},"R",[3407,3691,3692],{},"r6i.large",[3407,3694,3695],{},"r6i.xlarge",". Більше RAM відносно CPU. Для in-memory кешування (Redis\u002FMemcached на тому ж instance), великих баз даних в пам'яті, .NET застосунків з великими Dataset.",[3584,3698,3700],{"id":3699},"storage-optimized","Storage Optimized",[3348,3702,3669,3703,3706,3707,3710],{},[3366,3704,3705],{},"I"," та ",[3366,3708,3709],{},"D",": надвисока швидкість роботи з диском (NVMe SSD). Для баз даних з інтенсивним I\u002FO, Elasticsearch, аналітичних задач.",[3712,3713,3714,3717,3718,3720,3721,3723],"note",{},[3366,3715,3716],{},"Для початківців:"," якщо ви не впевнені — починайте з ",[3407,3719,3581],{}," (Free Tier) для навчання, ",[3407,3722,3607],{}," для перших production застосунків. Тип завжди можна змінити — зупинити instance, змінити тип, запустити знову.",[3725,3726,3727,3736,3744,3752],"card-group",{},[3728,3729,3732,3733,3735],"card",{"icon":3730,"title":3731},"i-heroicons-bolt","T — Burstable (Free Tier)","CPU Credits для рідкісних піків. ",[3407,3734,3581],{}," — Free Tier. Ідеально для розробки, навчання, низьконавантажених API.",[3728,3737,3740,3741,3743],{"icon":3738,"title":3739},"i-heroicons-server","M — General Purpose","Фіксований CPU, збалансоване CPU\u002FRAM. ",[3407,3742,3653],{}," — production .NET API зі стабільним навантаженням.",[3728,3745,3748,3749,3751],{"icon":3746,"title":3747},"i-heroicons-cpu-chip","C — Compute Optimized","Вище CPU до RAM. ",[3407,3750,3676],{}," — CPU-інтенсивні задачі: обробка зображень, ML inference, відеотранскодування.",[3728,3753,3756,3757,3759],{"icon":3754,"title":3755},"i-heroicons-circle-stack","R — Memory Optimized","Більше RAM до CPU. ",[3407,3758,3692],{}," — in-memory кешування, великі Dataset, аналітика в пам'яті.",[3547,3761],{},[3358,3763,3765],{"id":3764},"ec2-instance-lifecycle-стани-та-переходи","EC2 Instance Lifecycle — стани та переходи",[3348,3767,3768,3769,3772],{},"Кожен EC2 instance проходить через певні ",[3366,3770,3771],{},"стани (states)"," протягом свого існування. Розуміння цих станів критично важливе: від них залежить тарифікація, збереження даних та IP-адреса після рестарту.",[3397,3774,3775],{},[3400,3776,3778],{"className":3402,"code":3777,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"pending\\n(ініціалізується)\" as PEND #fef3c7\nrectangle \"running\\n(працює · тарифікується)\" as RUN #bbf7d0\nrectangle \"stopping\\n(зупиняється)\" as STOP #fde68a\nrectangle \"stopped\\n(зупинений · EBS збережений)\" as STOPD #e5e7eb\nrectangle \"shutting-down\\n(видаляється)\" as SHUT #fecaca\nrectangle \"terminated\\n(видалений назавжди)\" as TERM #fecaca\nrectangle \"rebooting\\n(перезавантажується)\" as REBOOT #dbeafe\n\nPEND -right-> RUN : ~1-3 хв\nRUN -down-> STOP : Stop\nRUN -right-> SHUT : Terminate\nRUN -up-> REBOOT : Reboot\nSTOP -down-> STOPD\nSTOPD -left-> PEND : Start\nSTOPD -right-> TERM : Terminate\nSHUT -right-> TERM\nREBOOT -left-> RUN : ~30 сек\n\nnote bottom of STOPD\n  Обчислення не тарифікуються.\n  EBS томи — тарифікуються далі.\n  Публічний IP змінюється при Start\n  (якщо немає Elastic IP).\nend note\n@enduml\n",[3407,3779,3780,3784,3788,3792,3796,3801,3806,3811,3816,3821,3826,3831,3835,3840,3845,3850,3855,3860,3865,3870,3875,3880,3884,3889,3895,3901,3907,3913,3919],{"__ignoreMap":3405},[3410,3781,3782],{"class":3412,"line":3413},[3410,3783,3416],{},[3410,3785,3786],{"class":3412,"line":3419},[3410,3787,3422],{},[3410,3789,3790],{"class":3412,"line":3425},[3410,3791,3428],{},[3410,3793,3794],{"class":3412,"line":3431},[3410,3795,3435],{"emptyLinePlaceholder":3434},[3410,3797,3798],{"class":3412,"line":3438},[3410,3799,3800],{},"rectangle \"pending\\n(ініціалізується)\" as PEND #fef3c7\n",[3410,3802,3803],{"class":3412,"line":3444},[3410,3804,3805],{},"rectangle \"running\\n(працює · тарифікується)\" as RUN #bbf7d0\n",[3410,3807,3808],{"class":3412,"line":3450},[3410,3809,3810],{},"rectangle \"stopping\\n(зупиняється)\" as STOP #fde68a\n",[3410,3812,3813],{"class":3412,"line":3456},[3410,3814,3815],{},"rectangle \"stopped\\n(зупинений · EBS збережений)\" as STOPD #e5e7eb\n",[3410,3817,3818],{"class":3412,"line":3462},[3410,3819,3820],{},"rectangle \"shutting-down\\n(видаляється)\" as SHUT #fecaca\n",[3410,3822,3823],{"class":3412,"line":3468},[3410,3824,3825],{},"rectangle \"terminated\\n(видалений назавжди)\" as TERM #fecaca\n",[3410,3827,3828],{"class":3412,"line":3474},[3410,3829,3830],{},"rectangle \"rebooting\\n(перезавантажується)\" as REBOOT #dbeafe\n",[3410,3832,3833],{"class":3412,"line":3480},[3410,3834,3435],{"emptyLinePlaceholder":3434},[3410,3836,3837],{"class":3412,"line":3486},[3410,3838,3839],{},"PEND -right-> RUN : ~1-3 хв\n",[3410,3841,3842],{"class":3412,"line":3491},[3410,3843,3844],{},"RUN -down-> STOP : Stop\n",[3410,3846,3847],{"class":3412,"line":3497},[3410,3848,3849],{},"RUN -right-> SHUT : Terminate\n",[3410,3851,3852],{"class":3412,"line":3503},[3410,3853,3854],{},"RUN -up-> REBOOT : Reboot\n",[3410,3856,3857],{"class":3412,"line":3508},[3410,3858,3859],{},"STOP -down-> STOPD\n",[3410,3861,3862],{"class":3412,"line":3513},[3410,3863,3864],{},"STOPD -left-> PEND : Start\n",[3410,3866,3867],{"class":3412,"line":3519},[3410,3868,3869],{},"STOPD -right-> TERM : Terminate\n",[3410,3871,3872],{"class":3412,"line":3524},[3410,3873,3874],{},"SHUT -right-> TERM\n",[3410,3876,3877],{"class":3412,"line":3530},[3410,3878,3879],{},"REBOOT -left-> RUN : ~30 сек\n",[3410,3881,3882],{"class":3412,"line":3536},[3410,3883,3435],{"emptyLinePlaceholder":3434},[3410,3885,3886],{"class":3412,"line":3542},[3410,3887,3888],{},"note bottom of STOPD\n",[3410,3890,3892],{"class":3412,"line":3891},24,[3410,3893,3894],{},"  Обчислення не тарифікуються.\n",[3410,3896,3898],{"class":3412,"line":3897},25,[3410,3899,3900],{},"  EBS томи — тарифікуються далі.\n",[3410,3902,3904],{"class":3412,"line":3903},26,[3410,3905,3906],{},"  Публічний IP змінюється при Start\n",[3410,3908,3910],{"class":3412,"line":3909},27,[3410,3911,3912],{},"  (якщо немає Elastic IP).\n",[3410,3914,3916],{"class":3412,"line":3915},28,[3410,3917,3918],{},"end note\n",[3410,3920,3922],{"class":3412,"line":3921},29,[3410,3923,3545],{},[3584,3925,3927,3928,3931],{"id":3926},"стан-stopped-зупинений-але-не-видалений","Стан ",[3407,3929,3930],{},"stopped"," — зупинений, але не видалений",[3348,3933,3934,3937,3938,3941,3942,3945],{},[3366,3935,3936],{},"Stop"," — аналог «вимкнути комп'ютер». Instance зупинений, але ",[3366,3939,3940],{},"існує",": EBS томи зберігають усі дані, Security Groups залишаються, Instance ID не змінюється. ",[3366,3943,3944],{},"Обчислення не тарифікуються",", проте EBS-диски тарифікуються далі (~$0.08\u002FGB\u002Fмісяць для gp3).",[3348,3947,3948],{},[3366,3949,3950],{},"Що відбувається при Stop → Start:",[3619,3952,3953,3960,3966,3969],{},[3622,3954,3955,3956,3959],{},"AWS може ",[3366,3957,3958],{},"перемістити instance на інший фізичний хост"," у тій самій AZ",[3622,3961,3962,3965],{},[3366,3963,3964],{},"Публічна IP-адреса змінюється"," — якщо не прикріплений Elastic IP, DNS запис на старий IP перестане працювати",[3622,3967,3968],{},"Приватна IP (всередині VPC) — залишається незмінною",[3622,3970,3971],{},"Дані на всіх EBS томах — збережені",[3348,3973,3974,3977],{},[3366,3975,3976],{},"Коли використовувати Stop:"," dev-сервери, які не потрібні вночі або у вихідні — зупиняєте ввечері, запускаєте вранці. Платите лише за EBS (~$1.6\u002Fмісяць за 20 GB gp3), не за EC2.",[3584,3979,3927,3981,3984],{"id":3980},"стан-terminated-незворотнє-видалення",[3407,3982,3983],{},"terminated"," — незворотнє видалення",[3348,3986,3987,3990,3991,3994,3995,3997,3998,4001],{},[3366,3988,3989],{},"Terminate"," — «видалити комп'ютер назавжди». Після переходу в ",[3407,3992,3993],{},"shutting-down"," → ",[3407,3996,3983],{}," instance ",[3366,3999,4000],{},"неможливо відновити",". За замовчуванням root EBS том також видаляється (параметр «Delete on termination»). Додаткові EBS томи можна налаштувати на збереження.",[4003,4004,4005,4006,4009],"caution",{},"Terminate — ",[3366,4007,4008],{},"незворотня"," операція. AWS не може відновити видалений instance. Перед видаленням переконайтесь, що важливі дані збережені у S3 або на окремому EBS томі з вимкненим «Delete on termination».",[3584,4011,3927,4013,4016],{"id":4012},"стан-rebooting-перезавантаження-без-зміни-хосту",[3407,4014,4015],{},"rebooting"," — перезавантаження без зміни хосту",[3348,4018,4019,4020,4023,4024,4027],{},"На відміну від Stop → Start, ",[3366,4021,4022],{},"Reboot"," залишає instance на тому самому фізичному хості. Публічна IP-адреса ",[3366,4025,4026],{},"не змінюється",". Тарифікація не переривається. Рекомендований для застосування оновлень ОС, що вимагають перезапуску.",[3584,4029,4031],{"id":4030},"hibernate-збереження-ram-на-диск","Hibernate — збереження RAM на диск",[3348,4033,4034,4037,4038,4041],{},[3366,4035,4036],{},"Hibernate"," — особливий режим зупинки: вміст ",[3366,4039,4040],{},"оперативної пам'яті зберігається на root EBS томі",". При наступному запуску instance відновлюється з точного стану: всі процеси продовжуються, з'єднання відновлюються — схоже на режим сну ноутбука.",[3348,4043,4044,4047],{},[3366,4045,4046],{},"Вимоги:"," instance type підтримує Hibernate (T3, M5, C5, R5 та ін.), root EBS обов'язково зашифрований, RAM ≤ 150 GB, тривалість Hibernate ≤ 60 днів.",[4049,4050,4051,4074],"table",{},[4052,4053,4054],"thead",{},[4055,4056,4057,4061,4065,4068,4071],"tr",{},[4058,4059,4060],"th",{},"Дія",[4058,4062,4064],{"align":4063},"center","CPU тарифікація",[4058,4066,4067],{"align":4063},"Публічний IP",[4058,4069,4070],{"align":4063},"Дані на EBS",[4058,4072,4073],{"align":4063},"Відновлення",[4075,4076,4077,4096,4112,4129],"tbody",{},[4055,4078,4079,4084,4087,4090,4093],{},[4080,4081,4082],"td",{},[3366,4083,3936],{},[4080,4085,4086],{"align":4063},"Ні",[4080,4088,4089],{"align":4063},"Змінюється",[4080,4091,4092],{"align":4063},"Збережені",[4080,4094,4095],{"align":4063},"Start (~1-2 хв)",[4055,4097,4098,4102,4104,4106,4109],{},[4080,4099,4100],{},[3366,4101,4036],{},[4080,4103,4086],{"align":4063},[4080,4105,4089],{"align":4063},[4080,4107,4108],{"align":4063},"Збережені + RAM",[4080,4110,4111],{"align":4063},"Start (~30 сек)",[4055,4113,4114,4118,4121,4124,4126],{},[4080,4115,4116],{},[3366,4117,4022],{},[4080,4119,4120],{"align":4063},"Так (без перерви)",[4080,4122,4123],{"align":4063},"Не змінюється",[4080,4125,4092],{"align":4063},[4080,4127,4128],{"align":4063},"Авто (~30 сек)",[4055,4130,4131,4135,4137,4140,4143],{},[4080,4132,4133],{},[3366,4134,3989],{},[4080,4136,4086],{"align":4063},[4080,4138,4139],{"align":4063},"Звільняється",[4080,4141,4142],{"align":4063},"Видаляються (root)",[4080,4144,4145],{"align":4063},"Неможливо",[4147,4148,4149,3572,4152,4154,4155,4161,4162,4164],"tip",{},[3366,4150,4151],{},"Free Tier та стани:",[3407,4153,3581],{}," у Free Tier — 750 годин на місяць ",[3366,4156,4157,4158],{},"у стані ",[3407,4159,4160],{},"running",". У стані ",[3407,4163,3930],{}," Free Tier-ліміт не витрачається, але EBS у Free Tier обмежений — 30 GB загалом.",[3547,4166],{},[3348,4168,4169],{},[3351,4170],{"alt":4171,"className":4172,"src":4173},"Amazon Machine Image AMI template creates EC2 instances from snapshot",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F03.jpg",[3358,4175,4177],{"id":4176},"ami-amazon-machine-image","AMI — Amazon Machine Image",[3348,4179,4180,4183],{},[3366,4181,4182],{},"AMI (Amazon Machine Image)"," — це готовий «шаблон» операційної системи з попередньо встановленим програмним забезпеченням. Коли ви запускаєте EC2 instance — ви вказуєте AMI, і instance «клонується» з цього шаблону.",[3348,4185,4186,4187,4190],{},"Думайте про AMI як про ",[3366,4188,4189],{},"знімок жорсткого диска"," (snapshot): включає ОС, всі встановлені програми, конфігурацію. Запуск instance з AMI — це як розгортання готового диска на новому комп'ютері.",[3397,4192,4193],{},[3400,4194,4196],{"className":3402,"code":4195,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"AMI: Ubuntu 26.04 LTS\\n(або Custom AMI + .NET 10)\" as AMI #dbeafe {\n    rectangle \"ОС + пакети\" as OS #bbf7d0\n    rectangle \"Конфігурація\" as CFG #d1fae5\n}\n\nnode \"EC2 Instance A\\n(eu-central-1a)\" as I1 #e0e7ff\nnode \"EC2 Instance B\\n(eu-central-1b)\" as I2 #e0e7ff\nnode \"EC2 Instance C\\n(Auto Scaling)\" as I3 #e0e7ff\n\nAMI -down-> I1 : клонування\nAMI -down-> I2 : клонування\nAMI -down-> I3 : клонування\n\nnote right of AMI\n  Один AMI — необмежена\n  кількість instances.\n  Кожен — незалежна копія.\nend note\n@enduml\n",[3407,4197,4198,4202,4206,4210,4214,4219,4224,4229,4233,4237,4242,4247,4252,4256,4261,4266,4271,4275,4280,4285,4290,4295,4299],{"__ignoreMap":3405},[3410,4199,4200],{"class":3412,"line":3413},[3410,4201,3416],{},[3410,4203,4204],{"class":3412,"line":3419},[3410,4205,3422],{},[3410,4207,4208],{"class":3412,"line":3425},[3410,4209,3428],{},[3410,4211,4212],{"class":3412,"line":3431},[3410,4213,3435],{"emptyLinePlaceholder":3434},[3410,4215,4216],{"class":3412,"line":3438},[3410,4217,4218],{},"rectangle \"AMI: Ubuntu 26.04 LTS\\n(або Custom AMI + .NET 10)\" as AMI #dbeafe {\n",[3410,4220,4221],{"class":3412,"line":3444},[3410,4222,4223],{},"    rectangle \"ОС + пакети\" as OS #bbf7d0\n",[3410,4225,4226],{"class":3412,"line":3450},[3410,4227,4228],{},"    rectangle \"Конфігурація\" as CFG #d1fae5\n",[3410,4230,4231],{"class":3412,"line":3456},[3410,4232,3483],{},[3410,4234,4235],{"class":3412,"line":3462},[3410,4236,3435],{"emptyLinePlaceholder":3434},[3410,4238,4239],{"class":3412,"line":3468},[3410,4240,4241],{},"node \"EC2 Instance A\\n(eu-central-1a)\" as I1 #e0e7ff\n",[3410,4243,4244],{"class":3412,"line":3474},[3410,4245,4246],{},"node \"EC2 Instance B\\n(eu-central-1b)\" as I2 #e0e7ff\n",[3410,4248,4249],{"class":3412,"line":3480},[3410,4250,4251],{},"node \"EC2 Instance C\\n(Auto Scaling)\" as I3 #e0e7ff\n",[3410,4253,4254],{"class":3412,"line":3486},[3410,4255,3435],{"emptyLinePlaceholder":3434},[3410,4257,4258],{"class":3412,"line":3491},[3410,4259,4260],{},"AMI -down-> I1 : клонування\n",[3410,4262,4263],{"class":3412,"line":3497},[3410,4264,4265],{},"AMI -down-> I2 : клонування\n",[3410,4267,4268],{"class":3412,"line":3503},[3410,4269,4270],{},"AMI -down-> I3 : клонування\n",[3410,4272,4273],{"class":3412,"line":3508},[3410,4274,3435],{"emptyLinePlaceholder":3434},[3410,4276,4277],{"class":3412,"line":3513},[3410,4278,4279],{},"note right of AMI\n",[3410,4281,4282],{"class":3412,"line":3519},[3410,4283,4284],{},"  Один AMI — необмежена\n",[3410,4286,4287],{"class":3412,"line":3524},[3410,4288,4289],{},"  кількість instances.\n",[3410,4291,4292],{"class":3412,"line":3530},[3410,4293,4294],{},"  Кожен — незалежна копія.\n",[3410,4296,4297],{"class":3412,"line":3536},[3410,4298,3918],{},[3410,4300,4301],{"class":3412,"line":3542},[3410,4302,3545],{},[3584,4304,4306],{"id":4305},"типи-ami","Типи AMI",[3348,4308,4309,4312],{},[3366,4310,4311],{},"AWS Managed AMI"," — офіційні образи від Amazon та партнерів:",[3619,4314,4315,4321,4327,4333,4339],{},[3622,4316,4317,4320],{},[3366,4318,4319],{},"Amazon Linux 2023"," — власний дистрибутив AWS, оптимізований для EC2. Рекомендований для більшості Linux-задач.",[3622,4322,4323,4326],{},[3366,4324,4325],{},"Ubuntu Server 26.04 LTS"," — популярний серед розробників. Відмінна підтримка .NET.",[3622,4328,4329,4332],{},[3366,4330,4331],{},"Windows Server 2022"," — для .NET Framework та IIS. Включає ліцензію Windows у вартість EC2.",[3622,4334,4335,4338],{},[3366,4336,4337],{},"Windows Server 2022 with SQL Server"," — для застосунків з MS SQL Server.",[3622,4340,4341,4344],{},[3366,4342,4343],{},"Red Hat Enterprise Linux (RHEL)"," — для корпоративних середовищ.",[3348,4346,4347,4350],{},[3366,4348,4349],{},"AWS Marketplace AMI"," — образи від третіх сторін з попередньо встановленим ПЗ (платні або безкоштовні): Bitnami WordPress, GitLab CE, Nginx Plus тощо.",[3348,4352,4353,4356],{},[3366,4354,4355],{},"Community AMI"," — публічні образи від спільноти. Використовуйте з обережністю — перевіряйте джерело.",[3348,4358,4359,4362],{},[3366,4360,4361],{},"Custom AMI (ваші власні)"," — ви можете створити AMI зі свого налаштованого instance. Зручно для auto scaling: замість того, щоб кожен новий сервер встановлював .NET та конфігурував застосунок — він одразу стартує з готовим середовищем.",[3584,4364,4366],{"id":4365},"ami-та-регіони","AMI та регіони",[3348,4368,4369,4370,4373,4374,4377,4378,4381],{},"Важливий нюанс: ",[3366,4371,4372],{},"AMI прив'язані до регіону",". AMI, доступна у ",[3407,4375,4376],{},"eu-central-1",", недоступна у ",[3407,4379,4380],{},"us-east-1"," — потрібно скопіювати. ID однієї й тієї ж ОС різниться між регіонами.",[4147,4383,4384],{},"При написанні скриптів автоматизації — ніколи не хардкодьте AMI ID! Замість цього запитуйте актуальний ID через SSM Parameter Store або AWS CLI фільтрами.",[3348,4386,4387],{},"Знайти актуальний AMI ID для Ubuntu 26.04 у вашому регіоні:",[3400,4389,4393],{"className":4390,"code":4391,"language":4392,"meta":3405,"style":3405},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","aws ec2 describe-images \\\n    --owners 099720109477 \\\n    --filters \"Name=name,Values=ubuntu\u002Fimages\u002Fhvm-ssd-gp3\u002Fubuntu-resolute-26.04-amd64-server-*\" \\\n    --query \"sort_by(Images, &CreationDate)[-1].ImageId\" \\\n    --output text --region eu-central-1\n# ami-0a1b2c3d4e5f67890\n","bash",[3407,4394,4395,4412,4424,4434,4444,4458],{"__ignoreMap":3405},[3410,4396,4397,4401,4405,4408],{"class":3412,"line":3413},[3410,4398,4400],{"class":4399},"s8Opu","aws",[3410,4402,4404],{"class":4403},"sbdoH"," ec2",[3410,4406,4407],{"class":4403}," describe-images",[3410,4409,4411],{"class":4410},"sjcCO"," \\\n",[3410,4413,4414,4418,4422],{"class":3412,"line":3419},[3410,4415,4417],{"class":4416},"su1O8","    --owners",[3410,4419,4421],{"class":4420},"sJj4R"," 099720109477",[3410,4423,4411],{"class":4410},[3410,4425,4426,4429,4432],{"class":3412,"line":3425},[3410,4427,4428],{"class":4416},"    --filters",[3410,4430,4431],{"class":4403}," \"Name=name,Values=ubuntu\u002Fimages\u002Fhvm-ssd-gp3\u002Fubuntu-resolute-26.04-amd64-server-*\"",[3410,4433,4411],{"class":4410},[3410,4435,4436,4439,4442],{"class":3412,"line":3431},[3410,4437,4438],{"class":4416},"    --query",[3410,4440,4441],{"class":4403}," \"sort_by(Images, &CreationDate)[-1].ImageId\"",[3410,4443,4411],{"class":4410},[3410,4445,4446,4449,4452,4455],{"class":3412,"line":3438},[3410,4447,4448],{"class":4416},"    --output",[3410,4450,4451],{"class":4403}," text",[3410,4453,4454],{"class":4416}," --region",[3410,4456,4457],{"class":4403}," eu-central-1\n",[3410,4459,4460],{"class":3412,"line":3444},[3410,4461,4463],{"class":4462},"spJ8K","# ami-0a1b2c3d4e5f67890\n",[3348,4465,4466,4467,4470],{},"Тут ",[3407,4468,4469],{},"099720109477"," — це офіційний AWS Account ID компанії Canonical (розробника Ubuntu). Це гарантує, що ви отримаєте справжній офіційний образ.",[3547,4472],{},[3348,4474,4475],{},[3351,4476],{"alt":4477,"className":4478,"src":4479},"EC2 pricing models on-demand reserved instances savings plans spot comparison",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F04.png",[3397,4481,4482],{},[3400,4483,4485],{"className":3402,"code":4484,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"On-Demand\\n$0.0116\u002Fгод (t3.micro)\" as OD #dbeafe\nrectangle \"Savings Plans\\n(1-3 роки, -30-75%)\" as SP #d1fae5\nrectangle \"Spot Instances\\n(-60-90%, переривувані)\" as SI #fef3c7\n\nrectangle \"Гнучкість\" as FLEX #e5e7eb\nrectangle \"Економія\" as SAVE #e5e7eb\n\nOD -down-> FLEX : максимальна\nOD -down-> SAVE : мінімальна\nSP -down-> FLEX : середня\nSP -down-> SAVE : висока\nSI -down-> FLEX : низька\nSI -down-> SAVE : максимальна\n@enduml\n",[3407,4486,4487,4491,4495,4499,4503,4508,4513,4518,4522,4527,4532,4536,4541,4546,4551,4556,4561,4566],{"__ignoreMap":3405},[3410,4488,4489],{"class":3412,"line":3413},[3410,4490,3416],{},[3410,4492,4493],{"class":3412,"line":3419},[3410,4494,3422],{},[3410,4496,4497],{"class":3412,"line":3425},[3410,4498,3428],{},[3410,4500,4501],{"class":3412,"line":3431},[3410,4502,3435],{"emptyLinePlaceholder":3434},[3410,4504,4505],{"class":3412,"line":3438},[3410,4506,4507],{},"rectangle \"On-Demand\\n$0.0116\u002Fгод (t3.micro)\" as OD #dbeafe\n",[3410,4509,4510],{"class":3412,"line":3444},[3410,4511,4512],{},"rectangle \"Savings Plans\\n(1-3 роки, -30-75%)\" as SP #d1fae5\n",[3410,4514,4515],{"class":3412,"line":3450},[3410,4516,4517],{},"rectangle \"Spot Instances\\n(-60-90%, переривувані)\" as SI #fef3c7\n",[3410,4519,4520],{"class":3412,"line":3456},[3410,4521,3435],{"emptyLinePlaceholder":3434},[3410,4523,4524],{"class":3412,"line":3462},[3410,4525,4526],{},"rectangle \"Гнучкість\" as FLEX #e5e7eb\n",[3410,4528,4529],{"class":3412,"line":3468},[3410,4530,4531],{},"rectangle \"Економія\" as SAVE #e5e7eb\n",[3410,4533,4534],{"class":3412,"line":3474},[3410,4535,3435],{"emptyLinePlaceholder":3434},[3410,4537,4538],{"class":3412,"line":3480},[3410,4539,4540],{},"OD -down-> FLEX : максимальна\n",[3410,4542,4543],{"class":3412,"line":3486},[3410,4544,4545],{},"OD -down-> SAVE : мінімальна\n",[3410,4547,4548],{"class":3412,"line":3491},[3410,4549,4550],{},"SP -down-> FLEX : середня\n",[3410,4552,4553],{"class":3412,"line":3497},[3410,4554,4555],{},"SP -down-> SAVE : висока\n",[3410,4557,4558],{"class":3412,"line":3503},[3410,4559,4560],{},"SI -down-> FLEX : низька\n",[3410,4562,4563],{"class":3412,"line":3508},[3410,4564,4565],{},"SI -down-> SAVE : максимальна\n",[3410,4567,4568],{"class":3412,"line":3513},[3410,4569,3545],{},[3358,4571,4573],{"id":4572},"ec2-pricing-models-моделі-оплати","EC2 Pricing Models — моделі оплати",[3348,4575,4576,4577,4580],{},"Ціна EC2 залежить не лише від типу instance, але і від ",[3366,4578,4579],{},"моделі оплати",". Правильний вибір може заощадити 50–90% витрат.",[3584,4582,4584],{"id":4583},"on-demand-оплата-по-факту","On-Demand — оплата по факту",[3348,4586,4587,4590],{},[3366,4588,4589],{},"Принцип:"," платите за кожну секунду роботи instance. Немає зобов'язань, немає передоплати. Запустили — платите. Зупинили — не платите.",[3348,4592,4593,4596],{},[3366,4594,4595],{},"Коли використовувати:"," навчання, розробка, тестування, нерегулярні задачі, коли ви ще не знаєте, скільки ресурсів потрібно.",[3348,4598,4599,4602,4603,4605],{},[3366,4600,4601],{},"Ціна"," (eu-central-1): ",[3407,4604,3581],{}," ≈ $0.0116\u002Fгод ≈ $8.4\u002Fмісяць при 24\u002F7 роботі.",[3584,4607,4609],{"id":4608},"reserved-instances-та-savings-plans","Reserved Instances та Savings Plans",[3348,4611,4612,4614,4615,4618],{},[3366,4613,4589],{}," ви зобов'язуєтесь використовувати певну кількість ресурсів протягом ",[3366,4616,4617],{},"1 або 3 років"," і отримуєте знижку 30–75% відносно On-Demand.",[3348,4620,4621,4624,4625,4627],{},[3366,4622,4623],{},"Reserved Instances (RI):"," резервуєте конкретний тип instance (",[3407,4626,3607],{},") у конкретному регіоні. Якщо вам раптом потрібен більший instance — RI не застосовується.",[3348,4629,4630,4633],{},[3366,4631,4632],{},"Savings Plans:"," гнучкіша альтернатива. Ви зобов'язуєтесь витрачати N доларів на годину (наприклад $0.05\u002Fгод), а знижка застосовується автоматично до будь-яких EC2 instances та Lambda, навіть якщо ви змінили тип.",[3348,4635,4636,4638],{},[3366,4637,4595],{}," для production серверів, які працюють 24\u002F7 протягом тривалого часу.",[3584,4640,4642],{"id":4641},"spot-instances-найдешевші-але-переривувані","Spot Instances — найдешевші, але переривувані",[3348,4644,4645,4647,4648,4651,4652,4655],{},[3366,4646,4589],{}," AWS продає невикористані EC2 потужності зі знижкою ",[3366,4649,4650],{},"60–90%"," відносно On-Demand. Але якщо ці потужності знадобляться AWS — ваш instance може бути ",[3366,4653,4654],{},"примусово зупинений"," з попередженням за 2 хвилини.",[3348,4657,4658,4660],{},[3366,4659,4595],{}," batch-обробка даних, ML-тренування, відеорендеринг, CI\u002FCD pipeline — задачі, які можна перервати і продовжити.",[3348,4662,4663,4666],{},[3366,4664,4665],{},"Коли НЕ використовувати:"," для production web-сервера, де переривання неприпустиме.",[3725,4668,4669,4678,4686],{},[3728,4670,4673,4674,4677],{"icon":4671,"title":4672},"i-heroicons-clock","On-Demand","Оплата посекундно. Без зобов'язань. ",[3366,4675,4676],{},"Ідеально:"," навчання, розробка, тестування.",[3728,4679,4682,4683,4685],{"icon":4680,"title":4681},"i-heroicons-banknotes","Savings Plans","Зобов'язання на 1-3 роки. Знижка 30-75%. ",[3366,4684,4676],{}," стабільні production сервери.",[3728,4687,4689,4690,4692],{"icon":3730,"title":4688},"Spot Instances","Знижка 60-90%. Можуть бути перервані. ",[3366,4691,4676],{}," batch-задачі, CI\u002FCD, ML.",[3547,4694],{},[3348,4696,4697],{},[3351,4698],{"alt":4699,"className":4700,"src":4701},"Amazon EBS Elastic Block Store volume types gp3 io2 st1 attached to EC2",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F05.jpg",[3397,4703,4704],{},[3400,4705,4707],{"className":3402,"code":4706,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nnode \"EC2 Instance\" as EC2 #dbeafe {\n    rectangle \".NET API\" as API #bbf7d0\n}\n\nrectangle \"EBS Volumes\" as EBS #e9ecef {\n    rectangle \"Root Volume\\ngp3 20GB (ОС)\" as ROOT #d1fae5\n    rectangle \"Data Volume\\nio2 100GB (БД)\" as DATA #fef3c7\n    rectangle \"Log Volume\\nst1 50GB (Логи)\" as LOG #f3f4f6\n}\n\ndatabase \"EBS Snapshots\\n(in S3)\" as SNAP #e0e7ff\n\nEC2 -right-> EBS : підключені\nROOT -down-> SNAP : backup щодня\nDATA -down-> SNAP : backup щогодини\n@enduml\n",[3407,4708,4709,4713,4717,4721,4725,4730,4735,4739,4743,4748,4753,4758,4763,4767,4771,4776,4780,4785,4790,4795],{"__ignoreMap":3405},[3410,4710,4711],{"class":3412,"line":3413},[3410,4712,3416],{},[3410,4714,4715],{"class":3412,"line":3419},[3410,4716,3422],{},[3410,4718,4719],{"class":3412,"line":3425},[3410,4720,3428],{},[3410,4722,4723],{"class":3412,"line":3431},[3410,4724,3435],{"emptyLinePlaceholder":3434},[3410,4726,4727],{"class":3412,"line":3438},[3410,4728,4729],{},"node \"EC2 Instance\" as EC2 #dbeafe {\n",[3410,4731,4732],{"class":3412,"line":3444},[3410,4733,4734],{},"    rectangle \".NET API\" as API #bbf7d0\n",[3410,4736,4737],{"class":3412,"line":3450},[3410,4738,3483],{},[3410,4740,4741],{"class":3412,"line":3456},[3410,4742,3435],{"emptyLinePlaceholder":3434},[3410,4744,4745],{"class":3412,"line":3462},[3410,4746,4747],{},"rectangle \"EBS Volumes\" as EBS #e9ecef {\n",[3410,4749,4750],{"class":3412,"line":3468},[3410,4751,4752],{},"    rectangle \"Root Volume\\ngp3 20GB (ОС)\" as ROOT #d1fae5\n",[3410,4754,4755],{"class":3412,"line":3474},[3410,4756,4757],{},"    rectangle \"Data Volume\\nio2 100GB (БД)\" as DATA #fef3c7\n",[3410,4759,4760],{"class":3412,"line":3480},[3410,4761,4762],{},"    rectangle \"Log Volume\\nst1 50GB (Логи)\" as LOG #f3f4f6\n",[3410,4764,4765],{"class":3412,"line":3486},[3410,4766,3483],{},[3410,4768,4769],{"class":3412,"line":3491},[3410,4770,3435],{"emptyLinePlaceholder":3434},[3410,4772,4773],{"class":3412,"line":3497},[3410,4774,4775],{},"database \"EBS Snapshots\\n(in S3)\" as SNAP #e0e7ff\n",[3410,4777,4778],{"class":3412,"line":3503},[3410,4779,3435],{"emptyLinePlaceholder":3434},[3410,4781,4782],{"class":3412,"line":3508},[3410,4783,4784],{},"EC2 -right-> EBS : підключені\n",[3410,4786,4787],{"class":3412,"line":3513},[3410,4788,4789],{},"ROOT -down-> SNAP : backup щодня\n",[3410,4791,4792],{"class":3412,"line":3519},[3410,4793,4794],{},"DATA -down-> SNAP : backup щогодини\n",[3410,4796,4797],{"class":3412,"line":3524},[3410,4798,3545],{},[3358,4800,4802],{"id":4801},"ebs-elastic-block-store-диски-для-ec2","EBS — Elastic Block Store (диски для EC2)",[3348,4804,4805,4808,4809,4812],{},[3366,4806,4807],{},"EBS (Elastic Block Store)"," — це мережеві диски (аналог жорстких дисків), які підключаються до EC2 instances. Кожен EC2 instance має щонайменше один EBS том — ",[3366,4810,4811],{},"root volume"," з операційною системою.",[3348,4814,4815,4818,4819,4822],{},[3366,4816,4817],{},"Ключова особливість EBS:"," дані ",[3366,4820,4821],{},"зберігаються незалежно від EC2 instance",". Якщо зупинити або навіть видалити instance — EBS том залишається і дані не втрачаються (якщо не увімкнено «Delete on termination»).",[3584,4824,4826],{"id":4825},"типи-ebs-томів","Типи EBS томів",[3348,4828,4829,4832],{},[3366,4830,4831],{},"gp3 (General Purpose SSD)"," — рекомендований для більшості задач. 3000 IOPS та 125 MB\u002Fs за замовчуванням (можна збільшити незалежно від розміру). Ціна: ~$0.08\u002FGB\u002Fмісяць.",[3348,4834,4835,4838],{},[3366,4836,4837],{},"gp2 (застарілий General Purpose SSD)"," — попереднє покоління. IOPS прив'язані до розміру (3 IOPS\u002FGB). Уникайте для нових проєктів.",[3348,4840,4841,4844],{},[3366,4842,4843],{},"io2 (Provisioned IOPS SSD)"," — для баз даних з інтенсивним I\u002FO. До 64,000 IOPS. Дорожче.",[3348,4846,4847,4850],{},[3366,4848,4849],{},"st1 (Throughput Optimized HDD)"," — для великих об'ємів послідовного читання\u002Fзапису. Дешевший за SSD, але повільніший.",[3584,4852,4854],{"id":4853},"ebs-snapshots-резервні-копії","EBS Snapshots — резервні копії",[3348,4856,4857,4860],{},[3366,4858,4859],{},"Snapshot"," — це точкова копія EBS тому, збережена в S3. Використовується для:",[3619,4862,4863,4866,4869,4872],{},[3622,4864,4865],{},"Резервного копіювання даних",[3622,4867,4868],{},"Переміщення даних між регіонами",[3622,4870,4871],{},"Створення AMI з поточного стану instance",[3622,4873,4874],{},"Відновлення instance до попереднього стану",[4876,4877,4879,4891,4902,4911,4920,4928,4931,4940,4949,4958,4967,4971,4980,4984,4993,4997],"terminal-preview",{"title":4878},"aws ec2 describe-volumes + create-snapshot",[4880,4881,4883,3572,4888],"div",{"className":4882},[3412],[3410,4884,4887],{"className":4885},[4886],"opacity-40","$",[3366,4889,4890],{},"aws ec2 describe-volumes \\",[4880,4892,4894,4898,4899],{"className":4893},[3412],[3410,4895,4897],{"className":4896},[4886],">","     ",[3366,4900,4901],{},"--filters \"Name=attachment.instance-id,Values=i-1234567890abcdef0\" \\",[4880,4903,4905,4898,4908],{"className":4904},[3412],[3410,4906,4897],{"className":4907},[4886],[3366,4909,4910],{},"--query \"Volumes[*].VolumeId\" \\",[4880,4912,4914,4898,4917],{"className":4913},[3412],[3410,4915,4897],{"className":4916},[4886],[3366,4918,4919],{},"--output text --region eu-central-1",[4880,4921,4923],{"className":4922},[3412],[3410,4924,4927],{"className":4925},[4926],"text-green-400","vol-0a1b2c3d4e5f67890",[4880,4929],{"className":4930},[3412],[4880,4932,4934,3572,4937],{"className":4933},[3412],[3410,4935,4887],{"className":4936},[4886],[3366,4938,4939],{},"aws ec2 create-snapshot \\",[4880,4941,4943,4898,4946],{"className":4942},[3412],[3410,4944,4897],{"className":4945},[4886],[3366,4947,4948],{},"--volume-id vol-0a1b2c3d4e5f67890 \\",[4880,4950,4952,4898,4955],{"className":4951},[3412],[3410,4953,4897],{"className":4954},[4886],[3366,4956,4957],{},"--description \"Backup before update\" \\",[4880,4959,4961,4898,4964],{"className":4960},[3412],[3410,4962,4897],{"className":4963},[4886],[3366,4965,4966],{},"--region eu-central-1",[4880,4968,4970],{"className":4969},[3412],"{",[4880,4972,4974,4975,4979],{"className":4973},[3412],"    \"SnapshotId\": ",[3410,4976,4978],{"className":4977},[4926],"\"snap-0123456789abcdef0\"",",",[4880,4981,4983],{"className":4982},[3412],"    \"VolumeId\": \"vol-0a1b2c3d4e5f67890\",",[4880,4985,4987,4988,4979],{"className":4986},[3412],"    \"State\": ",[3410,4989,4992],{"className":4990},[4991],"text-yellow-400","\"pending\"",[4880,4994,4996],{"className":4995},[3412],"    \"Progress\": \"0%\"",[4880,4998,5000],{"className":4999},[3412],"}",[3584,5002,5004],{"id":5003},"instance-store-надшвидке-тимчасове-сховище","Instance Store — надшвидке тимчасове сховище",[3348,5006,5007,5008,5011,5012,3599,5015,3599,5018,3599,5021,3599,5024,3599,5027,5030],{},"Поряд з EBS існує інший тип сховища — ",[3366,5009,5010],{},"Instance Store"," (ephemeral storage). Це фізично вбудовані NVMe SSD диски на тому самому хості, де запущений instance. Доступний лише для певних типів instances: сімейства ",[3407,5013,5014],{},"i4i",[3407,5016,5017],{},"i3",[3407,5019,5020],{},"d3",[3407,5022,5023],{},"m5d",[3407,5025,5026],{},"c5d",[3407,5028,5029],{},"r5d"," та ін.",[3348,5032,5033],{},[3366,5034,5035],{},"Характеристики Instance Store:",[3619,5037,5038,5048,5057],{},[3622,5039,5040,5043,5044,5047],{},[3366,5041,5042],{},"Надзвичайна швидкість:"," без мережевого hop до окремого сховища — затримка менше 0.1 мс, IOPS до мільйонів. ",[3407,5045,5046],{},"i4i.xlarge"," дає до 625,000 IOPS проти ~16,000 у gp3 EBS",[3622,5049,5050,4818,5053,5056],{},[3366,5051,5052],{},"Тимчасовий (ephemeral):",[3366,5054,5055],{},"повністю знищуються"," при Stop, Terminate або апаратному збої хоста. При Reboot — зберігаються",[3622,5058,5059,5062],{},[3366,5060,5061],{},"Включений у вартість:"," Instance Store не тарифікується окремо — ціна входить у cost instance type",[4003,5064,5065,5066,5069],{},"Ніколи не зберігайте на Instance Store дані без реплікації. База даних, конфіги, артефакти деплою — зберігайте на EBS або S3. Instance Store підходить лише для ",[3366,5067,5068],{},"тимчасових даних",": кеш, temp-директорії, буфери обробки — де втрата некритична або є кластерна реплікація.",[4049,5071,5072,5084],{},[4052,5073,5074],{},[4055,5075,5076,5079,5082],{},[4058,5077,5078],{},"Характеристика",[4058,5080,5081],{"align":4063},"EBS gp3",[4058,5083,5010],{"align":4063},[4075,5085,5086,5099,5112,5125,5137,5149,5162],{},[4055,5087,5088,5093,5096],{},[4080,5089,5090],{},[3366,5091,5092],{},"Persistence",[4080,5094,5095],{"align":4063},"Зберігається при Stop",[4080,5097,5098],{"align":4063},"Знищується при Stop",[4055,5100,5101,5106,5109],{},[4080,5102,5103],{},[3366,5104,5105],{},"IOPS",[4080,5107,5108],{"align":4063},"до 16,000",[4080,5110,5111],{"align":4063},"до 3.3 млн",[4055,5113,5114,5119,5122],{},[4080,5115,5116],{},[3366,5117,5118],{},"Latency",[4080,5120,5121],{"align":4063},"0.5–4 мс",[4080,5123,5124],{"align":4063},"\u003C 0.1 мс",[4055,5126,5127,5131,5134],{},[4080,5128,5129],{},[3366,5130,4601],{},[4080,5132,5133],{"align":4063},"~$0.08\u002FGB\u002Fмісяць",[4080,5135,5136],{"align":4063},"Включена в instance",[4055,5138,5139,5144,5147],{},[4080,5140,5141],{},[3366,5142,5143],{},"EBS Snapshot",[4080,5145,5146],{"align":4063},"Так",[4080,5148,4086],{"align":4063},[4055,5150,5151,5156,5159],{},[4080,5152,5153],{},[3366,5154,5155],{},"Зміна розміру",[4080,5157,5158],{"align":4063},"Так (без зупинки)",[4080,5160,5161],{"align":4063},"Ні (фіксований)",[4055,5163,5164,5169,5172],{},[4080,5165,5166],{},[3366,5167,5168],{},"Призначення",[4080,5170,5171],{"align":4063},"Основне сховище",[4080,5173,5174],{"align":4063},"Кеш, буфери, scratch",[3348,5176,5177,5180],{},[3366,5178,5179],{},"Типові сценарії:"," кеш Elasticsearch (дані є в основному сховищі), буфер черги повідомлень із реплікацією, проміжні файли при обробці відео або ML-пайплайні, scratch space для великих обчислень.",[3547,5182],{},[3348,5184,5185],{},[3351,5186],{"alt":5187,"className":5188,"src":5189},"EC2 Security Groups stateful firewall inbound outbound traffic rules diagram",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F06.png",[3397,5191,5192],{},[3400,5193,5195],{"className":3402,"code":5194,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nnode \"EC2 Instance\" as EC2 #dbeafe {\n    rectangle \"Security Group\\n(dotnet-api-sg)\" as SG #bbf7d0 {\n        rectangle \"Inbound Rules\" as IN #d1fae5\n        rectangle \"Outbound Rules\" as OUT #d1fae5\n    }\n}\n\nactor \"User\" as User\nactor \"Developer\" as Dev\n\nUser -right-> IN : HTTP(80) from 0.0.0.0\u002F0\nDev -right-> IN : SSH(22) from My IP\nIN -right-> \"ASP.NET Core API\" : allowed\nOUT --> \"Internet\" : all traffic allowed (default)\n@enduml\n",[3407,5196,5197,5201,5205,5209,5213,5217,5222,5227,5232,5236,5240,5244,5249,5254,5258,5263,5268,5273,5278],{"__ignoreMap":3405},[3410,5198,5199],{"class":3412,"line":3413},[3410,5200,3416],{},[3410,5202,5203],{"class":3412,"line":3419},[3410,5204,3422],{},[3410,5206,5207],{"class":3412,"line":3425},[3410,5208,3428],{},[3410,5210,5211],{"class":3412,"line":3431},[3410,5212,3435],{"emptyLinePlaceholder":3434},[3410,5214,5215],{"class":3412,"line":3438},[3410,5216,4729],{},[3410,5218,5219],{"class":3412,"line":3444},[3410,5220,5221],{},"    rectangle \"Security Group\\n(dotnet-api-sg)\" as SG #bbf7d0 {\n",[3410,5223,5224],{"class":3412,"line":3450},[3410,5225,5226],{},"        rectangle \"Inbound Rules\" as IN #d1fae5\n",[3410,5228,5229],{"class":3412,"line":3456},[3410,5230,5231],{},"        rectangle \"Outbound Rules\" as OUT #d1fae5\n",[3410,5233,5234],{"class":3412,"line":3462},[3410,5235,3477],{},[3410,5237,5238],{"class":3412,"line":3468},[3410,5239,3483],{},[3410,5241,5242],{"class":3412,"line":3474},[3410,5243,3435],{"emptyLinePlaceholder":3434},[3410,5245,5246],{"class":3412,"line":3480},[3410,5247,5248],{},"actor \"User\" as User\n",[3410,5250,5251],{"class":3412,"line":3486},[3410,5252,5253],{},"actor \"Developer\" as Dev\n",[3410,5255,5256],{"class":3412,"line":3491},[3410,5257,3435],{"emptyLinePlaceholder":3434},[3410,5259,5260],{"class":3412,"line":3497},[3410,5261,5262],{},"User -right-> IN : HTTP(80) from 0.0.0.0\u002F0\n",[3410,5264,5265],{"class":3412,"line":3503},[3410,5266,5267],{},"Dev -right-> IN : SSH(22) from My IP\n",[3410,5269,5270],{"class":3412,"line":3508},[3410,5271,5272],{},"IN -right-> \"ASP.NET Core API\" : allowed\n",[3410,5274,5275],{"class":3412,"line":3513},[3410,5276,5277],{},"OUT --> \"Internet\" : all traffic allowed (default)\n",[3410,5279,5280],{"class":3412,"line":3519},[3410,5281,3545],{},[3358,5283,5285],{"id":5284},"security-groups-файрвол-для-ec2","Security Groups — файрвол для EC2",[3348,5287,5288,5291],{},[3366,5289,5290],{},"Security Group"," — це віртуальний файрвол, який контролює вхідний (inbound) і вихідний (outbound) мережевий трафік для EC2 instance. Думайте про нього як про список правил: «дозволити трафік з порту 80» або «заборонити все, крім SSH з нашого IP».",[3348,5293,5294],{},[3366,5295,5296],{},"Ключові властивості Security Groups:",[3619,5298,5299,5305,5315,5321],{},[3622,5300,5301,5304],{},[3366,5302,5303],{},"Stateful (з відстеженням стану):"," якщо дозволено вхідне з'єднання — відповідний вихідний трафік дозволяється автоматично, і навпаки. Вам не потрібно додавати окреме правило для «відповідь на запит».",[3622,5306,5307,5310,5311,5314],{},[3366,5308,5309],{},"Дозвільні, не забороняючі:"," у Security Groups можна лише ",[3366,5312,5313],{},"дозволяти"," трафік. Не можна написати «заборонити з IP 1.2.3.4». Для заборони — використовуйте NACL.",[3622,5316,5317,5320],{},[3366,5318,5319],{},"Можна призначити кілька"," Security Groups одному instance.",[3622,5322,5323,5326],{},[3366,5324,5325],{},"За замовчуванням:"," весь вхідний трафік заборонений, весь вихідний — дозволений.",[3584,5328,5330],{"id":5329},"правила-security-group","Правила Security Group",[3348,5332,5333],{},"Кожне правило описує:",[4049,5335,5336,5349],{},[4052,5337,5338],{},[4055,5339,5340,5343,5346],{},[4058,5341,5342],{},"Поле",[4058,5344,5345],{},"Приклад",[4058,5347,5348],{},"Опис",[4075,5350,5351,5362,5373,5384],{},[4055,5352,5353,5356,5359],{},[4080,5354,5355],{},"Type",[4080,5357,5358],{},"HTTP, SSH, Custom TCP",[4080,5360,5361],{},"Тип трафіку (HTTP автоматично ставить порт 80)",[4055,5363,5364,5367,5370],{},[4080,5365,5366],{},"Protocol",[4080,5368,5369],{},"TCP, UDP, ICMP",[4080,5371,5372],{},"Протокол",[4055,5374,5375,5378,5381],{},[4080,5376,5377],{},"Port Range",[4080,5379,5380],{},"80, 443, 8080, 22",[4080,5382,5383],{},"Порт або діапазон портів",[4055,5385,5386,5389,5392],{},[4080,5387,5388],{},"Source",[4080,5390,5391],{},"0.0.0.0\u002F0, 203.0.113.5\u002F32, sg-xxx",[4080,5393,5394],{},"Звідки дозволений трафік",[3348,5396,5397,5403],{},[3366,5398,5399,5400],{},"Source ",[3407,5401,5402],{},"0.0.0.0\u002F0"," — означає «з будь-якого IP у світі». Використовуйте лише для публічних портів (80, 443).",[3348,5405,5406,5411,5412,5415],{},[3366,5407,5399,5408],{},[3407,5409,5410],{},"203.0.113.5\u002F32"," — лише з конкретного IP (наприклад, ваш домашній IP). ",[3407,5413,5414],{},"\u002F32"," означає один конкретний IP. Ідеально для SSH — не відкривайте 22 порт для всього світу!",[3348,5417,5418,5423],{},[3366,5419,5399,5420],{},[3407,5421,5422],{},"sg-0a1b2c3d"," — лише від інших EC2 instances з цим Security Group. Зручно для мікросервісної архітектури: API може звертатись до БД лише якщо знаходиться в тій самій Security Group.",[3584,5425,5427],{"id":5426},"security-groups-vs-nacls","Security Groups vs NACLs",[3348,5429,5430],{},"Студенти часто плутають ці два механізми. Ось принципова різниця:",[4049,5432,5433,5444],{},[4052,5434,5435],{},[4055,5436,5437,5439,5441],{},[4058,5438,5078],{},[4058,5440,5290],{},[4058,5442,5443],{},"Network ACL (NACL)",[4075,5445,5446,5459,5472,5485,5498],{},[4055,5447,5448,5453,5456],{},[4080,5449,5450],{},[3366,5451,5452],{},"Рівень застосування",[4080,5454,5455],{},"EC2 Instance",[4080,5457,5458],{},"Subnet",[4055,5460,5461,5466,5469],{},[4080,5462,5463],{},[3366,5464,5465],{},"Тип правил",[4080,5467,5468],{},"Лише Allow",[4080,5470,5471],{},"Allow та Deny",[4055,5473,5474,5479,5482],{},[4080,5475,5476],{},[3366,5477,5478],{},"Stateful\u002FStateless",[4080,5480,5481],{},"Stateful",[4080,5483,5484],{},"Stateless",[4055,5486,5487,5492,5495],{},[4080,5488,5489],{},[3366,5490,5491],{},"Порядок правил",[4080,5493,5494],{},"Усі правила перевіряються",[4080,5496,5497],{},"Правила нумеровані, першe спрацьоване",[4055,5499,5500,5505,5508],{},[4080,5501,5502],{},[3366,5503,5504],{},"Типове використання",[4080,5506,5507],{},"Щоденне управління доступом",[4080,5509,5510],{},"Блокування діапазонів IP",[3348,5512,5513,5516],{},[3366,5514,5515],{},"Для більшості задач достатньо Security Groups."," NACLs — додатковий шар захисту для специфічних сценаріїв (наприклад, заблокувати країну або діапазон IP після DDoS атаки).",[3547,5518],{},[3358,5520,5522],{"id":5521},"vpc-virtual-private-cloud-та-мережева-топологія-ec2","VPC — Virtual Private Cloud та мережева топологія EC2",[3348,5524,5525,5526,5529],{},"Кожен EC2 instance запускається ",[3366,5527,5528],{},"всередині VPC (Virtual Private Cloud)"," — ізольованої приватної мережі у хмарі AWS. Розуміння VPC необхідне для проєктування безпечної архітектури: саме VPC визначає, хто може звертатись до вашого instance і куди сам instance може ходити в мережі.",[3348,5531,5532,5533,5536],{},"AWS автоматично створює ",[3366,5534,5535],{},"Default VPC"," у кожному регіоні з готовими публічними підмережами та Internet Gateway. Для навчання та простих проєктів Default VPC цілком підходить — саме його ми використовуємо у практичних прикладах цього розділу.",[3397,5538,5539],{},[3400,5540,5542],{"className":3402,"code":5541,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ncloud \"Internet\" as INET\n\nrectangle \"VPC: 10.0.0.0\u002F16\" #dbeafe {\n    rectangle \"Public Subnet\\n10.0.1.0\u002F24\" as PUB #d1fae5 {\n        node \"Load Balancer (ALB)\\nабо EC2 (публічний)\" as ALB #bbf7d0\n    }\n    rectangle \"Private Subnet\\n10.0.2.0\u002F24\" as PRIV #fef3c7 {\n        node \"EC2\\n(App Server)\" as APP #fde68a\n        database \"RDS\\n(Database)\" as DB #fecaca\n    }\n    rectangle \"Internet Gateway\" as IGW #e0e7ff\n    rectangle \"NAT Gateway\\n(виходити — так,\\nвходити — ні)\" as NAT #e0e7ff\n}\n\nINET -down-> IGW\nIGW -down-> ALB\nALB -down-> APP : internal HTTP\nAPP -down-> DB : :5432 (private)\nAPP -up-> NAT : outbound (apt-get, AWS API)\nNAT -up-> IGW\nIGW -up-> INET\n\nnote right of PRIV\n  Немає маршруту до IGW —\n  недоступна з інтернету напряму.\n  Ідеально для БД та backend.\nend note\n@enduml\n",[3407,5543,5544,5548,5552,5556,5560,5565,5569,5574,5579,5584,5588,5593,5598,5603,5607,5612,5617,5621,5625,5630,5635,5640,5645,5650,5655,5660,5664,5669,5674,5679,5685,5690],{"__ignoreMap":3405},[3410,5545,5546],{"class":3412,"line":3413},[3410,5547,3416],{},[3410,5549,5550],{"class":3412,"line":3419},[3410,5551,3422],{},[3410,5553,5554],{"class":3412,"line":3425},[3410,5555,3428],{},[3410,5557,5558],{"class":3412,"line":3431},[3410,5559,3435],{"emptyLinePlaceholder":3434},[3410,5561,5562],{"class":3412,"line":3438},[3410,5563,5564],{},"cloud \"Internet\" as INET\n",[3410,5566,5567],{"class":3412,"line":3444},[3410,5568,3435],{"emptyLinePlaceholder":3434},[3410,5570,5571],{"class":3412,"line":3450},[3410,5572,5573],{},"rectangle \"VPC: 10.0.0.0\u002F16\" #dbeafe {\n",[3410,5575,5576],{"class":3412,"line":3456},[3410,5577,5578],{},"    rectangle \"Public Subnet\\n10.0.1.0\u002F24\" as PUB #d1fae5 {\n",[3410,5580,5581],{"class":3412,"line":3462},[3410,5582,5583],{},"        node \"Load Balancer (ALB)\\nабо EC2 (публічний)\" as ALB #bbf7d0\n",[3410,5585,5586],{"class":3412,"line":3468},[3410,5587,3477],{},[3410,5589,5590],{"class":3412,"line":3474},[3410,5591,5592],{},"    rectangle \"Private Subnet\\n10.0.2.0\u002F24\" as PRIV #fef3c7 {\n",[3410,5594,5595],{"class":3412,"line":3480},[3410,5596,5597],{},"        node \"EC2\\n(App Server)\" as APP #fde68a\n",[3410,5599,5600],{"class":3412,"line":3486},[3410,5601,5602],{},"        database \"RDS\\n(Database)\" as DB #fecaca\n",[3410,5604,5605],{"class":3412,"line":3491},[3410,5606,3477],{},[3410,5608,5609],{"class":3412,"line":3497},[3410,5610,5611],{},"    rectangle \"Internet Gateway\" as IGW #e0e7ff\n",[3410,5613,5614],{"class":3412,"line":3503},[3410,5615,5616],{},"    rectangle \"NAT Gateway\\n(виходити — так,\\nвходити — ні)\" as NAT #e0e7ff\n",[3410,5618,5619],{"class":3412,"line":3508},[3410,5620,3483],{},[3410,5622,5623],{"class":3412,"line":3513},[3410,5624,3435],{"emptyLinePlaceholder":3434},[3410,5626,5627],{"class":3412,"line":3519},[3410,5628,5629],{},"INET -down-> IGW\n",[3410,5631,5632],{"class":3412,"line":3524},[3410,5633,5634],{},"IGW -down-> ALB\n",[3410,5636,5637],{"class":3412,"line":3530},[3410,5638,5639],{},"ALB -down-> APP : internal HTTP\n",[3410,5641,5642],{"class":3412,"line":3536},[3410,5643,5644],{},"APP -down-> DB : :5432 (private)\n",[3410,5646,5647],{"class":3412,"line":3542},[3410,5648,5649],{},"APP -up-> NAT : outbound (apt-get, AWS API)\n",[3410,5651,5652],{"class":3412,"line":3891},[3410,5653,5654],{},"NAT -up-> IGW\n",[3410,5656,5657],{"class":3412,"line":3897},[3410,5658,5659],{},"IGW -up-> INET\n",[3410,5661,5662],{"class":3412,"line":3903},[3410,5663,3435],{"emptyLinePlaceholder":3434},[3410,5665,5666],{"class":3412,"line":3909},[3410,5667,5668],{},"note right of PRIV\n",[3410,5670,5671],{"class":3412,"line":3915},[3410,5672,5673],{},"  Немає маршруту до IGW —\n",[3410,5675,5676],{"class":3412,"line":3921},[3410,5677,5678],{},"  недоступна з інтернету напряму.\n",[3410,5680,5682],{"class":3412,"line":5681},30,[3410,5683,5684],{},"  Ідеально для БД та backend.\n",[3410,5686,5688],{"class":3412,"line":5687},31,[3410,5689,3918],{},[3410,5691,5693],{"class":3412,"line":5692},32,[3410,5694,3545],{},[3584,5696,5698],{"id":5697},"public-subnet-vs-private-subnet","Public Subnet vs Private Subnet",[3348,5700,5701,5704,5705,5708],{},[3366,5702,5703],{},"Public Subnet (публічна підмережа)"," — підмережа, таблиця маршрутизації якої містить маршрут ",[3407,5706,5707],{},"0.0.0.0\u002F0 → igw-xxx"," до Internet Gateway. Instances тут мають публічний IP і доступні з інтернету (якщо дозволяє Security Group). Сюди розміщують: Application Load Balancer, Bastion Host, публічні API, Elastic IP.",[3348,5710,5711,5714,5715,5718],{},[3366,5712,5713],{},"Private Subnet (приватна підмережа)"," — підмережа ",[3366,5716,5717],{},"без маршруту до IGW",". Instances недоступні з інтернету напряму — навіть якщо у них є публічний IP (він є, але маршрут відсутній). Ідеальне місце для: RDS, ElastiCache, backend-сервісів, черг повідомлень.",[4147,5720,5721,5724,5725,5728],{},[3366,5722,5723],{},"Правило безпечної архітектури:"," база даних — завжди у private subnet. Навіть якщо Security Group обмежує доступ — публічний IP на RDS залишається вектором атаки. Глибокий захист (defense in depth) = Security Group ",[3366,5726,5727],{},"плюс"," приватна підмережа.",[3584,5730,5732],{"id":5731},"internet-gateway-та-nat-gateway","Internet Gateway та NAT Gateway",[3348,5734,5735,5738,5739],{},[3366,5736,5737],{},"Internet Gateway (IGW)"," забезпечує двонаправлений трафік між instances у public subnet та інтернетом. Один на VPC, горизонтально масштабований, завжди доступний. ",[3366,5740,5741],{},"Безкоштовний.",[3348,5743,5744,5747,5748,5751,5752,5755,5756,5759,5760,3673,5763,5767],{},[3366,5745,5746],{},"NAT Gateway"," дозволяє instances у ",[3366,5749,5750],{},"private subnet"," ініціювати вихідні з'єднання (завантажувати оновлення, пакети, звертатись до AWS API), але ",[3366,5753,5754],{},"не дає зовнішнім клієнтам ініціювати вхідні з'єднання",". Тобто App Server у private subnet може ",[3407,5757,5758],{},"apt-get update",", проте підключитись до нього ззовні неможливо. NAT Gateway ",[3366,5761,5762],{},"платний",[5764,5765,5766],"del",{},"$0.045\u002Fгод (","$32\u002Fмісяць) + трафік ~$0.045\u002FGB.",[3584,5769,5771],{"id":5770},"cidr-запис-діапазонів-ip-адрес","CIDR — запис діапазонів IP-адрес",[3348,5773,5774,5777,5778,5781],{},[3366,5775,5776],{},"CIDR (Classless Inter-Domain Routing)"," — формат ",[3407,5779,5780],{},"IP\u002Fprefix",", де prefix — кількість фіксованих бітів:",[3619,5783,5784,5790,5796,5801],{},[3622,5785,5786,5789],{},[3407,5787,5788],{},"10.0.0.0\u002F16"," → 65,536 адрес (10.0.0.0 – 10.0.255.255) — типово для VPC",[3622,5791,5792,5795],{},[3407,5793,5794],{},"10.0.1.0\u002F24"," → 256 адрес (10.0.1.0 – 10.0.1.255) — типово для subnet",[3622,5797,5798,5800],{},[3407,5799,5410],{}," → одна конкретна адреса — для SSH правила у Security Group",[3622,5802,5803,5805],{},[3407,5804,5402],{}," → будь-яка адреса у світі — для публічних HTTP\u002FHTTPS правил",[3584,5807,5809],{"id":5808},"зони-доступності-та-відмовостійкість","Зони доступності та відмовостійкість",[3348,5811,5812,5813,5816,5817,5820],{},"Підмережа прив'язана до ",[3366,5814,5815],{},"однієї Availability Zone",". Best practice для production: мінімум дві підмережі (public + private) у ",[3366,5818,5819],{},"різних AZ",". Тоді збій однієї фізичної зони AWS не вимикає весь застосунок — Application Load Balancer автоматично перенаправляє трафік до instances в іншій AZ.",[3547,5822],{},[3348,5824,5825],{},[3351,5826],{"alt":5827,"className":5828,"src":5829},"Elastic IP static public IP address attached to EC2 instance diagram",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F07.png",[3358,5831,5833],{"id":5832},"elastic-ip-стала-публічна-ip-адреса","Elastic IP — стала публічна IP-адреса",[3397,5835,5836],{},[3400,5837,5839],{"className":3402,"code":5838,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Без Elastic IP\" #fef3c7 {\n    node \"Restart 1\\nIP: 3.64.100.10\" as N1 #fde68a\n    node \"Restart 2\\nIP: 18.184.55.32 ← змінився!\" as N2 #fecaca\n}\n\npackage \"З Elastic IP\" #d1fae5 {\n    rectangle \"Elastic IP: 3.64.185.42\\n(стала адреса)\" as EIP #bbf7d0\n    node \"Restart 1\" as N3 #e0e7ff\n    node \"Restart 2\" as N4 #e0e7ff\n}\n\nEIP -down-> N3\nEIP -down-> N4\n\nnote right of EIP\n  DNS: myapi.pp.ua → 3.64.185.42\n  Завжди коректний після рестарту\nend note\n@enduml\n",[3407,5840,5841,5845,5849,5853,5857,5862,5867,5872,5876,5880,5885,5890,5895,5900,5904,5908,5913,5918,5922,5927,5932,5937,5941],{"__ignoreMap":3405},[3410,5842,5843],{"class":3412,"line":3413},[3410,5844,3416],{},[3410,5846,5847],{"class":3412,"line":3419},[3410,5848,3422],{},[3410,5850,5851],{"class":3412,"line":3425},[3410,5852,3428],{},[3410,5854,5855],{"class":3412,"line":3431},[3410,5856,3435],{"emptyLinePlaceholder":3434},[3410,5858,5859],{"class":3412,"line":3438},[3410,5860,5861],{},"package \"Без Elastic IP\" #fef3c7 {\n",[3410,5863,5864],{"class":3412,"line":3444},[3410,5865,5866],{},"    node \"Restart 1\\nIP: 3.64.100.10\" as N1 #fde68a\n",[3410,5868,5869],{"class":3412,"line":3450},[3410,5870,5871],{},"    node \"Restart 2\\nIP: 18.184.55.32 ← змінився!\" as N2 #fecaca\n",[3410,5873,5874],{"class":3412,"line":3456},[3410,5875,3483],{},[3410,5877,5878],{"class":3412,"line":3462},[3410,5879,3435],{"emptyLinePlaceholder":3434},[3410,5881,5882],{"class":3412,"line":3468},[3410,5883,5884],{},"package \"З Elastic IP\" #d1fae5 {\n",[3410,5886,5887],{"class":3412,"line":3474},[3410,5888,5889],{},"    rectangle \"Elastic IP: 3.64.185.42\\n(стала адреса)\" as EIP #bbf7d0\n",[3410,5891,5892],{"class":3412,"line":3480},[3410,5893,5894],{},"    node \"Restart 1\" as N3 #e0e7ff\n",[3410,5896,5897],{"class":3412,"line":3486},[3410,5898,5899],{},"    node \"Restart 2\" as N4 #e0e7ff\n",[3410,5901,5902],{"class":3412,"line":3491},[3410,5903,3483],{},[3410,5905,5906],{"class":3412,"line":3497},[3410,5907,3435],{"emptyLinePlaceholder":3434},[3410,5909,5910],{"class":3412,"line":3503},[3410,5911,5912],{},"EIP -down-> N3\n",[3410,5914,5915],{"class":3412,"line":3508},[3410,5916,5917],{},"EIP -down-> N4\n",[3410,5919,5920],{"class":3412,"line":3513},[3410,5921,3435],{"emptyLinePlaceholder":3434},[3410,5923,5924],{"class":3412,"line":3519},[3410,5925,5926],{},"note right of EIP\n",[3410,5928,5929],{"class":3412,"line":3524},[3410,5930,5931],{},"  DNS: myapi.pp.ua → 3.64.185.42\n",[3410,5933,5934],{"class":3412,"line":3530},[3410,5935,5936],{},"  Завжди коректний після рестарту\n",[3410,5938,5939],{"class":3412,"line":3536},[3410,5940,3918],{},[3410,5942,5943],{"class":3412,"line":3542},[3410,5944,3545],{},[3348,5946,5947,5948,5951,5952,5955],{},"За замовчуванням кожен раз, коли ви ",[3366,5949,5950],{},"зупиняєте і запускаєте"," EC2 instance — він отримує ",[3366,5953,5954],{},"нову публічну IP-адресу",". Це проблема для production: DNS запис вказує на стару IP, і після рестарту сервер «зникає» з інтернету.",[3348,5957,5958,5961,5962,5965],{},[3366,5959,5960],{},"Elastic IP (EIP)"," — це ",[3366,5963,5964],{},"стала"," публічна IP-адреса, яку ви можете прикріпити до будь-якого EC2 instance. При зупинці\u002Fзапуску instance — EIP залишається незмінним.",[3348,5967,5968,5971,5972,5975,5976,5979,5980,5983],{},[3366,5969,5970],{},"Важливо про ціну:"," Elastic IP ",[3366,5973,5974],{},"безкоштовний",", поки він прикріплений до ",[3366,5977,5978],{},"запущеного"," instance. Але якщо EIP виділений але не прикріплений (або прикріплений до зупиненого instance) — він коштує ",[5764,5981,5982],{},"$0.005\u002Fгод (","$3.6\u002Fмісяць). AWS стягує плату за невикористані IP, щоб не допустити вичерпання пулу публічних адрес.",[4003,5985,5986],{},"Завжди звільняйте Elastic IP, якщо більше не використовуєте instance. EIP, що висить без instance — це «порожня» витрата. Після видалення instance — EIP лишається у вашому акаунті і тарифікується!",[3547,5988],{},[3358,5990,5992],{"id":5991},"cloudwatch-та-моніторинг-ec2","CloudWatch та моніторинг EC2",[3348,5994,5995,5996,5999,6000,6003],{},"Запустити застосунок — лише половина роботи. Щоб впевнено керувати production-сервером, потрібно ",[3366,5997,5998],{},"спостерігати"," за ним: знати завантаження CPU та пам'яті, стежити за здоров'ям instance, отримувати сповіщення до того, як про проблему повідомить користувач. ",[3366,6001,6002],{},"Amazon CloudWatch"," — сервіс моніторингу AWS, який автоматично збирає метрики з EC2, зберігає логи та надсилає сповіщення.",[3397,6005,6006],{},[3400,6007,6009],{"className":3402,"code":6008,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nnode \"EC2 Instance\" #dbeafe {\n    rectangle \"Hypervisor\\n(CPU, Network, Disk I\u002FO)\" as HYP #d1fae5\n    rectangle \"CloudWatch Agent\\n(RAM, Disk %, App Logs)\" as CWA #bbf7d0\n}\n\nrectangle \"Amazon CloudWatch\" #e0e7ff {\n    rectangle \"Metrics\\n(5-хв або 1-хв)\" as MET #fef3c7\n    rectangle \"Alarms\" as ALR #fde68a\n    rectangle \"Log Groups\\n(\u002Fec2\u002Fdotnet-api)\" as LOG #f3f4f6\n}\n\nrectangle \"SNS Topic\\n(email \u002F Slack)\" as SNS #fecaca\nrectangle \"Auto Scaling Group\\n(scale out\u002Fin)\" as ASG #d1fae5\n\nHYP -right-> MET : автоматично (безкоштовно)\nCWA -right-> MET : кожну хвилину\nCWA -right-> LOG : streaming\nMET -down-> ALR : threshold\nALR -right-> SNS : сповіщення\nALR -down-> ASG : масштабування\n@enduml\n",[3407,6010,6011,6015,6019,6023,6027,6032,6037,6042,6046,6050,6055,6060,6065,6070,6074,6078,6083,6088,6092,6097,6102,6107,6112,6117,6122],{"__ignoreMap":3405},[3410,6012,6013],{"class":3412,"line":3413},[3410,6014,3416],{},[3410,6016,6017],{"class":3412,"line":3419},[3410,6018,3422],{},[3410,6020,6021],{"class":3412,"line":3425},[3410,6022,3428],{},[3410,6024,6025],{"class":3412,"line":3431},[3410,6026,3435],{"emptyLinePlaceholder":3434},[3410,6028,6029],{"class":3412,"line":3438},[3410,6030,6031],{},"node \"EC2 Instance\" #dbeafe {\n",[3410,6033,6034],{"class":3412,"line":3444},[3410,6035,6036],{},"    rectangle \"Hypervisor\\n(CPU, Network, Disk I\u002FO)\" as HYP #d1fae5\n",[3410,6038,6039],{"class":3412,"line":3450},[3410,6040,6041],{},"    rectangle \"CloudWatch Agent\\n(RAM, Disk %, App Logs)\" as CWA #bbf7d0\n",[3410,6043,6044],{"class":3412,"line":3456},[3410,6045,3483],{},[3410,6047,6048],{"class":3412,"line":3462},[3410,6049,3435],{"emptyLinePlaceholder":3434},[3410,6051,6052],{"class":3412,"line":3468},[3410,6053,6054],{},"rectangle \"Amazon CloudWatch\" #e0e7ff {\n",[3410,6056,6057],{"class":3412,"line":3474},[3410,6058,6059],{},"    rectangle \"Metrics\\n(5-хв або 1-хв)\" as MET #fef3c7\n",[3410,6061,6062],{"class":3412,"line":3480},[3410,6063,6064],{},"    rectangle \"Alarms\" as ALR #fde68a\n",[3410,6066,6067],{"class":3412,"line":3486},[3410,6068,6069],{},"    rectangle \"Log Groups\\n(\u002Fec2\u002Fdotnet-api)\" as LOG #f3f4f6\n",[3410,6071,6072],{"class":3412,"line":3491},[3410,6073,3483],{},[3410,6075,6076],{"class":3412,"line":3497},[3410,6077,3435],{"emptyLinePlaceholder":3434},[3410,6079,6080],{"class":3412,"line":3503},[3410,6081,6082],{},"rectangle \"SNS Topic\\n(email \u002F Slack)\" as SNS #fecaca\n",[3410,6084,6085],{"class":3412,"line":3508},[3410,6086,6087],{},"rectangle \"Auto Scaling Group\\n(scale out\u002Fin)\" as ASG #d1fae5\n",[3410,6089,6090],{"class":3412,"line":3513},[3410,6091,3435],{"emptyLinePlaceholder":3434},[3410,6093,6094],{"class":3412,"line":3519},[3410,6095,6096],{},"HYP -right-> MET : автоматично (безкоштовно)\n",[3410,6098,6099],{"class":3412,"line":3524},[3410,6100,6101],{},"CWA -right-> MET : кожну хвилину\n",[3410,6103,6104],{"class":3412,"line":3530},[3410,6105,6106],{},"CWA -right-> LOG : streaming\n",[3410,6108,6109],{"class":3412,"line":3536},[3410,6110,6111],{},"MET -down-> ALR : threshold\n",[3410,6113,6114],{"class":3412,"line":3542},[3410,6115,6116],{},"ALR -right-> SNS : сповіщення\n",[3410,6118,6119],{"class":3412,"line":3891},[3410,6120,6121],{},"ALR -down-> ASG : масштабування\n",[3410,6123,6124],{"class":3412,"line":3897},[3410,6125,3545],{},[3584,6127,6129],{"id":6128},"стандартні-метрики-ec2-без-налаштувань-безкоштовно","Стандартні метрики EC2 (без налаштувань, безкоштовно)",[3348,6131,6132,6133,6136,6137,6140],{},"AWS автоматично збирає метрики ",[3366,6134,6135],{},"на рівні гіпервізора"," кожні 5 хвилин. При ",[3366,6138,6139],{},"Detailed Monitoring"," (~$0.01\u002Fметрика\u002Fмісяць) — кожну хвилину:",[4049,6142,6143,6156],{},[4052,6144,6145],{},[4055,6146,6147,6150,6153],{},[4058,6148,6149],{},"Метрика",[4058,6151,6152],{},"Що вимірює",[4058,6154,6155],{"align":4063},"Рекомендований поріг",[4075,6157,6158,6171,6188,6204,6217],{},[4055,6159,6160,6165,6168],{},[4080,6161,6162],{},[3407,6163,6164],{},"CPUUtilization",[4080,6166,6167],{},"% використання CPU",[4080,6169,6170],{"align":4063},"Alarm при > 80%",[4055,6172,6173,6182,6185],{},[4080,6174,6175,6178,6179],{},[3407,6176,6177],{},"NetworkIn"," \u002F ",[3407,6180,6181],{},"NetworkOut",[4080,6183,6184],{},"Байти мережевого трафіку",[4080,6186,6187],{"align":4063},"Аналіз тренду",[4055,6189,6190,6198,6201],{},[4080,6191,6192,6178,6195],{},[3407,6193,6194],{},"DiskReadOps",[3407,6196,6197],{},"DiskWriteOps",[4080,6199,6200],{},"IOPS операцій до EBS",[4080,6202,6203],{"align":4063},"\u003C 3000 для gp3 baseline",[4055,6205,6206,6211,6214],{},[4080,6207,6208],{},[3407,6209,6210],{},"StatusCheckFailed_Instance",[4080,6212,6213],{},"Збій перевірки всередині ОС",[4080,6215,6216],{"align":4063},"Alarm при > 0",[4055,6218,6219,6224,6227],{},[4080,6220,6221],{},[3407,6222,6223],{},"StatusCheckFailed_System",[4080,6225,6226],{},"Збій апаратного хосту",[4080,6228,6216],{"align":4063},[3348,6230,6231,6234,6235,3572,6238,6241],{},[3366,6232,6233],{},"Критична відсутність:"," стандартні метрики ",[3366,6236,6237],{},"не включають",[3407,6239,6240],{},"MemoryUtilization"," та заповненість диска — ці дані недоступні на рівні гіпервізора. Для них потрібен CloudWatch Agent.",[3584,6243,6245],{"id":6244},"cloudwatch-agent-ram-диск-та-логи-застосунку","CloudWatch Agent — RAM, диск та логи застосунку",[3348,6247,6248,6251],{},[3366,6249,6250],{},"CloudWatch Agent"," — легкий демон, що збирає метрики ОС та надсилає логи застосунку у CloudWatch. Встановлення на Ubuntu:",[3400,6253,6255],{"className":4390,"code":6254,"language":4392,"meta":3405,"style":3405},"# Встановлення агента\nsudo apt-get install -y amazon-cloudwatch-agent\n\n# Мінімальна конфігурація: RAM + диск + логи застосунку\nsudo tee \u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fetc\u002Famazon-cloudwatch-agent.json > \u002Fdev\u002Fnull \u003C\u003C'EOF'\n{\n  \"metrics\": {\n    \"append_dimensions\": { \"InstanceId\": \"${aws:InstanceId}\" },\n    \"metrics_collected\": {\n      \"mem\": { \"measurement\": [\"mem_used_percent\"], \"metrics_collection_interval\": 60 },\n      \"disk\": { \"measurement\": [\"disk_used_percent\"], \"resources\": [\"\u002F\"], \"metrics_collection_interval\": 60 }\n    }\n  },\n  \"logs\": {\n    \"logs_collected\": {\n      \"files\": {\n        \"collect_list\": [{\n          \"file_path\": \"\u002Fvar\u002Fapp\u002Flogs\u002Fapp.log\",\n          \"log_group_name\": \"\u002Fec2\u002Fdotnet-api\",\n          \"log_stream_name\": \"{instance_id}\"\n        }]\n      }\n    }\n  }\n}\nEOF\n\n# Запуск агента\nsudo \u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fbin\u002Famazon-cloudwatch-agent-ctl \\\n    -a fetch-config -m ec2 \\\n    -c file:\u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fetc\u002Famazon-cloudwatch-agent.json -s\n",[3407,6256,6257,6262,6279,6283,6288,6311,6316,6321,6326,6331,6336,6341,6345,6350,6355,6360,6365,6370,6375,6380,6385,6390,6395,6399,6404,6408,6413,6417,6422,6431,6446],{"__ignoreMap":3405},[3410,6258,6259],{"class":3412,"line":3413},[3410,6260,6261],{"class":4462},"# Встановлення агента\n",[3410,6263,6264,6267,6270,6273,6276],{"class":3412,"line":3419},[3410,6265,6266],{"class":4399},"sudo",[3410,6268,6269],{"class":4403}," apt-get",[3410,6271,6272],{"class":4403}," install",[3410,6274,6275],{"class":4416}," -y",[3410,6277,6278],{"class":4403}," amazon-cloudwatch-agent\n",[3410,6280,6281],{"class":3412,"line":3425},[3410,6282,3435],{"emptyLinePlaceholder":3434},[3410,6284,6285],{"class":3412,"line":3431},[3410,6286,6287],{"class":4462},"# Мінімальна конфігурація: RAM + диск + логи застосунку\n",[3410,6289,6290,6292,6295,6298,6302,6305,6308],{"class":3412,"line":3438},[3410,6291,6266],{"class":4399},[3410,6293,6294],{"class":4403}," tee",[3410,6296,6297],{"class":4403}," \u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fetc\u002Famazon-cloudwatch-agent.json",[3410,6299,6301],{"class":6300},"sHH4Y"," > ",[3410,6303,6304],{"class":4403},"\u002Fdev\u002Fnull",[3410,6306,6307],{"class":6300}," \u003C\u003C",[3410,6309,6310],{"class":6300},"'EOF'\n",[3410,6312,6313],{"class":3412,"line":3444},[3410,6314,6315],{"class":4403},"{\n",[3410,6317,6318],{"class":3412,"line":3450},[3410,6319,6320],{"class":4403},"  \"metrics\": {\n",[3410,6322,6323],{"class":3412,"line":3456},[3410,6324,6325],{"class":4403},"    \"append_dimensions\": { \"InstanceId\": \"${aws:InstanceId}\" },\n",[3410,6327,6328],{"class":3412,"line":3462},[3410,6329,6330],{"class":4403},"    \"metrics_collected\": {\n",[3410,6332,6333],{"class":3412,"line":3468},[3410,6334,6335],{"class":4403},"      \"mem\": { \"measurement\": [\"mem_used_percent\"], \"metrics_collection_interval\": 60 },\n",[3410,6337,6338],{"class":3412,"line":3474},[3410,6339,6340],{"class":4403},"      \"disk\": { \"measurement\": [\"disk_used_percent\"], \"resources\": [\"\u002F\"], \"metrics_collection_interval\": 60 }\n",[3410,6342,6343],{"class":3412,"line":3480},[3410,6344,3477],{"class":4403},[3410,6346,6347],{"class":3412,"line":3486},[3410,6348,6349],{"class":4403},"  },\n",[3410,6351,6352],{"class":3412,"line":3491},[3410,6353,6354],{"class":4403},"  \"logs\": {\n",[3410,6356,6357],{"class":3412,"line":3497},[3410,6358,6359],{"class":4403},"    \"logs_collected\": {\n",[3410,6361,6362],{"class":3412,"line":3503},[3410,6363,6364],{"class":4403},"      \"files\": {\n",[3410,6366,6367],{"class":3412,"line":3508},[3410,6368,6369],{"class":4403},"        \"collect_list\": [{\n",[3410,6371,6372],{"class":3412,"line":3513},[3410,6373,6374],{"class":4403},"          \"file_path\": \"\u002Fvar\u002Fapp\u002Flogs\u002Fapp.log\",\n",[3410,6376,6377],{"class":3412,"line":3519},[3410,6378,6379],{"class":4403},"          \"log_group_name\": \"\u002Fec2\u002Fdotnet-api\",\n",[3410,6381,6382],{"class":3412,"line":3524},[3410,6383,6384],{"class":4403},"          \"log_stream_name\": \"{instance_id}\"\n",[3410,6386,6387],{"class":3412,"line":3530},[3410,6388,6389],{"class":4403},"        }]\n",[3410,6391,6392],{"class":3412,"line":3536},[3410,6393,6394],{"class":4403},"      }\n",[3410,6396,6397],{"class":3412,"line":3542},[3410,6398,3477],{"class":4403},[3410,6400,6401],{"class":3412,"line":3891},[3410,6402,6403],{"class":4403},"  }\n",[3410,6405,6406],{"class":3412,"line":3897},[3410,6407,3483],{"class":4403},[3410,6409,6410],{"class":3412,"line":3903},[3410,6411,6412],{"class":6300},"EOF\n",[3410,6414,6415],{"class":3412,"line":3909},[3410,6416,3435],{"emptyLinePlaceholder":3434},[3410,6418,6419],{"class":3412,"line":3915},[3410,6420,6421],{"class":4462},"# Запуск агента\n",[3410,6423,6424,6426,6429],{"class":3412,"line":3921},[3410,6425,6266],{"class":4399},[3410,6427,6428],{"class":4403}," \u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fbin\u002Famazon-cloudwatch-agent-ctl",[3410,6430,4411],{"class":4410},[3410,6432,6433,6436,6439,6442,6444],{"class":3412,"line":5681},[3410,6434,6435],{"class":4416},"    -a",[3410,6437,6438],{"class":4403}," fetch-config",[3410,6440,6441],{"class":4416}," -m",[3410,6443,4404],{"class":4403},[3410,6445,4411],{"class":4410},[3410,6447,6448,6451,6454],{"class":3412,"line":5687},[3410,6449,6450],{"class":4416},"    -c",[3410,6452,6453],{"class":4403}," file:\u002Fopt\u002Faws\u002Famazon-cloudwatch-agent\u002Fetc\u002Famazon-cloudwatch-agent.json",[3410,6455,6456],{"class":4416}," -s\n",[3712,6458,6459,6460,6465],{},"CloudWatch Agent потребує IAM Role з ",[3366,6461,6462],{},[3407,6463,6464],{},"CloudWatchAgentServerPolicy"," — додайте її до ролі, прикріпленої до EC2 instance. Без цього дозволу агент не зможе надсилати метрики та логи.",[3584,6467,6469],{"id":6468},"cloudwatch-alarms-автоматичні-сповіщення","CloudWatch Alarms — автоматичні сповіщення",[3348,6471,6472,6475],{},[3366,6473,6474],{},"Alarm"," спрацьовує коли метрика порушує поріг і надсилає сповіщення через SNS (email, Slack, PagerDuty) або запускає Auto Scaling:",[3400,6477,6479],{"className":4390,"code":6478,"language":4392,"meta":3405,"style":3405},"# Alarm: CPU > 80% протягом 5 хвилин\naws cloudwatch put-metric-alarm \\\n    --alarm-name \"high-cpu-dotnet-api\" \\\n    --metric-name CPUUtilization \\\n    --namespace AWS\u002FEC2 \\\n    --dimensions Name=InstanceId,Value=$INSTANCE_ID \\\n    --statistic Average \\\n    --period 300 \\\n    --threshold 80 \\\n    --comparison-operator GreaterThanThreshold \\\n    --evaluation-periods 1 \\\n    --alarm-actions arn:aws:sns:eu-central-1:123456789012:alert-topic \\\n    --region eu-central-1\n\n# Alarm: instance health check failed → негайне сповіщення\naws cloudwatch put-metric-alarm \\\n    --alarm-name \"instance-status-failed\" \\\n    --metric-name StatusCheckFailed_Instance \\\n    --namespace AWS\u002FEC2 \\\n    --dimensions Name=InstanceId,Value=$INSTANCE_ID \\\n    --statistic Maximum \\\n    --period 60 \\\n    --threshold 0 \\\n    --comparison-operator GreaterThanThreshold \\\n    --evaluation-periods 1 \\\n    --alarm-actions arn:aws:sns:eu-central-1:123456789012:alert-topic \\\n    --region eu-central-1\n",[3407,6480,6481,6486,6498,6508,6518,6528,6542,6552,6562,6572,6582,6592,6602,6609,6613,6618,6628,6637,6646,6654,6664,6673,6682,6691,6699,6707,6715],{"__ignoreMap":3405},[3410,6482,6483],{"class":3412,"line":3413},[3410,6484,6485],{"class":4462},"# Alarm: CPU > 80% протягом 5 хвилин\n",[3410,6487,6488,6490,6493,6496],{"class":3412,"line":3419},[3410,6489,4400],{"class":4399},[3410,6491,6492],{"class":4403}," cloudwatch",[3410,6494,6495],{"class":4403}," put-metric-alarm",[3410,6497,4411],{"class":4410},[3410,6499,6500,6503,6506],{"class":3412,"line":3425},[3410,6501,6502],{"class":4416},"    --alarm-name",[3410,6504,6505],{"class":4403}," \"high-cpu-dotnet-api\"",[3410,6507,4411],{"class":4410},[3410,6509,6510,6513,6516],{"class":3412,"line":3431},[3410,6511,6512],{"class":4416},"    --metric-name",[3410,6514,6515],{"class":4403}," CPUUtilization",[3410,6517,4411],{"class":4410},[3410,6519,6520,6523,6526],{"class":3412,"line":3438},[3410,6521,6522],{"class":4416},"    --namespace",[3410,6524,6525],{"class":4403}," AWS\u002FEC2",[3410,6527,4411],{"class":4410},[3410,6529,6530,6533,6536,6540],{"class":3412,"line":3444},[3410,6531,6532],{"class":4416},"    --dimensions",[3410,6534,6535],{"class":4403}," Name=InstanceId,Value=",[3410,6537,6539],{"class":6538},"siwwj","$INSTANCE_ID",[3410,6541,4411],{"class":4410},[3410,6543,6544,6547,6550],{"class":3412,"line":3450},[3410,6545,6546],{"class":4416},"    --statistic",[3410,6548,6549],{"class":4403}," Average",[3410,6551,4411],{"class":4410},[3410,6553,6554,6557,6560],{"class":3412,"line":3456},[3410,6555,6556],{"class":4416},"    --period",[3410,6558,6559],{"class":4420}," 300",[3410,6561,4411],{"class":4410},[3410,6563,6564,6567,6570],{"class":3412,"line":3462},[3410,6565,6566],{"class":4416},"    --threshold",[3410,6568,6569],{"class":4420}," 80",[3410,6571,4411],{"class":4410},[3410,6573,6574,6577,6580],{"class":3412,"line":3468},[3410,6575,6576],{"class":4416},"    --comparison-operator",[3410,6578,6579],{"class":4403}," GreaterThanThreshold",[3410,6581,4411],{"class":4410},[3410,6583,6584,6587,6590],{"class":3412,"line":3474},[3410,6585,6586],{"class":4416},"    --evaluation-periods",[3410,6588,6589],{"class":4420}," 1",[3410,6591,4411],{"class":4410},[3410,6593,6594,6597,6600],{"class":3412,"line":3480},[3410,6595,6596],{"class":4416},"    --alarm-actions",[3410,6598,6599],{"class":4403}," arn:aws:sns:eu-central-1:123456789012:alert-topic",[3410,6601,4411],{"class":4410},[3410,6603,6604,6607],{"class":3412,"line":3486},[3410,6605,6606],{"class":4416},"    --region",[3410,6608,4457],{"class":4403},[3410,6610,6611],{"class":3412,"line":3491},[3410,6612,3435],{"emptyLinePlaceholder":3434},[3410,6614,6615],{"class":3412,"line":3497},[3410,6616,6617],{"class":4462},"# Alarm: instance health check failed → негайне сповіщення\n",[3410,6619,6620,6622,6624,6626],{"class":3412,"line":3503},[3410,6621,4400],{"class":4399},[3410,6623,6492],{"class":4403},[3410,6625,6495],{"class":4403},[3410,6627,4411],{"class":4410},[3410,6629,6630,6632,6635],{"class":3412,"line":3508},[3410,6631,6502],{"class":4416},[3410,6633,6634],{"class":4403}," \"instance-status-failed\"",[3410,6636,4411],{"class":4410},[3410,6638,6639,6641,6644],{"class":3412,"line":3513},[3410,6640,6512],{"class":4416},[3410,6642,6643],{"class":4403}," StatusCheckFailed_Instance",[3410,6645,4411],{"class":4410},[3410,6647,6648,6650,6652],{"class":3412,"line":3519},[3410,6649,6522],{"class":4416},[3410,6651,6525],{"class":4403},[3410,6653,4411],{"class":4410},[3410,6655,6656,6658,6660,6662],{"class":3412,"line":3524},[3410,6657,6532],{"class":4416},[3410,6659,6535],{"class":4403},[3410,6661,6539],{"class":6538},[3410,6663,4411],{"class":4410},[3410,6665,6666,6668,6671],{"class":3412,"line":3530},[3410,6667,6546],{"class":4416},[3410,6669,6670],{"class":4403}," Maximum",[3410,6672,4411],{"class":4410},[3410,6674,6675,6677,6680],{"class":3412,"line":3536},[3410,6676,6556],{"class":4416},[3410,6678,6679],{"class":4420}," 60",[3410,6681,4411],{"class":4410},[3410,6683,6684,6686,6689],{"class":3412,"line":3542},[3410,6685,6566],{"class":4416},[3410,6687,6688],{"class":4420}," 0",[3410,6690,4411],{"class":4410},[3410,6692,6693,6695,6697],{"class":3412,"line":3891},[3410,6694,6576],{"class":4416},[3410,6696,6579],{"class":4403},[3410,6698,4411],{"class":4410},[3410,6700,6701,6703,6705],{"class":3412,"line":3897},[3410,6702,6586],{"class":4416},[3410,6704,6589],{"class":4420},[3410,6706,4411],{"class":4410},[3410,6708,6709,6711,6713],{"class":3412,"line":3903},[3410,6710,6596],{"class":4416},[3410,6712,6599],{"class":4403},[3410,6714,4411],{"class":4410},[3410,6716,6717,6719],{"class":3412,"line":3909},[3410,6718,6606],{"class":4416},[3410,6720,4457],{"class":4403},[4147,6722,6723,3572,6726,6729,6730,6733,6734,6737],{},[3366,6724,6725],{},"Мінімальний production checklist alarms:",[3407,6727,6728],{},"CPUUtilization > 80%"," (перевантаження), ",[3407,6731,6732],{},"StatusCheckFailed_Instance > 0"," (instance недоступний), ",[3407,6735,6736],{},"disk_used_percent > 85%"," (через CloudWatch Agent — диск майже повний). Ці три алерми покривають найпоширеніші аварійні ситуації.",[3547,6739],{},[3348,6741,6742],{},[3351,6743],{"alt":6744,"className":6745,"src":6746},"EC2 User Data script automation first boot configuration bash PowerShell",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F08.png",[3397,6748,6749],{},[3400,6750,6752],{"className":3402,"code":6751,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Developer\" as Dev\nnode \"EC2 Instance Launch\" as LAUNCH #dbeafe {\n    rectangle \"User Data Script\" as UD #bbf7d0\n    queue \"First Boot Only\" as BOOT #f3f4f6\n    rectangle \"Install .NET 10\" as DOTNET #d1fae5\n    rectangle \"Setup App Dir\" as DIR #d1fae5\n}\n\nDev -right-> LAUNCH : запускає instance\nLAUNCH -down-> UD : виконує скрипт\nUD -down-> BOOT : один раз\nBOOT -down-> DOTNET : apt-get install\nBOOT -down-> DIR : mkdir \u002Fvar\u002Fapp\n@enduml\n",[3407,6753,6754,6758,6762,6766,6770,6774,6779,6784,6789,6794,6799,6803,6807,6812,6817,6822,6827,6832],{"__ignoreMap":3405},[3410,6755,6756],{"class":3412,"line":3413},[3410,6757,3416],{},[3410,6759,6760],{"class":3412,"line":3419},[3410,6761,3422],{},[3410,6763,6764],{"class":3412,"line":3425},[3410,6765,3428],{},[3410,6767,6768],{"class":3412,"line":3431},[3410,6769,3435],{"emptyLinePlaceholder":3434},[3410,6771,6772],{"class":3412,"line":3438},[3410,6773,5253],{},[3410,6775,6776],{"class":3412,"line":3444},[3410,6777,6778],{},"node \"EC2 Instance Launch\" as LAUNCH #dbeafe {\n",[3410,6780,6781],{"class":3412,"line":3450},[3410,6782,6783],{},"    rectangle \"User Data Script\" as UD #bbf7d0\n",[3410,6785,6786],{"class":3412,"line":3456},[3410,6787,6788],{},"    queue \"First Boot Only\" as BOOT #f3f4f6\n",[3410,6790,6791],{"class":3412,"line":3462},[3410,6792,6793],{},"    rectangle \"Install .NET 10\" as DOTNET #d1fae5\n",[3410,6795,6796],{"class":3412,"line":3468},[3410,6797,6798],{},"    rectangle \"Setup App Dir\" as DIR #d1fae5\n",[3410,6800,6801],{"class":3412,"line":3474},[3410,6802,3483],{},[3410,6804,6805],{"class":3412,"line":3480},[3410,6806,3435],{"emptyLinePlaceholder":3434},[3410,6808,6809],{"class":3412,"line":3486},[3410,6810,6811],{},"Dev -right-> LAUNCH : запускає instance\n",[3410,6813,6814],{"class":3412,"line":3491},[3410,6815,6816],{},"LAUNCH -down-> UD : виконує скрипт\n",[3410,6818,6819],{"class":3412,"line":3497},[3410,6820,6821],{},"UD -down-> BOOT : один раз\n",[3410,6823,6824],{"class":3412,"line":3503},[3410,6825,6826],{},"BOOT -down-> DOTNET : apt-get install\n",[3410,6828,6829],{"class":3412,"line":3508},[3410,6830,6831],{},"BOOT -down-> DIR : mkdir \u002Fvar\u002Fapp\n",[3410,6833,6834],{"class":3412,"line":3513},[3410,6835,3545],{},[3358,6837,6839],{"id":6838},"ec2-user-data-автоматизація-при-запуску","EC2 User Data — автоматизація при запуску",[3348,6841,6842,6845,6846,6849],{},[3366,6843,6844],{},"User Data"," — це скрипт (bash або PowerShell), який виконується ",[3366,6847,6848],{},"один раз"," при першому запуску EC2 instance. Це механізм автоматичного налаштування сервера без ручного SSH-підключення.",[3348,6851,6852],{},[3366,6853,6854],{},"Приклад User Data для Ubuntu з автоматичним встановленням .NET 10:",[3400,6856,6858],{"className":4390,"code":6857,"language":4392,"meta":3405,"style":3405},"#!\u002Fbin\u002Fbash\n# Цей скрипт виконається автоматично при першому запуску instance\n\n# Оновлюємо список пакетів (аналог \"перевірити оновлення\" у Windows)\napt-get update -y\n\n# .NET 10 входить до стандартних репозиторіїв Ubuntu 26.04 —\n# додатковий репозиторій Microsoft не потрібен\n# Встановлюємо .NET 10 Runtime (лише для запуску, не розробки)\napt-get install -y dotnet-runtime-10.0\n\n# Створюємо директорію для застосунку\nmkdir -p \u002Fvar\u002Fapp\n\n# Записуємо лог — щоб переконатись, що скрипт виконався\necho \"Setup completed at $(date)\" >> \u002Fvar\u002Fapp\u002Fsetup.log\n",[3407,6859,6860,6865,6870,6874,6879,6890,6894,6899,6904,6909,6920,6924,6929,6940,6944,6949],{"__ignoreMap":3405},[3410,6861,6862],{"class":3412,"line":3413},[3410,6863,6864],{"class":4462},"#!\u002Fbin\u002Fbash\n",[3410,6866,6867],{"class":3412,"line":3419},[3410,6868,6869],{"class":4462},"# Цей скрипт виконається автоматично при першому запуску instance\n",[3410,6871,6872],{"class":3412,"line":3425},[3410,6873,3435],{"emptyLinePlaceholder":3434},[3410,6875,6876],{"class":3412,"line":3431},[3410,6877,6878],{"class":4462},"# Оновлюємо список пакетів (аналог \"перевірити оновлення\" у Windows)\n",[3410,6880,6881,6884,6887],{"class":3412,"line":3438},[3410,6882,6883],{"class":4399},"apt-get",[3410,6885,6886],{"class":4403}," update",[3410,6888,6889],{"class":4416}," -y\n",[3410,6891,6892],{"class":3412,"line":3444},[3410,6893,3435],{"emptyLinePlaceholder":3434},[3410,6895,6896],{"class":3412,"line":3450},[3410,6897,6898],{"class":4462},"# .NET 10 входить до стандартних репозиторіїв Ubuntu 26.04 —\n",[3410,6900,6901],{"class":3412,"line":3456},[3410,6902,6903],{"class":4462},"# додатковий репозиторій Microsoft не потрібен\n",[3410,6905,6906],{"class":3412,"line":3462},[3410,6907,6908],{"class":4462},"# Встановлюємо .NET 10 Runtime (лише для запуску, не розробки)\n",[3410,6910,6911,6913,6915,6917],{"class":3412,"line":3468},[3410,6912,6883],{"class":4399},[3410,6914,6272],{"class":4403},[3410,6916,6275],{"class":4416},[3410,6918,6919],{"class":4403}," dotnet-runtime-10.0\n",[3410,6921,6922],{"class":3412,"line":3474},[3410,6923,3435],{"emptyLinePlaceholder":3434},[3410,6925,6926],{"class":3412,"line":3480},[3410,6927,6928],{"class":4462},"# Створюємо директорію для застосунку\n",[3410,6930,6931,6934,6937],{"class":3412,"line":3486},[3410,6932,6933],{"class":4399},"mkdir",[3410,6935,6936],{"class":4416}," -p",[3410,6938,6939],{"class":4403}," \u002Fvar\u002Fapp\n",[3410,6941,6942],{"class":3412,"line":3491},[3410,6943,3435],{"emptyLinePlaceholder":3434},[3410,6945,6946],{"class":3412,"line":3497},[3410,6947,6948],{"class":4462},"# Записуємо лог — щоб переконатись, що скрипт виконався\n",[3410,6950,6951,6954,6957,6960,6963,6966],{"class":3412,"line":3503},[3410,6952,6953],{"class":4399},"echo",[3410,6955,6956],{"class":4403}," \"Setup completed at $(",[3410,6958,6959],{"class":4399},"date",[3410,6961,6962],{"class":4403},")\"",[3410,6964,6965],{"class":6300}," >> ",[3410,6967,6968],{"class":4403},"\u002Fvar\u002Fapp\u002Fsetup.log\n",[3348,6970,6971],{},[3366,6972,6973],{},"User Data для Windows Server (PowerShell):",[3400,6975,6979],{"className":6976,"code":6977,"language":6978,"meta":3405,"style":3405},"language-powershell shiki shiki-themes light-plus dark-plus dark-plus","\u003Cpowershell>\n# Встановити .NET 10 Hosting Bundle (включає Runtime і IIS модуль)\n$url = \"https:\u002F\u002Fdownload.microsoft.com\u002Fdownload\u002Fdotnet\u002F10.0\u002Faspnetcore-runtime-10.0.0-win-x64.exe\"\n$installer = \"C:\\aspnetcore-installer.exe\"\nInvoke-WebRequest -Uri $url -OutFile $installer\nStart-Process -FilePath $installer -ArgumentList \"\u002Fquiet \u002Fnorestart\" -Wait\n\n# Встановити IIS та необхідні компоненти\nInstall-WindowsFeature -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console -IncludeManagementTools\n\n# Записати лог\n\"Setup completed at $(Get-Date)\" | Out-File C:\\setup.log\n\u003C\u002Fpowershell>\n","powershell",[3407,6980,6981,6986,6991,7002,7012,7028,7047,7051,7056,7064,7068,7073,7099],{"__ignoreMap":3405},[3410,6982,6983],{"class":3412,"line":3413},[3410,6984,6985],{"class":6300},"\u003Cpowershell>\n",[3410,6987,6988],{"class":3412,"line":3419},[3410,6989,6990],{"class":4462},"# Встановити .NET 10 Hosting Bundle (включає Runtime і IIS модуль)\n",[3410,6992,6993,6996,6999],{"class":3412,"line":3425},[3410,6994,6995],{"class":6538},"$url",[3410,6997,6998],{"class":6300}," = ",[3410,7000,7001],{"class":4403},"\"https:\u002F\u002Fdownload.microsoft.com\u002Fdownload\u002Fdotnet\u002F10.0\u002Faspnetcore-runtime-10.0.0-win-x64.exe\"\n",[3410,7003,7004,7007,7009],{"class":3412,"line":3431},[3410,7005,7006],{"class":6538},"$installer",[3410,7008,6998],{"class":6300},[3410,7010,7011],{"class":4403},"\"C:\\aspnetcore-installer.exe\"\n",[3410,7013,7014,7017,7020,7022,7025],{"class":3412,"line":3438},[3410,7015,7016],{"class":4399},"Invoke-WebRequest",[3410,7018,7019],{"class":6300}," -Uri ",[3410,7021,6995],{"class":6538},[3410,7023,7024],{"class":6300}," -OutFile ",[3410,7026,7027],{"class":6538},"$installer\n",[3410,7029,7030,7033,7036,7038,7041,7044],{"class":3412,"line":3444},[3410,7031,7032],{"class":4399},"Start-Process",[3410,7034,7035],{"class":6300}," -FilePath ",[3410,7037,7006],{"class":6538},[3410,7039,7040],{"class":6300}," -ArgumentList ",[3410,7042,7043],{"class":4403},"\"\u002Fquiet \u002Fnorestart\"",[3410,7045,7046],{"class":6300}," -Wait\n",[3410,7048,7049],{"class":3412,"line":3450},[3410,7050,3435],{"emptyLinePlaceholder":3434},[3410,7052,7053],{"class":3412,"line":3456},[3410,7054,7055],{"class":4462},"# Встановити IIS та необхідні компоненти\n",[3410,7057,7058,7061],{"class":3412,"line":3462},[3410,7059,7060],{"class":4399},"Install-WindowsFeature",[3410,7062,7063],{"class":6300}," -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console -IncludeManagementTools\n",[3410,7065,7066],{"class":3412,"line":3468},[3410,7067,3435],{"emptyLinePlaceholder":3434},[3410,7069,7070],{"class":3412,"line":3474},[3410,7071,7072],{"class":4462},"# Записати лог\n",[3410,7074,7075,7078,7081,7084,7087,7090,7093,7096],{"class":3412,"line":3480},[3410,7076,7077],{"class":4403},"\"Setup completed at ",[3410,7079,7080],{"class":4416},"$(",[3410,7082,7083],{"class":4399},"Get-Date",[3410,7085,7086],{"class":4416},")",[3410,7088,7089],{"class":4403},"\"",[3410,7091,7092],{"class":6300}," | ",[3410,7094,7095],{"class":4399},"Out-File",[3410,7097,7098],{"class":6300}," C:\\setup.log\n",[3410,7100,7101],{"class":3412,"line":3486},[3410,7102,7103],{"class":6300},"\u003C\u002Fpowershell>\n",[3547,7105],{},[3348,7107,7108],{},[3351,7109],{"alt":7110,"className":7111,"src":7112},"EC2 Instance Metadata Service IMDSv1 vs IMDSv2 token request flow",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F09.png",[3358,7114,7116],{"id":7115},"ec2-instance-metadata-service-imds","EC2 Instance Metadata Service (IMDS)",[3348,7118,7119,7122,7123,7126],{},[3366,7120,7121],{},"Instance Metadata Service (IMDS)"," — це внутрішній HTTP-сервіс, доступний з будь-якого EC2 instance за адресою ",[3407,7124,7125],{},"http:\u002F\u002F169.254.169.254",". Він надає інформацію про сам instance: ID, тип, регіон, IAM Role, публічний IP тощо.",[3348,7128,7129,7130,7133],{},"Ця адреса (",[3407,7131,7132],{},"169.254.169.254",") — спеціальна «link-local» адреса, доступна лише зсередини instance. Жоден зовнішній комп'ютер не може звернутись до IMDS ззовні — це внутрішній сервіс EC2.",[3397,7135,7136],{},[3400,7137,7139],{"className":3402,"code":7138,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nnode \"EC2 Instance\" as EC2 #dbeafe {\n    rectangle \".NET Application\\n(AWS SDK)\" as APP #bbf7d0\n    rectangle \"IMDS Client\\n(IMDSv2 token)\" as CLIENT #d1fae5\n}\n\nrectangle \"IMDS\\n169.254.169.254\\n(link-local, лише зсередини)\" as IMDS #e0e7ff\n\ndatabase \"IAM Role\\nCredentials\" as IAM #fef3c7\ndatabase \"Instance Metadata\\n(ID, IP, Region...)\" as META #fde68a\n\nAPP -right-> CLIENT : запит\nCLIENT -right-> IMDS : HTTP GET + IMDSv2 token\nIMDS -down-> IAM : \u002Fiam\u002Fsecurity-credentials\u002F\nIMDS -down-> META : \u002Finstance-id, \u002Fpublic-ipv4...\n\nnote bottom of IMDS\n  Доступний лише зсередини instance.\n  Зовнішній трафік не досягає IMDS.\nend note\n@enduml\n",[3407,7140,7141,7145,7149,7153,7157,7161,7166,7171,7175,7179,7184,7188,7193,7198,7202,7207,7212,7217,7222,7226,7231,7236,7241,7245],{"__ignoreMap":3405},[3410,7142,7143],{"class":3412,"line":3413},[3410,7144,3416],{},[3410,7146,7147],{"class":3412,"line":3419},[3410,7148,3422],{},[3410,7150,7151],{"class":3412,"line":3425},[3410,7152,3428],{},[3410,7154,7155],{"class":3412,"line":3431},[3410,7156,3435],{"emptyLinePlaceholder":3434},[3410,7158,7159],{"class":3412,"line":3438},[3410,7160,4729],{},[3410,7162,7163],{"class":3412,"line":3444},[3410,7164,7165],{},"    rectangle \".NET Application\\n(AWS SDK)\" as APP #bbf7d0\n",[3410,7167,7168],{"class":3412,"line":3450},[3410,7169,7170],{},"    rectangle \"IMDS Client\\n(IMDSv2 token)\" as CLIENT #d1fae5\n",[3410,7172,7173],{"class":3412,"line":3456},[3410,7174,3483],{},[3410,7176,7177],{"class":3412,"line":3462},[3410,7178,3435],{"emptyLinePlaceholder":3434},[3410,7180,7181],{"class":3412,"line":3468},[3410,7182,7183],{},"rectangle \"IMDS\\n169.254.169.254\\n(link-local, лише зсередини)\" as IMDS #e0e7ff\n",[3410,7185,7186],{"class":3412,"line":3474},[3410,7187,3435],{"emptyLinePlaceholder":3434},[3410,7189,7190],{"class":3412,"line":3480},[3410,7191,7192],{},"database \"IAM Role\\nCredentials\" as IAM #fef3c7\n",[3410,7194,7195],{"class":3412,"line":3486},[3410,7196,7197],{},"database \"Instance Metadata\\n(ID, IP, Region...)\" as META #fde68a\n",[3410,7199,7200],{"class":3412,"line":3491},[3410,7201,3435],{"emptyLinePlaceholder":3434},[3410,7203,7204],{"class":3412,"line":3497},[3410,7205,7206],{},"APP -right-> CLIENT : запит\n",[3410,7208,7209],{"class":3412,"line":3503},[3410,7210,7211],{},"CLIENT -right-> IMDS : HTTP GET + IMDSv2 token\n",[3410,7213,7214],{"class":3412,"line":3508},[3410,7215,7216],{},"IMDS -down-> IAM : \u002Fiam\u002Fsecurity-credentials\u002F\n",[3410,7218,7219],{"class":3412,"line":3513},[3410,7220,7221],{},"IMDS -down-> META : \u002Finstance-id, \u002Fpublic-ipv4...\n",[3410,7223,7224],{"class":3412,"line":3519},[3410,7225,3435],{"emptyLinePlaceholder":3434},[3410,7227,7228],{"class":3412,"line":3524},[3410,7229,7230],{},"note bottom of IMDS\n",[3410,7232,7233],{"class":3412,"line":3530},[3410,7234,7235],{},"  Доступний лише зсередини instance.\n",[3410,7237,7238],{"class":3412,"line":3536},[3410,7239,7240],{},"  Зовнішній трафік не досягає IMDS.\n",[3410,7242,7243],{"class":3412,"line":3542},[3410,7244,3918],{},[3410,7246,7247],{"class":3412,"line":3891},[3410,7248,3545],{},[3348,7250,7251],{},[3366,7252,7253],{},"Навіщо IMDS .NET розробнику:",[3619,7255,7256,7259,7262],{},[3622,7257,7258],{},"AWS SDK for .NET автоматично звертається до IMDS для отримання IAM Role credentials — саме завдяки цьому ваш код на EC2 не потребує Access Keys",[3622,7260,7261],{},"Можна отримати публічний IP instance прямо зсередині коду — без зовнішніх запитів",[3622,7263,7264],{},"Визначити, в якому регіоні запущений instance",[3400,7266,7268],{"className":4390,"code":7267,"language":4392,"meta":3405,"style":3405},"curl http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-id\n# i-1234567890abcdef0\n\ncurl http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fpublic-ipv4\n# 3.64.185.42\n\ncurl http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-type\n# t3.medium\n\ncurl -s http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fplacement\u002Fregion\n# eu-central-1\n",[3407,7269,7270,7278,7283,7287,7294,7299,7303,7310,7315,7319,7329],{"__ignoreMap":3405},[3410,7271,7272,7275],{"class":3412,"line":3413},[3410,7273,7274],{"class":4399},"curl",[3410,7276,7277],{"class":4403}," http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-id\n",[3410,7279,7280],{"class":3412,"line":3419},[3410,7281,7282],{"class":4462},"# i-1234567890abcdef0\n",[3410,7284,7285],{"class":3412,"line":3425},[3410,7286,3435],{"emptyLinePlaceholder":3434},[3410,7288,7289,7291],{"class":3412,"line":3431},[3410,7290,7274],{"class":4399},[3410,7292,7293],{"class":4403}," http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fpublic-ipv4\n",[3410,7295,7296],{"class":3412,"line":3438},[3410,7297,7298],{"class":4462},"# 3.64.185.42\n",[3410,7300,7301],{"class":3412,"line":3444},[3410,7302,3435],{"emptyLinePlaceholder":3434},[3410,7304,7305,7307],{"class":3412,"line":3450},[3410,7306,7274],{"class":4399},[3410,7308,7309],{"class":4403}," http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-type\n",[3410,7311,7312],{"class":3412,"line":3456},[3410,7313,7314],{"class":4462},"# t3.medium\n",[3410,7316,7317],{"class":3412,"line":3462},[3410,7318,3435],{"emptyLinePlaceholder":3434},[3410,7320,7321,7323,7326],{"class":3412,"line":3468},[3410,7322,7274],{"class":4399},[3410,7324,7325],{"class":4416}," -s",[3410,7327,7328],{"class":4403}," http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fplacement\u002Fregion\n",[3410,7330,7331],{"class":3412,"line":3474},[3410,7332,7333],{"class":4462},"# eu-central-1\n",[3348,7335,7336,7339],{},[3366,7337,7338],{},"IMDSv2 — безпечніша версія:"," AWS рекомендує використовувати IMDSv2, яка вимагає спочатку отримати токен, а потім використовувати його для запитів. Це захищає від Server-Side Request Forgery (SSRF) атак.",[3400,7341,7343],{"className":4390,"code":7342,"language":4392,"meta":3405,"style":3405},"TOKEN=$(curl -s -X PUT \"http:\u002F\u002F169.254.169.254\u002Flatest\u002Fapi\u002Ftoken\" \\\n    -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\")\n\ncurl -s -H \"X-aws-ec2-metadata-token: $TOKEN\" \\\n    http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-id\n# i-1234567890abcdef0\n",[3407,7344,7345,7368,7379,7383,7402,7407],{"__ignoreMap":3405},[3410,7346,7347,7350,7353,7355,7357,7360,7363,7366],{"class":3412,"line":3413},[3410,7348,7349],{"class":6538},"TOKEN",[3410,7351,7352],{"class":6300},"=$(",[3410,7354,7274],{"class":4399},[3410,7356,7325],{"class":4416},[3410,7358,7359],{"class":4416}," -X",[3410,7361,7362],{"class":4403}," PUT",[3410,7364,7365],{"class":4403}," \"http:\u002F\u002F169.254.169.254\u002Flatest\u002Fapi\u002Ftoken\"",[3410,7367,4411],{"class":4410},[3410,7369,7370,7373,7376],{"class":3412,"line":3419},[3410,7371,7372],{"class":4416},"    -H",[3410,7374,7375],{"class":4403}," \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"",[3410,7377,7378],{"class":6300},")\n",[3410,7380,7381],{"class":3412,"line":3425},[3410,7382,3435],{"emptyLinePlaceholder":3434},[3410,7384,7385,7387,7389,7392,7395,7398,7400],{"class":3412,"line":3431},[3410,7386,7274],{"class":4399},[3410,7388,7325],{"class":4416},[3410,7390,7391],{"class":4416}," -H",[3410,7393,7394],{"class":4403}," \"X-aws-ec2-metadata-token: ",[3410,7396,7397],{"class":6538},"$TOKEN",[3410,7399,7089],{"class":4403},[3410,7401,4411],{"class":4410},[3410,7403,7404],{"class":3412,"line":3438},[3410,7405,7406],{"class":4403},"    http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Finstance-id\n",[3410,7408,7409],{"class":3412,"line":3444},[3410,7410,7282],{"class":4462},[3547,7412],{},[3358,7414,7416],{"id":7415},"iam-role-для-ec2-безпечний-доступ-без-хардкоду-ключів","IAM Role для EC2 — безпечний доступ без хардкоду ключів",[3348,7418,7419,7420,7423,7424,3706,7427,7430,7431,7434,7435,7438],{},"Коли .NET код на EC2 звертається до AWS-сервісів (S3, DynamoDB, SQS, Secrets Manager), йому потрібні ",[3366,7421,7422],{},"облікові дані (credentials)"," — щоб AWS міг верифікувати, від чийого імені виконуються запити і чи є на це дозвіл. Початківці часто допускають критичну помилку безпеки: хардкодять ",[3407,7425,7426],{},"AWS_ACCESS_KEY_ID",[3407,7428,7429],{},"AWS_SECRET_ACCESS_KEY"," прямо у ",[3407,7432,7433],{},"appsettings.json"," або ",[3407,7436,7437],{},".env"," файл на сервері. Якщо такий файл потрапить у публічний Git-репозиторій — автоматичні сканери знайдуть і використають ці ключі за лічені хвилини.",[3348,7440,7441,7444],{},[3366,7442,7443],{},"Правильне рішення — IAM Role",", прикріплена до EC2 instance. AWS SDK отримує тимчасові автоматично-ротовані credentials через IMDS. Жодного хардкоду. Жодного ризику витоку ключів.",[3397,7446,7447],{},[3400,7448,7450],{"className":3402,"code":7449,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"DevOps\" as DEV #dbeafe\n\nrectangle \"AWS IAM\" #bbf7d0 {\n    rectangle \"IAM Role\\nec2-api-role\" as ROLE #d1fae5\n    rectangle \"Trust Policy\\n(ec2.amazonaws.com)\" as TRUST #d1fae5\n    rectangle \"Permission Policy\\n(s3:GetObject, sqs:SendMessage)\" as PERM #d1fae5\n}\n\nnode \"EC2 Instance\" #fef3c7 {\n    rectangle \"Instance Profile\\n(обгортка для Role)\" as PROFILE #fde68a\n    rectangle \"AWS SDK for .NET\\nDefaultAWSCredentials\" as SDK #e0e7ff\n}\n\ndatabase \"IMDS 169.254.169.254\\n\u002Fiam\u002Fsecurity-credentials\u002F\" as IMDS #f3f4f6\nstorage \"S3 \u002F SQS \u002F DynamoDB...\" as SVC #e0e7ff\n\nDEV -right-> ROLE : створює\nROLE -down-> TRUST\nROLE -down-> PERM\nDEV -right-> PROFILE : attach до instance\nSDK -down-> IMDS : запит credentials\nIMDS -up-> SDK : temp credentials\\n(1 год TTL · авто-ротація)\nSDK -right-> SVC : підписаний AWS request\n@enduml\n",[3407,7451,7452,7456,7460,7464,7468,7473,7477,7482,7487,7492,7497,7501,7505,7510,7515,7520,7524,7528,7533,7538,7542,7547,7552,7557,7562,7567,7572,7577],{"__ignoreMap":3405},[3410,7453,7454],{"class":3412,"line":3413},[3410,7455,3416],{},[3410,7457,7458],{"class":3412,"line":3419},[3410,7459,3422],{},[3410,7461,7462],{"class":3412,"line":3425},[3410,7463,3428],{},[3410,7465,7466],{"class":3412,"line":3431},[3410,7467,3435],{"emptyLinePlaceholder":3434},[3410,7469,7470],{"class":3412,"line":3438},[3410,7471,7472],{},"actor \"DevOps\" as DEV #dbeafe\n",[3410,7474,7475],{"class":3412,"line":3444},[3410,7476,3435],{"emptyLinePlaceholder":3434},[3410,7478,7479],{"class":3412,"line":3450},[3410,7480,7481],{},"rectangle \"AWS IAM\" #bbf7d0 {\n",[3410,7483,7484],{"class":3412,"line":3456},[3410,7485,7486],{},"    rectangle \"IAM Role\\nec2-api-role\" as ROLE #d1fae5\n",[3410,7488,7489],{"class":3412,"line":3462},[3410,7490,7491],{},"    rectangle \"Trust Policy\\n(ec2.amazonaws.com)\" as TRUST #d1fae5\n",[3410,7493,7494],{"class":3412,"line":3468},[3410,7495,7496],{},"    rectangle \"Permission Policy\\n(s3:GetObject, sqs:SendMessage)\" as PERM #d1fae5\n",[3410,7498,7499],{"class":3412,"line":3474},[3410,7500,3483],{},[3410,7502,7503],{"class":3412,"line":3480},[3410,7504,3435],{"emptyLinePlaceholder":3434},[3410,7506,7507],{"class":3412,"line":3486},[3410,7508,7509],{},"node \"EC2 Instance\" #fef3c7 {\n",[3410,7511,7512],{"class":3412,"line":3491},[3410,7513,7514],{},"    rectangle \"Instance Profile\\n(обгортка для Role)\" as PROFILE #fde68a\n",[3410,7516,7517],{"class":3412,"line":3497},[3410,7518,7519],{},"    rectangle \"AWS SDK for .NET\\nDefaultAWSCredentials\" as SDK #e0e7ff\n",[3410,7521,7522],{"class":3412,"line":3503},[3410,7523,3483],{},[3410,7525,7526],{"class":3412,"line":3508},[3410,7527,3435],{"emptyLinePlaceholder":3434},[3410,7529,7530],{"class":3412,"line":3513},[3410,7531,7532],{},"database \"IMDS 169.254.169.254\\n\u002Fiam\u002Fsecurity-credentials\u002F\" as IMDS #f3f4f6\n",[3410,7534,7535],{"class":3412,"line":3519},[3410,7536,7537],{},"storage \"S3 \u002F SQS \u002F DynamoDB...\" as SVC #e0e7ff\n",[3410,7539,7540],{"class":3412,"line":3524},[3410,7541,3435],{"emptyLinePlaceholder":3434},[3410,7543,7544],{"class":3412,"line":3530},[3410,7545,7546],{},"DEV -right-> ROLE : створює\n",[3410,7548,7549],{"class":3412,"line":3536},[3410,7550,7551],{},"ROLE -down-> TRUST\n",[3410,7553,7554],{"class":3412,"line":3542},[3410,7555,7556],{},"ROLE -down-> PERM\n",[3410,7558,7559],{"class":3412,"line":3891},[3410,7560,7561],{},"DEV -right-> PROFILE : attach до instance\n",[3410,7563,7564],{"class":3412,"line":3897},[3410,7565,7566],{},"SDK -down-> IMDS : запит credentials\n",[3410,7568,7569],{"class":3412,"line":3903},[3410,7570,7571],{},"IMDS -up-> SDK : temp credentials\\n(1 год TTL · авто-ротація)\n",[3410,7573,7574],{"class":3412,"line":3909},[3410,7575,7576],{},"SDK -right-> SVC : підписаний AWS request\n",[3410,7578,7579],{"class":3412,"line":3915},[3410,7580,3545],{},[3584,7582,7584],{"id":7583},"як-це-працює-технічно","Як це працює технічно",[7586,7587,7588,7616,7623,7632],"ol",{},[3622,7589,7590,7591,7594,7595],{},"Адміністратор створює ",[3366,7592,7593],{},"IAM Role"," з двома складовими:\n",[3619,7596,7597,7606],{},[3622,7598,7599,7602,7603],{},[3366,7600,7601],{},"Trust Policy"," — хто може «взяти» (assume) цю роль. Для EC2: ",[3407,7604,7605],{},"\"Service\": \"ec2.amazonaws.com\"",[3622,7607,7608,7611,7612,7615],{},[3366,7609,7610],{},"Permission Policy"," — що ця роль може робити (наприклад ",[3407,7613,7614],{},"s3:GetObject"," на конкретний bucket)",[3622,7617,7618,7619,7622],{},"Роль прикріплюється до EC2 через ",[3366,7620,7621],{},"Instance Profile"," (контейнер для ролі — створюється автоматично через Console)",[3622,7624,7625,7628,7629],{},[3366,7626,7627],{},"AWS STS (Security Token Service)"," видає тимчасові credentials (AccessKeyId + SecretAccessKey + SessionToken) з TTL ~1 година, розміщуючи їх у IMDS за адресою ",[3407,7630,7631],{},"\u002Flatest\u002Fmeta-data\u002Fiam\u002Fsecurity-credentials\u002F{role-name}",[3622,7633,7634,7637],{},[3366,7635,7636],{},"AWS SDK for .NET"," автоматично запитує ці credentials з IMDS і оновлює їх до закінчення TTL — без жодного коду з вашого боку",[3584,7639,7641],{"id":7640},"приклад-надати-ec2-доступ-до-s3","Приклад: надати EC2 доступ до S3",[7643,7644,7645,7692],"tabs",{},[7646,7647,7649],"tabs-item",{"label":7648},"AWS Console",[7586,7650,7651,7656,7663,7669,7678,7684],{},[3622,7652,7653],{},[3366,7654,7655],{},"IAM → Roles → Create role",[3622,7657,7658,7659,7662],{},"Trusted entity: ",[3366,7660,7661],{},"AWS service → EC2"," → Next",[3622,7664,7665,7666,7662],{},"Permissions: знайдіть і оберіть ",[3407,7667,7668],{},"AmazonS3ReadOnlyAccess",[3622,7670,7671,7672,3994,7675],{},"Role name: ",[3407,7673,7674],{},"ec2-s3-readonly-role",[3366,7676,7677],{},"Create role",[3622,7679,7680,7681],{},"EC2 → Instances → ваш instance → ",[3366,7682,7683],{},"Actions → Security → Modify IAM role",[3622,7685,7686,7687,3994,7689],{},"Оберіть ",[3407,7688,7674],{},[3366,7690,7691],{},"Update IAM role",[7646,7693,7695],{"label":7694},"AWS CLI",[3400,7696,7698],{"className":4390,"code":7697,"language":4392,"meta":3405,"style":3405},"# 1. Створити роль з Trust Policy для EC2\naws iam create-role \\\n    --role-name ec2-s3-readonly-role \\\n    --assume-role-policy-document '{\n        \"Version\": \"2012-10-17\",\n        \"Statement\": [{\n            \"Effect\": \"Allow\",\n            \"Principal\": {\"Service\": \"ec2.amazonaws.com\"},\n            \"Action\": \"sts:AssumeRole\"\n        }]\n    }'\n\n# 2. Прикріпити managed policy (S3 read-only)\naws iam attach-role-policy \\\n    --role-name ec2-s3-readonly-role \\\n    --policy-arn arn:aws:iam::aws:policy\u002FAmazonS3ReadOnlyAccess\n\n# 3. Створити Instance Profile та додати роль\naws iam create-instance-profile \\\n    --instance-profile-name ec2-s3-readonly-profile\n\naws iam add-role-to-instance-profile \\\n    --instance-profile-name ec2-s3-readonly-profile \\\n    --role-name ec2-s3-readonly-role\n\n# 4. Прикріпити до запущеного instance\naws ec2 associate-iam-instance-profile \\\n    --instance-id $INSTANCE_ID \\\n    --iam-instance-profile Name=ec2-s3-readonly-profile \\\n    --region eu-central-1\n",[3407,7699,7700,7705,7717,7727,7735,7740,7745,7750,7755,7760,7764,7769,7773,7778,7789,7797,7805,7809,7814,7825,7833,7837,7848,7857,7864,7868,7873,7884,7894,7904],{"__ignoreMap":3405},[3410,7701,7702],{"class":3412,"line":3413},[3410,7703,7704],{"class":4462},"# 1. Створити роль з Trust Policy для EC2\n",[3410,7706,7707,7709,7712,7715],{"class":3412,"line":3419},[3410,7708,4400],{"class":4399},[3410,7710,7711],{"class":4403}," iam",[3410,7713,7714],{"class":4403}," create-role",[3410,7716,4411],{"class":4410},[3410,7718,7719,7722,7725],{"class":3412,"line":3425},[3410,7720,7721],{"class":4416},"    --role-name",[3410,7723,7724],{"class":4403}," ec2-s3-readonly-role",[3410,7726,4411],{"class":4410},[3410,7728,7729,7732],{"class":3412,"line":3431},[3410,7730,7731],{"class":4416},"    --assume-role-policy-document",[3410,7733,7734],{"class":4403}," '{\n",[3410,7736,7737],{"class":3412,"line":3438},[3410,7738,7739],{"class":4403},"        \"Version\": \"2012-10-17\",\n",[3410,7741,7742],{"class":3412,"line":3444},[3410,7743,7744],{"class":4403},"        \"Statement\": [{\n",[3410,7746,7747],{"class":3412,"line":3450},[3410,7748,7749],{"class":4403},"            \"Effect\": \"Allow\",\n",[3410,7751,7752],{"class":3412,"line":3456},[3410,7753,7754],{"class":4403},"            \"Principal\": {\"Service\": \"ec2.amazonaws.com\"},\n",[3410,7756,7757],{"class":3412,"line":3462},[3410,7758,7759],{"class":4403},"            \"Action\": \"sts:AssumeRole\"\n",[3410,7761,7762],{"class":3412,"line":3468},[3410,7763,6389],{"class":4403},[3410,7765,7766],{"class":3412,"line":3474},[3410,7767,7768],{"class":4403},"    }'\n",[3410,7770,7771],{"class":3412,"line":3480},[3410,7772,3435],{"emptyLinePlaceholder":3434},[3410,7774,7775],{"class":3412,"line":3486},[3410,7776,7777],{"class":4462},"# 2. Прикріпити managed policy (S3 read-only)\n",[3410,7779,7780,7782,7784,7787],{"class":3412,"line":3491},[3410,7781,4400],{"class":4399},[3410,7783,7711],{"class":4403},[3410,7785,7786],{"class":4403}," attach-role-policy",[3410,7788,4411],{"class":4410},[3410,7790,7791,7793,7795],{"class":3412,"line":3497},[3410,7792,7721],{"class":4416},[3410,7794,7724],{"class":4403},[3410,7796,4411],{"class":4410},[3410,7798,7799,7802],{"class":3412,"line":3503},[3410,7800,7801],{"class":4416},"    --policy-arn",[3410,7803,7804],{"class":4403}," arn:aws:iam::aws:policy\u002FAmazonS3ReadOnlyAccess\n",[3410,7806,7807],{"class":3412,"line":3508},[3410,7808,3435],{"emptyLinePlaceholder":3434},[3410,7810,7811],{"class":3412,"line":3513},[3410,7812,7813],{"class":4462},"# 3. Створити Instance Profile та додати роль\n",[3410,7815,7816,7818,7820,7823],{"class":3412,"line":3519},[3410,7817,4400],{"class":4399},[3410,7819,7711],{"class":4403},[3410,7821,7822],{"class":4403}," create-instance-profile",[3410,7824,4411],{"class":4410},[3410,7826,7827,7830],{"class":3412,"line":3524},[3410,7828,7829],{"class":4416},"    --instance-profile-name",[3410,7831,7832],{"class":4403}," ec2-s3-readonly-profile\n",[3410,7834,7835],{"class":3412,"line":3530},[3410,7836,3435],{"emptyLinePlaceholder":3434},[3410,7838,7839,7841,7843,7846],{"class":3412,"line":3536},[3410,7840,4400],{"class":4399},[3410,7842,7711],{"class":4403},[3410,7844,7845],{"class":4403}," add-role-to-instance-profile",[3410,7847,4411],{"class":4410},[3410,7849,7850,7852,7855],{"class":3412,"line":3542},[3410,7851,7829],{"class":4416},[3410,7853,7854],{"class":4403}," ec2-s3-readonly-profile",[3410,7856,4411],{"class":4410},[3410,7858,7859,7861],{"class":3412,"line":3891},[3410,7860,7721],{"class":4416},[3410,7862,7863],{"class":4403}," ec2-s3-readonly-role\n",[3410,7865,7866],{"class":3412,"line":3897},[3410,7867,3435],{"emptyLinePlaceholder":3434},[3410,7869,7870],{"class":3412,"line":3903},[3410,7871,7872],{"class":4462},"# 4. Прикріпити до запущеного instance\n",[3410,7874,7875,7877,7879,7882],{"class":3412,"line":3909},[3410,7876,4400],{"class":4399},[3410,7878,4404],{"class":4403},[3410,7880,7881],{"class":4403}," associate-iam-instance-profile",[3410,7883,4411],{"class":4410},[3410,7885,7886,7889,7892],{"class":3412,"line":3915},[3410,7887,7888],{"class":4416},"    --instance-id",[3410,7890,7891],{"class":6538}," $INSTANCE_ID",[3410,7893,4411],{"class":4410},[3410,7895,7896,7899,7902],{"class":3412,"line":3921},[3410,7897,7898],{"class":4416},"    --iam-instance-profile",[3410,7900,7901],{"class":4403}," Name=ec2-s3-readonly-profile",[3410,7903,4411],{"class":4410},[3410,7905,7906,7908],{"class":3412,"line":5681},[3410,7907,6606],{"class":4416},[3410,7909,4457],{"class":4403},[3584,7911,7913],{"id":7912},"використання-у-net-коді","Використання у .NET коді",[3348,7915,7916],{},"З прикріпленою IAM Role AWS SDK for .NET автоматично знаходить credentials — жодного конфігурування не потрібно:",[3400,7918,7922],{"className":7919,"code":7920,"language":7921,"meta":3405,"style":3405},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F Нічого конфігурувати! SDK сам знайде credentials через ланцюжок провайдерів:\n\u002F\u002F 1. Змінні середовища → 2. ~\u002F.aws\u002Fcredentials → 3. IAM Role через IMDS ← спрацює на EC2\nvar s3Client = new AmazonS3Client(RegionEndpoint.EUCentral1);\n\n\u002F\u002F Читання конфігу зі S3 замість хардкоду у репозиторії\nvar response = await s3Client.GetObjectAsync(\"my-config-bucket\", \"appsettings.Production.json\");\nusing var reader = new StreamReader(response.ResponseStream);\nvar configJson = await reader.ReadToEndAsync();\n","csharp",[3407,7923,7924,7929,7934,7965,7969,7974,8005,8036],{"__ignoreMap":3405},[3410,7925,7926],{"class":3412,"line":3413},[3410,7927,7928],{"class":4462},"\u002F\u002F Нічого конфігурувати! SDK сам знайде credentials через ланцюжок провайдерів:\n",[3410,7930,7931],{"class":3412,"line":3419},[3410,7932,7933],{"class":4462},"\u002F\u002F 1. Змінні середовища → 2. ~\u002F.aws\u002Fcredentials → 3. IAM Role через IMDS ← спрацює на EC2\n",[3410,7935,7936,7939,7942,7944,7947,7951,7954,7957,7959,7962],{"class":3412,"line":3425},[3410,7937,7938],{"class":4416},"var",[3410,7940,7941],{"class":6538}," s3Client",[3410,7943,6998],{"class":6300},[3410,7945,7946],{"class":4416},"new",[3410,7948,7950],{"class":7949},"sN1BT"," AmazonS3Client",[3410,7952,7953],{"class":6300},"(",[3410,7955,7956],{"class":6538},"RegionEndpoint",[3410,7958,3373],{"class":6300},[3410,7960,7961],{"class":6538},"EUCentral1",[3410,7963,7964],{"class":6300},");\n",[3410,7966,7967],{"class":3412,"line":3431},[3410,7968,3435],{"emptyLinePlaceholder":3434},[3410,7970,7971],{"class":3412,"line":3438},[3410,7972,7973],{"class":4462},"\u002F\u002F Читання конфігу зі S3 замість хардкоду у репозиторії\n",[3410,7975,7976,7978,7981,7983,7986,7988,7990,7993,7995,7998,8000,8003],{"class":3412,"line":3444},[3410,7977,7938],{"class":4416},[3410,7979,7980],{"class":6538}," response",[3410,7982,6998],{"class":6300},[3410,7984,7985],{"class":4416},"await",[3410,7987,7941],{"class":6538},[3410,7989,3373],{"class":6300},[3410,7991,7992],{"class":4399},"GetObjectAsync",[3410,7994,7953],{"class":6300},[3410,7996,7997],{"class":4403},"\"my-config-bucket\"",[3410,7999,3599],{"class":6300},[3410,8001,8002],{"class":4403},"\"appsettings.Production.json\"",[3410,8004,7964],{"class":6300},[3410,8006,8007,8011,8014,8017,8019,8021,8024,8026,8029,8031,8034],{"class":3412,"line":3450},[3410,8008,8010],{"class":8009},"s8xlr","using",[3410,8012,8013],{"class":4416}," var",[3410,8015,8016],{"class":6538}," reader",[3410,8018,6998],{"class":6300},[3410,8020,7946],{"class":4416},[3410,8022,8023],{"class":7949}," StreamReader",[3410,8025,7953],{"class":6300},[3410,8027,8028],{"class":6538},"response",[3410,8030,3373],{"class":6300},[3410,8032,8033],{"class":6538},"ResponseStream",[3410,8035,7964],{"class":6300},[3410,8037,8038,8040,8043,8045,8047,8049,8051,8054],{"class":3412,"line":3456},[3410,8039,7938],{"class":4416},[3410,8041,8042],{"class":6538}," configJson",[3410,8044,6998],{"class":6300},[3410,8046,7985],{"class":4416},[3410,8048,8016],{"class":6538},[3410,8050,3373],{"class":6300},[3410,8052,8053],{"class":4399},"ReadToEndAsync",[3410,8055,8056],{"class":6300},"();\n",[3348,8058,8059],{},"SDK автоматично оновлює тимчасові credentials до закінчення TTL — ваш код не зупиняється при ротації.",[4147,8061,8062,8065,8066,8069,8070,3706,8072,8075,8076,8079],{},[3366,8063,8064],{},"Принцип мінімальних привілеїв (Least Privilege):"," надавайте IAM Role лише необхідні дозволи. Якщо API лише читає один S3 bucket — не давайте ",[3407,8067,8068],{},"AmazonS3FullAccess",". Натомість — власна policy з ",[3407,8071,7614],{},[3407,8073,8074],{},"s3:ListBucket"," на ",[3407,8077,8078],{},"arn:aws:s3:::my-bucket\u002F*",". Це мінімізує збитки у разі компрометації instance.",[3547,8081],{},[3348,8083,8084],{},[3351,8085],{"alt":8086,"className":8087,"src":8088},"EC2 Instance Connect browser-based SSH connection without key pairs",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F10.png",[3358,8090,8092],{"id":8091},"ec2-instance-connect-підключення-без-ssh-ключів","EC2 Instance Connect — підключення без SSH ключів",[3348,8094,8095,8098,8099,8102],{},[3366,8096,8097],{},"EC2 Instance Connect"," — це сервіс AWS, який дозволяє підключитись до EC2 через браузер або CLI ",[3366,8100,8101],{},"без збереження SSH приватних ключів локально",". AWS тимчасово завантажує ваш публічний ключ у instance на 60 секунд.",[3348,8104,8105,8108,8109,8112,8113,3994,8115,8117],{},[3366,8106,8107],{},"Через Console:"," EC2 → Instances → оберіть instance → ",[3366,8110,8111],{},"Connect"," → вкладка ",[3366,8114,8097],{},[3366,8116,8111],{},". Відкриється термінал прямо у браузері.",[3348,8119,8120],{},[3366,8121,8122],{},"Через CLI:",[4876,8124,8126,8135,8139,8146,8149,8158],{"title":8125},"EC2 Instance Connect CLI — підключення без .pem ключа",[4880,8127,8129,3572,8132],{"className":8128},[3412],[3410,8130,4887],{"className":8131},[4886],[3366,8133,8134],{},"pip install ec2instanceconnectcli",[4880,8136,8138],{"className":8137},[3412],"Collecting ec2instanceconnectcli",[4880,8140,8142],{"className":8141},[3412],[3410,8143,8145],{"className":8144},[4926],"Successfully installed ec2instanceconnectcli-1.0.3",[4880,8147],{"className":8148},[3412],[4880,8150,8152,3572,8155],{"className":8151},[3412],[3410,8153,4887],{"className":8154},[4886],[3366,8156,8157],{},"mssh ec2-user@i-1234567890abcdef0 --region eu-central-1",[4880,8159,8161],{"className":8160},[3412],[3410,8162,8164],{"className":8163},[4926],"ec2-user@ip-172-31-10-25:~$",[4147,8166,8167],{},"EC2 Instance Connect не вимагає відкритого порту 22 для всього світу. Достатньо дозволити трафік із IP-діапазону AWS для EC2 Instance Connect. AWS публікує ці діапазони.",[3547,8169],{},[3358,8171,8173],{"id":8172},"ssh-key-pair-та-pem-аутентифікація-без-пароля","SSH Key Pair та PEM — аутентифікація без пароля",[3348,8175,8176,8177,8180],{},"Коли ви підключаєтесь до EC2 через SSH — AWS не просить ввести пароль. Замість цього використовується ",[3366,8178,8179],{},"асиметрична криптографія",": пара математично пов'язаних ключів. Для студентів, які звикли до логін\u002Fпароль — це принципово інший підхід, і важливо зрозуміти, як він працює.",[3584,8182,8184],{"id":8183},"асиметрична-криптографія-дві-половини-одного-ключа","Асиметрична криптографія: дві половини одного ключа",[3348,8186,8187],{},"Звичайна (симетрична) криптографія: один ключ, яким і шифрують, і розшифровують. Якщо цей ключ вкрасти — система компрометована.",[3348,8189,8190,8193,8194,8197],{},[3366,8191,8192],{},"Асиметрична криптографія"," (Public-Key Cryptography) використовує ",[3366,8195,8196],{},"дві математично пов'язані частини",":",[3725,8199,8200,8205],{},[3728,8201,8204],{"icon":8202,"title":8203},"ph:lock-open-duotone","Публічний ключ (Public Key)","Можна роздавати будь-кому — розміщувати на серверах, публікувати у профілі GitHub. Компрометація публічного ключа нічого не дає зловмиснику. Сервер зберігає публічний ключ та перевіряє за ним підпис клієнта.",[3728,8206,8209,8210,8213],{"icon":8207,"title":8208},"ph:key-duotone","Приватний ключ (Private Key)","Зберігається ",[3366,8211,8212],{},"лише у вас"," — ніколи не передається нікуди. Це ваш цифровий підпис. Клієнт (SSH) підписує запит приватним ключем. Якщо підпис верифікується публічним ключем — автентифікація пройшла.",[3348,8215,8216,8219,8220,8223],{},[3366,8217,8218],{},"Математична властивість:"," пара генерується так, що з публічного ключа ",[3366,8221,8222],{},"практично неможливо"," відновити приватний — навіть за необмеженого часу та потужності комп'ютерів сучасної ери. Алгоритм RSA базується на задачі факторизації великих чисел (1024–4096 біт), Ed25519 — на математиці еліптичних кривих.",[3397,8225,8226],{},[3400,8227,8232],{"className":8228,"code":8230,"language":8231},[8229],"language-text","@startuml\nskinparam backgroundColor #1e1e2e\nskinparam defaultFontColor #cdd6f4\nskinparam ArrowColor #89b4fa\nskinparam SequenceLifeLineBorderColor #585b70\nskinparam SequenceParticipantBorderColor #585b70\nskinparam SequenceParticipantBackgroundColor #313244\nskinparam SequenceParticipantFontColor #cdd6f4\nskinparam NoteBackgroundColor #45475a\nskinparam NoteBorderColor #585b70\nskinparam NoteFontColor #cdd6f4\n\nparticipant \"SSH Client\\n(ваш комп'ютер)\" as C\nparticipant \"EC2 Instance\\n(сервер)\" as S\n\nnote over C: Має приватний ключ\\n(ec2-lab-key.pem)\nnote over S: Має публічний ключ\\n(у ~\u002F.ssh\u002Fauthorized_keys)\n\nC -> S: TCP з'єднання на порт 22\nS -> C: Challenge (випадковий рядок)\nnote over C: Підписує challenge\\nприватним ключем\nC -> S: Підпис (Signature)\nnote over S: Верифікує підпис\\nпублічним ключем\nS -> C: Authentication OK\nnote over C,S: Зашифрований\\nSSH-сеанс встановлено\n@enduml\n","text",[3407,8233,8230],{"__ignoreMap":3405},[3584,8235,8237],{"id":8236},"що-таке-pem-файл","Що таке .pem файл?",[3348,8239,8240,8243],{},[3366,8241,8242],{},"PEM (Privacy Enhanced Mail)"," — текстовий формат для зберігання криптографічних об'єктів: ключів, сертифікатів. Назва застаріла (формат виник в email-стандартах 1990-х), але використовується досі.",[3348,8245,8246,8247,8250],{},"PEM-файл — це ",[3366,8248,8249],{},"Base64-закодований"," двійковий об'єкт між текстовими маркерами:",[3400,8252,8255],{"className":8253,"code":8254,"language":8231},[8229],"-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0Z3VS5JJcds3xHn\u002FygWep4AyHgMZJmANwNdGv4VWBWCA\n...кілька сотень символів Base64...\ntQJ5LMzKvOkzjJHJHAIDAQABAoIBAC5RgZ+hBx7xHNaMpPgwGALBSa9BFKQR\n-----END RSA PRIVATE KEY-----\n",[3407,8256,8254],{"__ignoreMap":3405},[3348,8258,8259,8260,8263],{},"Файл ",[3407,8261,8262],{},".pem"," — це лише контейнер. Він може містити:",[3619,8265,8266,8272,8278],{},[3622,8267,8268,8271],{},[3366,8269,8270],{},"RSA приватний ключ"," (що й відбувається при створенні EC2 Key Pair)",[3622,8273,8274,8277],{},[3366,8275,8276],{},"Сертифікат X.509"," (HTTPS-сертифікат вашого сайту — теж у PEM-форматі)",[3622,8279,8280,8283],{},[3366,8281,8282],{},"Ланцюжок сертифікатів"," (Certificate Authority chain)",[3712,8285,8286,3599,8288,3599,8291,8294,8295,8298],{},[3407,8287,8262],{},[3407,8289,8290],{},".key",[3407,8292,8293],{},".crt"," — часто лише різні розширення для одного й того ж Base64-формату. Відрізнити можна лише за ",[3407,8296,8297],{},"-----BEGIN ...-----"," маркером всередині.",[3584,8300,8302],{"id":8301},"як-ec2-key-pair-працює-від-генерації-до-входу","Як EC2 Key Pair працює: від генерації до входу",[3348,8304,8305,8306,8309],{},"При натисканні ",[3366,8307,8308],{},"Create key pair"," у AWS Console відбувається наступне:",[3400,8311,8314],{"className":8312,"code":8313,"language":8231},[8229],"1. AWS генерує пару RSA-2048 або Ed25519 ключів на своїх серверах\n2. Публічний ключ → зберігається в AWS, записується в EC2 instance при запуску\n   (у файл \u002Fhome\u002Fubuntu\u002F.ssh\u002Fauthorized_keys)\n3. Приватний ключ → завантажується вам у вигляді .pem файлу і ВИДАЛЯЄТЬСЯ з AWS\n4. AWS більше не має вашого приватного ключа — лише ви\n",[3407,8315,8313],{"__ignoreMap":3405},[3348,8317,8318,8324],{},[3366,8319,8320,8321,8323],{},"Тому якщо ви втратили ",[3407,8322,8262],{}," файл — підключитись до цього instance вже неможливо"," (лише через EC2 Instance Connect або монтування EBS-тому до іншого instance).",[3584,8326,8328],{"id":8327},"порівняння-пароль-vs-ключ","Порівняння: пароль vs ключ",[4049,8330,8331,8344],{},[4052,8332,8333],{},[4055,8334,8335,8338,8341],{},[4058,8336,8337],{},"Критерій",[4058,8339,8340],{},"Пароль",[4058,8342,8343],{},"SSH Key Pair",[4075,8345,8346,8363,8376,8389,8402,8421],{},[4055,8347,8348,8353,8356],{},[4080,8349,8350],{},[3366,8351,8352],{},"Передача по мережі",[4080,8354,8355],{},"Пароль\u002Fхеш передається",[4080,8357,8358,8359,8362],{},"Приватний ключ ",[3366,8360,8361],{},"ніколи"," не передається",[4055,8364,8365,8370,8373],{},[4080,8366,8367],{},[3366,8368,8369],{},"Brute-force",[4080,8371,8372],{},"Вразливий (можна перебрати)",[4080,8374,8375],{},"Неможливий (2048-бітний ключ)",[4055,8377,8378,8383,8386],{},[4080,8379,8380],{},[3366,8381,8382],{},"Фішинг",[4080,8384,8385],{},"Можна обманом отримати",[4080,8387,8388],{},"Не допоможе без файлу",[4055,8390,8391,8396,8399],{},[4080,8392,8393],{},[3366,8394,8395],{},"Зручність",[4080,8397,8398],{},"Потрібно пам'ятати",[4080,8400,8401],{},"Потрібен доступ до файлу",[4055,8403,8404,8409,8415],{},[4080,8405,8406],{},[3366,8407,8408],{},"Зберігання на сервері",[4080,8410,8411,8412],{},"Хеш паролю у ",[3407,8413,8414],{},"\u002Fetc\u002Fshadow",[4080,8416,8417,8418],{},"Публічний ключ у ",[3407,8419,8420],{},"authorized_keys",[4055,8422,8423,8428,8431],{},[4080,8424,8425],{},[3366,8426,8427],{},"Відкликання",[4080,8429,8430],{},"Змінити пароль",[4080,8432,8433,8434],{},"Видалити рядок з ",[3407,8435,8420],{},[3584,8437,8439],{"id":8438},"формати-ключів-pem-vs-ppk","Формати ключів: .pem vs .ppk",[3348,8441,8442,8445,8446,8448],{},[3366,8443,8444],{},"Mac \u002F Linux"," — SSH вбудований у систему і підтримує ",[3407,8447,8262],{}," напряму:",[3400,8450,8452],{"className":4390,"code":8451,"language":4392,"meta":3405,"style":3405},"ssh -i ~\u002F.ssh\u002Fec2-lab-key.pem ubuntu@1.2.3.4\n",[3407,8453,8454],{"__ignoreMap":3405},[3410,8455,8456,8459,8462,8465],{"class":3412,"line":3413},[3410,8457,8458],{"class":4399},"ssh",[3410,8460,8461],{"class":4416}," -i",[3410,8463,8464],{"class":4403}," ~\u002F.ssh\u002Fec2-lab-key.pem",[3410,8466,8467],{"class":4403}," ubuntu@1.2.3.4\n",[3348,8469,8470,8473,8474,8477,8478,8481,8482,8484,8485,8487,8488,3373],{},[3366,8471,8472],{},"Windows"," — старіші версії використовують ",[3366,8475,8476],{},"PuTTY",", який має власний формат ",[3407,8479,8480],{},".ppk",". При створенні ключа в AWS Console для Windows потрібно обирати ",[3407,8483,8480],{},". Якщо у вас ",[3407,8486,8262],{},", конвертуйте через ",[3366,8489,8490],{},"PuTTYgen",[4147,8492,8493,8496,8497,8500,8501,8503],{},[3366,8494,8495],{},"Windows 10\u002F11"," мають вбудований OpenSSH (з 2018 року). У PowerShell або CMD команда ",[3407,8498,8499],{},"ssh -i"," працює так само, як на Mac\u002FLinux. ",[3407,8502,8480],{}," потрібен лише якщо ви використовуєте PuTTY свідомо.",[3584,8505,8507],{"id":8506},"безпека-chmod-400-та-зберігання-ключа","Безпека: chmod 400 та зберігання ключа",[3348,8509,8510,8511,8514],{},"Коли SSH-клієнт бачить, що файл ключа доступний не лише власнику — він ",[3366,8512,8513],{},"відмовляється його використовувати"," і видає помилку:",[3400,8516,8519],{"className":8517,"code":8518,"language":8231},[8229],"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\nPermissions 0644 for 'ec2-lab-key.pem' are too open.\nIt is required that your private key files are NOT accessible by others.\nThis private key will be ignored.\n",[3407,8520,8518],{"__ignoreMap":3405},[3348,8522,8523,8524,8527,8528,8531,8532,8535],{},"Команда ",[3407,8525,8526],{},"chmod 400 ~\u002F.ssh\u002Fec2-lab-key.pem"," встановлює права ",[3407,8529,8530],{},"-r--------",": читання дозволено ",[3366,8533,8534],{},"лише власнику",", нікому більше.",[3400,8537,8540],{"className":8538,"code":8539,"language":8231},[8229],"400 = 4 (read) + 0 (---) + 0 (---) = власник може читати, група і всі інші — нічого\n",[3407,8541,8539],{"__ignoreMap":3405},[3348,8543,8544],{},[3366,8545,8546],{},"Де зберігати .pem файл:",[3619,8548,8549,8556,8559,8562,8565],{},[3622,8550,8551,8552,8555],{},"✅ ",[3407,8553,8554],{},"~\u002F.ssh\u002F"," — стандартна директорія для SSH-ключів",[3622,8557,8558],{},"✅ Менеджер паролів з можливістю зберігання файлів (1Password, Bitwarden)",[3622,8560,8561],{},"✅ Зашифрований архів у хмарному сховищі",[3622,8563,8564],{},"❌ Робочий стіл, папка Downloads, будь-яке синхронізоване сховище без шифрування",[3622,8566,8567],{},"❌ Git-репозиторій (навіть приватний)",[4003,8569,8570,8571,8573,8574,8577],{},"Якщо ви випадково закомітили ",[3407,8572,8262],{}," файл у Git — ",[3366,8575,8576],{},"негайно"," видаліть Key Pair в AWS Console і створіть новий. Навіть якщо репозиторій приватний — він міг бути вже прочитаний до видалення.",[3547,8579],{},[3348,8581,8582],{},[3351,8583],{"alt":8584,"className":8585,"src":8586},"Linux EC2 deployment workflow dotnet publish SCP systemd service lifecycle",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F11.png",[3358,8588,8590],{"id":8589},"практичний-приклад-net-10-api-на-linux-ubuntu-від-а-до-я","Практичний приклад: .NET 10 API на Linux (Ubuntu) від А до Я",[3348,8592,8593],{},"У цьому прикладі ми запустимо EC2 instance з Ubuntu, встановимо .NET 10, задеплоїмо ASP.NET Core API і налаштуємо його як системний сервіс, що автоматично стартує при перезапуску сервера.",[3584,8595,8597],{"id":8596},"крок-1-запуск-ec2-instance","Крок 1: Запуск EC2 instance",[7643,8599,8600,8772],{},[7646,8601,8602],{"label":7648},[7586,8603,8604,8617,8625,8650,8661,8707,8761,8767],{},[3622,8605,8606,8607,8610,8611,3994,8614],{},"Відкрийте ",[3366,8608,8609],{},"EC2"," у AWS Console → ",[3366,8612,8613],{},"Instances",[3366,8615,8616],{},"Launch instances",[3622,8618,8619,3572,8622],{},[3366,8620,8621],{},"Name:",[3407,8623,8624],{},"dotnet-api-server",[3622,8626,8627,8630],{},[3366,8628,8629],{},"Application and OS Images (AMI):",[3619,8631,8632,8639,8644],{},[3622,8633,8634,8635,8638],{},"Натисніть ",[3366,8636,8637],{},"Ubuntu"," у Quick Start",[3622,8640,7686,8641],{},[3366,8642,8643],{},"Ubuntu Server 26.04 LTS (HVM), SSD Volume Type",[3622,8645,8646,8647],{},"Architecture: ",[3366,8648,8649],{},"64-bit (x86)",[3622,8651,8652,3572,8655,8657,8658,8660],{},[3366,8653,8654],{},"Instance type:",[3407,8656,3581],{}," (Free Tier) або ",[3407,8659,3607],{}," для реального навантаження",[3622,8662,8663,8666],{},[3366,8664,8665],{},"Key pair (login):",[3619,8667,8668,8673,8679,8685,8694,8702],{},[3622,8669,8634,8670],{},[3366,8671,8672],{},"Create new key pair",[3622,8674,8675,8676],{},"Key pair name: ",[3407,8677,8678],{},"ec2-lab-key",[3622,8680,8681,8682],{},"Key pair type: ",[3366,8683,8684],{},"RSA",[3622,8686,8687,8688,8690,8691,8693],{},"Private key file format: ",[3366,8689,8262],{}," (для Mac\u002FLinux) або ",[3366,8692,8480],{}," (для Windows з PuTTY)",[3622,8695,8634,8696,8698,8699,8701],{},[3366,8697,8308],{}," — файл ",[3407,8700,8262],{}," автоматично завантажиться",[3622,8703,8704],{},[3366,8705,8706],{},"Збережіть цей файл! Його неможливо завантажити повторно.",[3622,8708,8709,8712],{},[3366,8710,8711],{},"Network settings:",[3619,8713,8714,8719,8722,8725,8731],{},[3622,8715,8634,8716],{},[3366,8717,8718],{},"Edit",[3622,8720,8721],{},"VPC: залиште default",[3622,8723,8724],{},"Subnet: залиште default",[3622,8726,8727,8728],{},"Auto-assign public IP: ",[3366,8729,8730],{},"Enable",[3622,8732,8733,8736,8737],{},[3366,8734,8735],{},"Firewall (security groups):"," Create security group\n",[3619,8738,8739,8745,8755],{},[3622,8740,8741,8742],{},"Security group name: ",[3407,8743,8744],{},"dotnet-api-sg",[3622,8746,8747,8748,3572,8751],{},"✅ Allow SSH traffic from: ",[3366,8749,8750],{},"My IP",[8752,8753,8754],"em",{},"(AWS автоматично визначить ваш поточний IP)",[3622,8756,8757,8758],{},"✅ Allow HTTP traffic from the internet ",[8752,8759,8760],{},"(порт 80)",[3622,8762,8763,8766],{},[3366,8764,8765],{},"Configure storage:"," 20 GB gp3 (достатньо)",[3622,8768,8634,8769],{},[3366,8770,8771],{},"Launch instance",[7646,8773,8774],{"label":7694},[3400,8775,8777],{"className":4390,"code":8776,"language":4392,"meta":3405,"style":3405},"# Крок 1a: Знайдіть актуальний Ubuntu 26.04 AMI ID у вашому регіоні\nAMI_ID=$(aws ec2 describe-images \\\n    --owners 099720109477 \\\n    --filters \"Name=name,Values=ubuntu\u002Fimages\u002Fhvm-ssd-gp3\u002Fubuntu-resolute-26.04-amd64-server-*\" \\\n    --query \"sort_by(Images, &CreationDate)[-1].ImageId\" \\\n    --output text --region eu-central-1)\necho \"AMI ID: $AMI_ID\"\n\n# Крок 1b: Знайдіть ваш default VPC ID\nVPC_ID=$(aws ec2 describe-vpcs \\\n    --filters \"Name=isDefault,Values=true\" \\\n    --query \"Vpcs[0].VpcId\" --output text --region eu-central-1)\n\n# Крок 1c: Створіть Security Group\nSG_ID=$(aws ec2 create-security-group \\\n    --group-name dotnet-api-sg \\\n    --description \"Security group for .NET API\" \\\n    --vpc-id $VPC_ID \\\n    --region eu-central-1 \\\n    --query GroupId --output text)\n\n# Крок 1d: Дозвольте SSH лише з вашого поточного IP\nMY_IP=$(curl -s https:\u002F\u002Fcheckip.amazonaws.com)\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID \\\n    --protocol tcp --port 22 \\\n    --cidr \"${MY_IP}\u002F32\" --region eu-central-1\n\n# Крок 1e: Дозвольте HTTP з будь-якого IP\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID \\\n    --protocol tcp --port 80 \\\n    --cidr 0.0.0.0\u002F0 --region eu-central-1\n\n# Крок 1f: Дозвольте port 5000 (для тестування .NET без reverse proxy)\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID \\\n    --protocol tcp --port 5000 \\\n    --cidr 0.0.0.0\u002F0 --region eu-central-1\n\n# Крок 1g: Створіть SSH key pair\naws ec2 create-key-pair \\\n    --key-name ec2-lab-key \\\n    --region eu-central-1 \\\n    --query \"KeyMaterial\" --output text > ~\u002F.ssh\u002Fec2-lab-key.pem\n\n# Встановіть правильні права на файл ключа (обов'язково!)\nchmod 400 ~\u002F.ssh\u002Fec2-lab-key.pem\n\n# Крок 1h: Запустіть instance\nINSTANCE_ID=$(aws ec2 run-instances \\\n    --image-id $AMI_ID \\\n    --instance-type t3.micro \\\n    --key-name ec2-lab-key \\\n    --security-group-ids $SG_ID \\\n    --region eu-central-1 \\\n    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=dotnet-api-server}]' \\\n    --query \"Instances[0].InstanceId\" --output text)\n\necho \"Instance ID: $INSTANCE_ID\"\n",[3407,8778,8779,8784,8799,8807,8815,8823,8836,8849,8853,8858,8874,8883,8901,8905,8910,8926,8936,8946,8956,8964,8977,8981,8986,9002,9013,9023,9039,9056,9060,9065,9075,9083,9095,9107,9112,9118,9129,9138,9152,9163,9168,9174,9186,9197,9206,9223,9228,9234,9246,9251,9257,9274,9285,9296,9305,9315,9324,9335,9349,9354],{"__ignoreMap":3405},[3410,8780,8781],{"class":3412,"line":3413},[3410,8782,8783],{"class":4462},"# Крок 1a: Знайдіть актуальний Ubuntu 26.04 AMI ID у вашому регіоні\n",[3410,8785,8786,8789,8791,8793,8795,8797],{"class":3412,"line":3419},[3410,8787,8788],{"class":6538},"AMI_ID",[3410,8790,7352],{"class":6300},[3410,8792,4400],{"class":4399},[3410,8794,4404],{"class":4403},[3410,8796,4407],{"class":4403},[3410,8798,4411],{"class":4410},[3410,8800,8801,8803,8805],{"class":3412,"line":3425},[3410,8802,4417],{"class":4416},[3410,8804,4421],{"class":4420},[3410,8806,4411],{"class":4410},[3410,8808,8809,8811,8813],{"class":3412,"line":3431},[3410,8810,4428],{"class":4416},[3410,8812,4431],{"class":4403},[3410,8814,4411],{"class":4410},[3410,8816,8817,8819,8821],{"class":3412,"line":3438},[3410,8818,4438],{"class":4416},[3410,8820,4441],{"class":4403},[3410,8822,4411],{"class":4410},[3410,8824,8825,8827,8829,8831,8834],{"class":3412,"line":3444},[3410,8826,4448],{"class":4416},[3410,8828,4451],{"class":4403},[3410,8830,4454],{"class":4416},[3410,8832,8833],{"class":4403}," eu-central-1",[3410,8835,7378],{"class":6300},[3410,8837,8838,8840,8843,8846],{"class":3412,"line":3450},[3410,8839,6953],{"class":4399},[3410,8841,8842],{"class":4403}," \"AMI ID: ",[3410,8844,8845],{"class":6538},"$AMI_ID",[3410,8847,8848],{"class":4403},"\"\n",[3410,8850,8851],{"class":3412,"line":3456},[3410,8852,3435],{"emptyLinePlaceholder":3434},[3410,8854,8855],{"class":3412,"line":3462},[3410,8856,8857],{"class":4462},"# Крок 1b: Знайдіть ваш default VPC ID\n",[3410,8859,8860,8863,8865,8867,8869,8872],{"class":3412,"line":3468},[3410,8861,8862],{"class":6538},"VPC_ID",[3410,8864,7352],{"class":6300},[3410,8866,4400],{"class":4399},[3410,8868,4404],{"class":4403},[3410,8870,8871],{"class":4403}," describe-vpcs",[3410,8873,4411],{"class":4410},[3410,8875,8876,8878,8881],{"class":3412,"line":3474},[3410,8877,4428],{"class":4416},[3410,8879,8880],{"class":4403}," \"Name=isDefault,Values=true\"",[3410,8882,4411],{"class":4410},[3410,8884,8885,8887,8890,8893,8895,8897,8899],{"class":3412,"line":3480},[3410,8886,4438],{"class":4416},[3410,8888,8889],{"class":4403}," \"Vpcs[0].VpcId\"",[3410,8891,8892],{"class":4416}," --output",[3410,8894,4451],{"class":4403},[3410,8896,4454],{"class":4416},[3410,8898,8833],{"class":4403},[3410,8900,7378],{"class":6300},[3410,8902,8903],{"class":3412,"line":3486},[3410,8904,3435],{"emptyLinePlaceholder":3434},[3410,8906,8907],{"class":3412,"line":3491},[3410,8908,8909],{"class":4462},"# Крок 1c: Створіть Security Group\n",[3410,8911,8912,8915,8917,8919,8921,8924],{"class":3412,"line":3497},[3410,8913,8914],{"class":6538},"SG_ID",[3410,8916,7352],{"class":6300},[3410,8918,4400],{"class":4399},[3410,8920,4404],{"class":4403},[3410,8922,8923],{"class":4403}," create-security-group",[3410,8925,4411],{"class":4410},[3410,8927,8928,8931,8934],{"class":3412,"line":3503},[3410,8929,8930],{"class":4416},"    --group-name",[3410,8932,8933],{"class":4403}," dotnet-api-sg",[3410,8935,4411],{"class":4410},[3410,8937,8938,8941,8944],{"class":3412,"line":3508},[3410,8939,8940],{"class":4416},"    --description",[3410,8942,8943],{"class":4403}," \"Security group for .NET API\"",[3410,8945,4411],{"class":4410},[3410,8947,8948,8951,8954],{"class":3412,"line":3513},[3410,8949,8950],{"class":4416},"    --vpc-id",[3410,8952,8953],{"class":6538}," $VPC_ID",[3410,8955,4411],{"class":4410},[3410,8957,8958,8960,8962],{"class":3412,"line":3519},[3410,8959,6606],{"class":4416},[3410,8961,8833],{"class":4403},[3410,8963,4411],{"class":4410},[3410,8965,8966,8968,8971,8973,8975],{"class":3412,"line":3524},[3410,8967,4438],{"class":4416},[3410,8969,8970],{"class":4403}," GroupId",[3410,8972,8892],{"class":4416},[3410,8974,4451],{"class":4403},[3410,8976,7378],{"class":6300},[3410,8978,8979],{"class":3412,"line":3530},[3410,8980,3435],{"emptyLinePlaceholder":3434},[3410,8982,8983],{"class":3412,"line":3536},[3410,8984,8985],{"class":4462},"# Крок 1d: Дозвольте SSH лише з вашого поточного IP\n",[3410,8987,8988,8991,8993,8995,8997,9000],{"class":3412,"line":3542},[3410,8989,8990],{"class":6538},"MY_IP",[3410,8992,7352],{"class":6300},[3410,8994,7274],{"class":4399},[3410,8996,7325],{"class":4416},[3410,8998,8999],{"class":4403}," https:\u002F\u002Fcheckip.amazonaws.com",[3410,9001,7378],{"class":6300},[3410,9003,9004,9006,9008,9011],{"class":3412,"line":3891},[3410,9005,4400],{"class":4399},[3410,9007,4404],{"class":4403},[3410,9009,9010],{"class":4403}," authorize-security-group-ingress",[3410,9012,4411],{"class":4410},[3410,9014,9015,9018,9021],{"class":3412,"line":3897},[3410,9016,9017],{"class":4416},"    --group-id",[3410,9019,9020],{"class":6538}," $SG_ID",[3410,9022,4411],{"class":4410},[3410,9024,9025,9028,9031,9034,9037],{"class":3412,"line":3903},[3410,9026,9027],{"class":4416},"    --protocol",[3410,9029,9030],{"class":4403}," tcp",[3410,9032,9033],{"class":4416}," --port",[3410,9035,9036],{"class":4420}," 22",[3410,9038,4411],{"class":4410},[3410,9040,9041,9044,9047,9049,9052,9054],{"class":3412,"line":3909},[3410,9042,9043],{"class":4416},"    --cidr",[3410,9045,9046],{"class":4403}," \"${",[3410,9048,8990],{"class":6538},[3410,9050,9051],{"class":4403},"}\u002F32\"",[3410,9053,4454],{"class":4416},[3410,9055,4457],{"class":4403},[3410,9057,9058],{"class":3412,"line":3915},[3410,9059,3435],{"emptyLinePlaceholder":3434},[3410,9061,9062],{"class":3412,"line":3921},[3410,9063,9064],{"class":4462},"# Крок 1e: Дозвольте HTTP з будь-якого IP\n",[3410,9066,9067,9069,9071,9073],{"class":3412,"line":5681},[3410,9068,4400],{"class":4399},[3410,9070,4404],{"class":4403},[3410,9072,9010],{"class":4403},[3410,9074,4411],{"class":4410},[3410,9076,9077,9079,9081],{"class":3412,"line":5687},[3410,9078,9017],{"class":4416},[3410,9080,9020],{"class":6538},[3410,9082,4411],{"class":4410},[3410,9084,9085,9087,9089,9091,9093],{"class":3412,"line":5692},[3410,9086,9027],{"class":4416},[3410,9088,9030],{"class":4403},[3410,9090,9033],{"class":4416},[3410,9092,6569],{"class":4420},[3410,9094,4411],{"class":4410},[3410,9096,9098,9100,9103,9105],{"class":3412,"line":9097},33,[3410,9099,9043],{"class":4416},[3410,9101,9102],{"class":4403}," 0.0.0.0\u002F0",[3410,9104,4454],{"class":4416},[3410,9106,4457],{"class":4403},[3410,9108,9110],{"class":3412,"line":9109},34,[3410,9111,3435],{"emptyLinePlaceholder":3434},[3410,9113,9115],{"class":3412,"line":9114},35,[3410,9116,9117],{"class":4462},"# Крок 1f: Дозвольте port 5000 (для тестування .NET без reverse proxy)\n",[3410,9119,9121,9123,9125,9127],{"class":3412,"line":9120},36,[3410,9122,4400],{"class":4399},[3410,9124,4404],{"class":4403},[3410,9126,9010],{"class":4403},[3410,9128,4411],{"class":4410},[3410,9130,9132,9134,9136],{"class":3412,"line":9131},37,[3410,9133,9017],{"class":4416},[3410,9135,9020],{"class":6538},[3410,9137,4411],{"class":4410},[3410,9139,9141,9143,9145,9147,9150],{"class":3412,"line":9140},38,[3410,9142,9027],{"class":4416},[3410,9144,9030],{"class":4403},[3410,9146,9033],{"class":4416},[3410,9148,9149],{"class":4420}," 5000",[3410,9151,4411],{"class":4410},[3410,9153,9155,9157,9159,9161],{"class":3412,"line":9154},39,[3410,9156,9043],{"class":4416},[3410,9158,9102],{"class":4403},[3410,9160,4454],{"class":4416},[3410,9162,4457],{"class":4403},[3410,9164,9166],{"class":3412,"line":9165},40,[3410,9167,3435],{"emptyLinePlaceholder":3434},[3410,9169,9171],{"class":3412,"line":9170},41,[3410,9172,9173],{"class":4462},"# Крок 1g: Створіть SSH key pair\n",[3410,9175,9177,9179,9181,9184],{"class":3412,"line":9176},42,[3410,9178,4400],{"class":4399},[3410,9180,4404],{"class":4403},[3410,9182,9183],{"class":4403}," create-key-pair",[3410,9185,4411],{"class":4410},[3410,9187,9189,9192,9195],{"class":3412,"line":9188},43,[3410,9190,9191],{"class":4416},"    --key-name",[3410,9193,9194],{"class":4403}," ec2-lab-key",[3410,9196,4411],{"class":4410},[3410,9198,9200,9202,9204],{"class":3412,"line":9199},44,[3410,9201,6606],{"class":4416},[3410,9203,8833],{"class":4403},[3410,9205,4411],{"class":4410},[3410,9207,9209,9211,9214,9216,9218,9220],{"class":3412,"line":9208},45,[3410,9210,4438],{"class":4416},[3410,9212,9213],{"class":4403}," \"KeyMaterial\"",[3410,9215,8892],{"class":4416},[3410,9217,4451],{"class":4403},[3410,9219,6301],{"class":6300},[3410,9221,9222],{"class":4403},"~\u002F.ssh\u002Fec2-lab-key.pem\n",[3410,9224,9226],{"class":3412,"line":9225},46,[3410,9227,3435],{"emptyLinePlaceholder":3434},[3410,9229,9231],{"class":3412,"line":9230},47,[3410,9232,9233],{"class":4462},"# Встановіть правильні права на файл ключа (обов'язково!)\n",[3410,9235,9237,9240,9243],{"class":3412,"line":9236},48,[3410,9238,9239],{"class":4399},"chmod",[3410,9241,9242],{"class":4420}," 400",[3410,9244,9245],{"class":4403}," ~\u002F.ssh\u002Fec2-lab-key.pem\n",[3410,9247,9249],{"class":3412,"line":9248},49,[3410,9250,3435],{"emptyLinePlaceholder":3434},[3410,9252,9254],{"class":3412,"line":9253},50,[3410,9255,9256],{"class":4462},"# Крок 1h: Запустіть instance\n",[3410,9258,9260,9263,9265,9267,9269,9272],{"class":3412,"line":9259},51,[3410,9261,9262],{"class":6538},"INSTANCE_ID",[3410,9264,7352],{"class":6300},[3410,9266,4400],{"class":4399},[3410,9268,4404],{"class":4403},[3410,9270,9271],{"class":4403}," run-instances",[3410,9273,4411],{"class":4410},[3410,9275,9277,9280,9283],{"class":3412,"line":9276},52,[3410,9278,9279],{"class":4416},"    --image-id",[3410,9281,9282],{"class":6538}," $AMI_ID",[3410,9284,4411],{"class":4410},[3410,9286,9288,9291,9294],{"class":3412,"line":9287},53,[3410,9289,9290],{"class":4416},"    --instance-type",[3410,9292,9293],{"class":4403}," t3.micro",[3410,9295,4411],{"class":4410},[3410,9297,9299,9301,9303],{"class":3412,"line":9298},54,[3410,9300,9191],{"class":4416},[3410,9302,9194],{"class":4403},[3410,9304,4411],{"class":4410},[3410,9306,9308,9311,9313],{"class":3412,"line":9307},55,[3410,9309,9310],{"class":4416},"    --security-group-ids",[3410,9312,9020],{"class":6538},[3410,9314,4411],{"class":4410},[3410,9316,9318,9320,9322],{"class":3412,"line":9317},56,[3410,9319,6606],{"class":4416},[3410,9321,8833],{"class":4403},[3410,9323,4411],{"class":4410},[3410,9325,9327,9330,9333],{"class":3412,"line":9326},57,[3410,9328,9329],{"class":4416},"    --tag-specifications",[3410,9331,9332],{"class":4403}," 'ResourceType=instance,Tags=[{Key=Name,Value=dotnet-api-server}]'",[3410,9334,4411],{"class":4410},[3410,9336,9338,9340,9343,9345,9347],{"class":3412,"line":9337},58,[3410,9339,4438],{"class":4416},[3410,9341,9342],{"class":4403}," \"Instances[0].InstanceId\"",[3410,9344,8892],{"class":4416},[3410,9346,4451],{"class":4403},[3410,9348,7378],{"class":6300},[3410,9350,9352],{"class":3412,"line":9351},59,[3410,9353,3435],{"emptyLinePlaceholder":3434},[3410,9355,9357,9359,9362,9364],{"class":3412,"line":9356},60,[3410,9358,6953],{"class":4399},[3410,9360,9361],{"class":4403}," \"Instance ID: ",[3410,9363,6539],{"class":6538},[3410,9365,8848],{"class":4403},[4876,9367,9369,9378,9387,9395,9402,9405,9412,9420,9428,9436],{"title":9368},"aws ec2 describe-instances — очікування статусу running",[4880,9370,9372,3572,9375],{"className":9371},[3412],[3410,9373,4887],{"className":9374},[4886],[3366,9376,9377],{},"aws ec2 describe-instances --instance-ids $INSTANCE_ID \\",[4880,9379,9381,4898,9384],{"className":9380},[3412],[3410,9382,4897],{"className":9383},[4886],[3366,9385,9386],{},"--query \"Reservations[0].Instances[0].State.Name\" \\",[4880,9388,9390,4898,9393],{"className":9389},[3412],[3410,9391,4897],{"className":9392},[4886],[3366,9394,4919],{},[4880,9396,9398],{"className":9397},[3412],[3410,9399,9401],{"className":9400},[4991],"pending",[4880,9403],{"className":9404},[3412],[4880,9406,9408],{"className":9407},[3412],[3410,9409,9411],{"className":9410},[4886],"# Через 2 хвилини...",[4880,9413,9415,3572,9418],{"className":9414},[3412],[3410,9416,4887],{"className":9417},[4886],[3366,9419,9377],{},[4880,9421,9423,4898,9426],{"className":9422},[3412],[3410,9424,4897],{"className":9425},[4886],[3366,9427,9386],{},[4880,9429,9431,4898,9434],{"className":9430},[3412],[3410,9432,4897],{"className":9433},[4886],[3366,9435,4919],{},[4880,9437,9439],{"className":9438},[3412],[3410,9440,4160],{"className":9441},[4926],[3348,9443,9444,9445,8075,9447,3373],{},"Зачекайте ~2 хвилини поки instance запуститься. Стан зміниться з ",[3407,9446,9401],{},[3407,9448,4160],{},[3547,9450],{},[3584,9452,9454],{"id":9453},"крок-2-підключення-до-сервера-через-ssh","Крок 2: Підключення до сервера через SSH",[3348,9456,9457,9460],{},[3366,9458,9459],{},"SSH (Secure Shell)"," — це протокол для безпечного підключення до віддаленого комп'ютера через термінал. Це як «Remote Desktop» але текстовий. Для Linux серверів SSH — стандартний спосіб роботи.",[3348,9462,9463,9464,9467],{},"Спочатку знайдіть ",[3366,9465,9466],{},"публічну IP-адресу"," вашого instance:",[7643,9469,9470,9498],{},[7646,9471,9472],{"label":7648},[7586,9473,9474,9482,9492],{},[3622,9475,9476,9477,9479,9480],{},"EC2 → ",[3366,9478,8613],{}," → оберіть ",[3407,9481,8624],{},[3622,9483,9484,9485,9488,9489],{},"У вкладці ",[3366,9486,9487],{},"Details"," знайдіть ",[3366,9490,9491],{},"Public IPv4 address",[3622,9493,9494,9495,7086],{},"Скопіюйте цей IP (наприклад: ",[3407,9496,9497],{},"3.64.185.42",[7646,9499,9500],{"label":7694},[3400,9501,9503],{"className":4390,"code":9502,"language":4392,"meta":3405,"style":3405},"# ЗАМІНІТЬ i-1234567890abcdef0 на ваш реальний Instance ID\naws ec2 describe-instances \\\n    --instance-ids $INSTANCE_ID \\\n    --query \"Reservations[0].Instances[0].PublicIpAddress\" \\\n    --output text --region eu-central-1\n",[3407,9504,9505,9510,9521,9530,9539],{"__ignoreMap":3405},[3410,9506,9507],{"class":3412,"line":3413},[3410,9508,9509],{"class":4462},"# ЗАМІНІТЬ i-1234567890abcdef0 на ваш реальний Instance ID\n",[3410,9511,9512,9514,9516,9519],{"class":3412,"line":3419},[3410,9513,4400],{"class":4399},[3410,9515,4404],{"class":4403},[3410,9517,9518],{"class":4403}," describe-instances",[3410,9520,4411],{"class":4410},[3410,9522,9523,9526,9528],{"class":3412,"line":3425},[3410,9524,9525],{"class":4416},"    --instance-ids",[3410,9527,7891],{"class":6538},[3410,9529,4411],{"class":4410},[3410,9531,9532,9534,9537],{"class":3412,"line":3431},[3410,9533,4438],{"class":4416},[3410,9535,9536],{"class":4403}," \"Reservations[0].Instances[0].PublicIpAddress\"",[3410,9538,4411],{"class":4410},[3410,9540,9541,9543,9545,9547],{"class":3412,"line":3438},[3410,9542,4448],{"class":4416},[3410,9544,4451],{"class":4403},[3410,9546,4454],{"class":4416},[3410,9548,4457],{"class":4403},[3348,9550,9551],{},"Тепер підключіться через SSH:",[4876,9553,9555,9564,9568,9572,9579,9583,9586],{"title":9554},"SSH підключення до EC2",[4880,9556,9558,3572,9561],{"className":9557},[3412],[3410,9559,4887],{"className":9560},[4886],[3366,9562,9563],{},"ssh -i ~\u002F.ssh\u002Fec2-lab-key.pem ubuntu@3.64.185.42",[4880,9565,9567],{"className":9566},[3412],"The authenticity of host '3.64.185.42' can't be established.",[4880,9569,9571],{"className":9570},[3412],"ED25519 key fingerprint is SHA256:abc123...",[4880,9573,9575,9576],{"className":9574},[3412],"Are you sure you want to continue connecting (yes\u002Fno\u002F[fingerprint])? ",[3366,9577,9578],{},"yes",[4880,9580,9582],{"className":9581},[3412],"Warning: Permanently added '3.64.185.42' (ED25519) to the list of known hosts.",[4880,9584],{"className":9585},[3412],[4880,9587,9589],{"className":9588},[3412],[3410,9590,9592],{"className":9591},[4926],"ubuntu@ip-172-31-10-25:~$",[3348,9594,9595],{},[3366,9596,9597],{},"Пояснення команди SSH:",[3619,9599,9600,9605,9627],{},[3622,9601,9602,9604],{},[3407,9603,8458],{}," — команда для підключення",[3622,9606,9607,9610,9611,9614,9615,9618,9619,9622,9623,9626],{},[3407,9608,9609],{},"-i ~\u002F.ssh\u002Fec2-lab-key.pem"," — прапорець ",[3407,9612,9613],{},"-i"," вказує файл ключа автентифікації. ",[3407,9616,9617],{},"~"," означає вашу домашню директорію (",[3407,9620,9621],{},"\u002FUsers\u002Fyourname"," на Mac, ",[3407,9624,9625],{},"C:\\Users\\yourname"," на Windows)",[3622,9628,9629,9632,9633,9636],{},[3407,9630,9631],{},"ubuntu@3.64.185.42"," — ім'я користувача (",[3407,9634,9635],{},"ubuntu"," для Ubuntu AMI) та IP-адреса сервера",[3348,9638,9639,9640,9643,9644,9646,9647,9650],{},"Після підключення ви побачите ",[3366,9641,9642],{},"запрошення командного рядка"," (",[3407,9645,9592],{},") — це означає, що ви знаходитесь всередині сервера. Всі наступні команди виконуються ",[3366,9648,9649],{},"на сервері",", не на вашому комп'ютері.",[4147,9652,9653,9654,9657,9658],{},"Якщо отримуєте помилку ",[3407,9655,9656],{},"Permission denied (publickey)"," — переконайтесь, що файл ключа має права 400: ",[3407,9659,8526],{},[3547,9661],{},[3584,9663,9665],{"id":9664},"крок-3-встановлення-net-10-на-ubuntu","Крок 3: Встановлення .NET 10 на Ubuntu",[3348,9667,9668],{},"Ви вже підключені до сервера через SSH. Виконайте наступні команди одну за одною.",[3348,9670,9671,9677,9678,9681,9682,9684],{},[3366,9672,9673,9674,9676],{},"Що таке ",[3407,9675,6883],{},"?"," Це менеджер пакетів Ubuntu — аналог Chocolatey для Windows або Homebrew для Mac. Командою ",[3407,9679,9680],{},"apt-get install"," ви встановлюєте програми, командою ",[3407,9683,5758],{}," — оновлюєте список доступних пакетів.",[3400,9686,9688],{"className":4390,"code":9687,"language":4392,"meta":3405,"style":3405},"# Оновлюємо список доступних пакетів у менеджері\n# -y означає \"погоджуватись автоматично\" без підтвердження\nsudo apt-get update -y\n",[3407,9689,9690,9695,9700],{"__ignoreMap":3405},[3410,9691,9692],{"class":3412,"line":3413},[3410,9693,9694],{"class":4462},"# Оновлюємо список доступних пакетів у менеджері\n",[3410,9696,9697],{"class":3412,"line":3419},[3410,9698,9699],{"class":4462},"# -y означає \"погоджуватись автоматично\" без підтвердження\n",[3410,9701,9702,9704,9706,9708],{"class":3412,"line":3425},[3410,9703,6266],{"class":4399},[3410,9705,6269],{"class":4403},[3410,9707,6886],{"class":4403},[3410,9709,6889],{"class":4416},[3348,9711,9712,9716,9717,9719,9720,9722,9723,3373],{},[3366,9713,9673,9714,9676],{},[3407,9715,6266],{}," На Linux більшість системних команд вимагають прав адміністратора. ",[3407,9718,6266],{}," (Super User DO) дозволяє виконати команду з правами адміністратора. Без ",[3407,9721,6266],{}," ви отримаєте помилку ",[3407,9724,9725],{},"Permission denied",[3712,9727,9728,9731,9732,9735,9736,9739,9740,9743],{},[3366,9729,9730],{},"Ubuntu 26.04 LTS і .NET 10:"," починаючи з Ubuntu 26.04, пакет ",[3407,9733,9734],{},"dotnet-sdk-10.0"," доступний безпосередньо у стандартних репозиторіях (",[3407,9737,9738],{},"resolute-updates","). Додаткові репозиторії Microsoft (",[3407,9741,9742],{},"packages-microsoft-prod",") більше не потрібні.",[4876,9745,9747,9756,9760,9764,9768,9772,9776],{"title":9746},"Встановлення .NET SDK",[4880,9748,9750,3572,9753],{"className":9749},[3412],[3410,9751,9592],{"className":9752},[4926],[3366,9754,9755],{},"sudo apt-get install -y dotnet-sdk-10.0",[4880,9757,9759],{"className":9758},[3412],"Reading package lists... Done",[4880,9761,9763],{"className":9762},[3412],"Building dependency tree... Done",[4880,9765,9767],{"className":9766},[3412],"The following NEW packages will be installed:",[4880,9769,9771],{"className":9770},[3412],"  dotnet-apphost-pack-10.0 dotnet-host-10.0 dotnet-hostfxr-10.0 dotnet-runtime-10.0 dotnet-sdk-10.0",[4880,9773,9775],{"className":9774},[3412],"0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.",[4880,9777,9779],{"className":9778},[3412],[3410,9780,9782],{"className":9781},[4926],"Setting up dotnet-sdk-10.0 (10.0.107-0ubuntu1~26.04.1)... Done",[3400,9784,9786],{"className":4390,"code":9785,"language":4392,"meta":3405,"style":3405},"# Перевірте встановлення\ndotnet --version\n",[3407,9787,9788,9793],{"__ignoreMap":3405},[3410,9789,9790],{"class":3412,"line":3413},[3410,9791,9792],{"class":4462},"# Перевірте встановлення\n",[3410,9794,9795,9798],{"class":3412,"line":3419},[3410,9796,9797],{"class":4399},"dotnet",[3410,9799,9800],{"class":4416}," --version\n",[4876,9802,9804,9813],{"title":9803},"Перевірка версії .NET",[4880,9805,9807,3572,9810],{"className":9806},[3412],[3410,9808,9592],{"className":9809},[4926],[3366,9811,9812],{},"dotnet --version",[4880,9814,9816],{"className":9815},[3412],"10.0.107",[3547,9818],{},[3584,9820,9822],{"id":9821},"крок-4-створення-та-публікація-net-web-api","Крок 4: Створення та публікація .NET Web API",[3348,9824,9825,9826,9829],{},"На ",[3366,9827,9828],{},"вашому локальному комп'ютері"," (відкрийте новий термінал, не SSH-сесію) створіть проєкт:",[3400,9831,9833],{"className":4390,"code":9832,"language":4392,"meta":3405,"style":3405},"# Створюємо новий Web API проєкт\ndotnet new webapi -n Ec2LabApi --no-openapi\ncd Ec2LabApi\n",[3407,9834,9835,9840,9859],{"__ignoreMap":3405},[3410,9836,9837],{"class":3412,"line":3413},[3410,9838,9839],{"class":4462},"# Створюємо новий Web API проєкт\n",[3410,9841,9842,9844,9847,9850,9853,9856],{"class":3412,"line":3419},[3410,9843,9797],{"class":4399},[3410,9845,9846],{"class":4403}," new",[3410,9848,9849],{"class":4403}," webapi",[3410,9851,9852],{"class":4416}," -n",[3410,9854,9855],{"class":4403}," Ec2LabApi",[3410,9857,9858],{"class":4416}," --no-openapi\n",[3410,9860,9861,9864],{"class":3412,"line":3425},[3410,9862,9863],{"class":4399},"cd",[3410,9865,9866],{"class":4403}," Ec2LabApi\n",[3348,9868,9869,9870,9873],{},"Замінимо вміст ",[3407,9871,9872],{},"Program.cs"," на наступний:",[3400,9875,9877],{"className":7919,"code":9876,"language":7921,"meta":3405,"style":3405},"var builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\n\u002F\u002F Відображаємо інформацію про сервер — корисно для перевірки\napp.MapGet(\"\u002F\", () => new\n{\n    message = \"Hello from EC2!\",\n    server = Environment.MachineName,\n    dotnetVersion = Environment.Version.ToString(),\n    timestamp = DateTime.UtcNow\n});\n\napp.MapGet(\"\u002Fhealth\", () => Results.Ok(\"Healthy\"));\n\napp.Run();\n",[3407,9878,9879,9903,9922,9926,9931,9952,9956,9969,9986,10008,10023,10028,10032,10063,10067],{"__ignoreMap":3405},[3410,9880,9881,9883,9886,9888,9891,9893,9896,9898,9901],{"class":3412,"line":3413},[3410,9882,7938],{"class":4416},[3410,9884,9885],{"class":6538}," builder",[3410,9887,6998],{"class":6300},[3410,9889,9890],{"class":6538},"WebApplication",[3410,9892,3373],{"class":6300},[3410,9894,9895],{"class":4399},"CreateBuilder",[3410,9897,7953],{"class":6300},[3410,9899,9900],{"class":6538},"args",[3410,9902,7964],{"class":6300},[3410,9904,9905,9907,9910,9912,9915,9917,9920],{"class":3412,"line":3419},[3410,9906,7938],{"class":4416},[3410,9908,9909],{"class":6538}," app",[3410,9911,6998],{"class":6300},[3410,9913,9914],{"class":6538},"builder",[3410,9916,3373],{"class":6300},[3410,9918,9919],{"class":4399},"Build",[3410,9921,8056],{"class":6300},[3410,9923,9924],{"class":3412,"line":3425},[3410,9925,3435],{"emptyLinePlaceholder":3434},[3410,9927,9928],{"class":3412,"line":3431},[3410,9929,9930],{"class":4462},"\u002F\u002F Відображаємо інформацію про сервер — корисно для перевірки\n",[3410,9932,9933,9936,9938,9941,9943,9946,9949],{"class":3412,"line":3438},[3410,9934,9935],{"class":6538},"app",[3410,9937,3373],{"class":6300},[3410,9939,9940],{"class":4399},"MapGet",[3410,9942,7953],{"class":6300},[3410,9944,9945],{"class":4403},"\"\u002F\"",[3410,9947,9948],{"class":6300},", () => ",[3410,9950,9951],{"class":4416},"new\n",[3410,9953,9954],{"class":3412,"line":3444},[3410,9955,6315],{"class":6300},[3410,9957,9958,9961,9963,9966],{"class":3412,"line":3450},[3410,9959,9960],{"class":6538},"    message",[3410,9962,6998],{"class":6300},[3410,9964,9965],{"class":4403},"\"Hello from EC2!\"",[3410,9967,9968],{"class":6300},",\n",[3410,9970,9971,9974,9976,9979,9981,9984],{"class":3412,"line":3456},[3410,9972,9973],{"class":6538},"    server",[3410,9975,6998],{"class":6300},[3410,9977,9978],{"class":6538},"Environment",[3410,9980,3373],{"class":6300},[3410,9982,9983],{"class":6538},"MachineName",[3410,9985,9968],{"class":6300},[3410,9987,9988,9991,9993,9995,9997,10000,10002,10005],{"class":3412,"line":3462},[3410,9989,9990],{"class":6538},"    dotnetVersion",[3410,9992,6998],{"class":6300},[3410,9994,9978],{"class":6538},[3410,9996,3373],{"class":6300},[3410,9998,9999],{"class":6538},"Version",[3410,10001,3373],{"class":6300},[3410,10003,10004],{"class":4399},"ToString",[3410,10006,10007],{"class":6300},"(),\n",[3410,10009,10010,10013,10015,10018,10020],{"class":3412,"line":3468},[3410,10011,10012],{"class":6538},"    timestamp",[3410,10014,6998],{"class":6300},[3410,10016,10017],{"class":6538},"DateTime",[3410,10019,3373],{"class":6300},[3410,10021,10022],{"class":6538},"UtcNow\n",[3410,10024,10025],{"class":3412,"line":3474},[3410,10026,10027],{"class":6300},"});\n",[3410,10029,10030],{"class":3412,"line":3480},[3410,10031,3435],{"emptyLinePlaceholder":3434},[3410,10033,10034,10036,10038,10040,10042,10045,10047,10050,10052,10055,10057,10060],{"class":3412,"line":3486},[3410,10035,9935],{"class":6538},[3410,10037,3373],{"class":6300},[3410,10039,9940],{"class":4399},[3410,10041,7953],{"class":6300},[3410,10043,10044],{"class":4403},"\"\u002Fhealth\"",[3410,10046,9948],{"class":6300},[3410,10048,10049],{"class":6538},"Results",[3410,10051,3373],{"class":6300},[3410,10053,10054],{"class":4399},"Ok",[3410,10056,7953],{"class":6300},[3410,10058,10059],{"class":4403},"\"Healthy\"",[3410,10061,10062],{"class":6300},"));\n",[3410,10064,10065],{"class":3412,"line":3491},[3410,10066,3435],{"emptyLinePlaceholder":3434},[3410,10068,10069,10071,10073,10076],{"class":3412,"line":3497},[3410,10070,9935],{"class":6538},[3410,10072,3373],{"class":6300},[3410,10074,10075],{"class":4399},"Run",[3410,10077,8056],{"class":6300},[3348,10079,10080],{},"Опублікуємо додаток для Linux (навіть якщо ви на Mac або Windows):",[3400,10082,10084],{"className":4390,"code":10083,"language":4392,"meta":3405,"style":3405},"# Публікуємо для Linux x64\n# -r linux-x64 вказує цільову платформу\n# --self-contained false означає що на сервері має бути .NET Runtime (ми його вже встановили)\n# -o .\u002Fpublish вказує куди зберегти результат\ndotnet publish -c Release -r linux-x64 --self-contained false -o .\u002Fpublish\n",[3407,10085,10086,10091,10096,10101,10106],{"__ignoreMap":3405},[3410,10087,10088],{"class":3412,"line":3413},[3410,10089,10090],{"class":4462},"# Публікуємо для Linux x64\n",[3410,10092,10093],{"class":3412,"line":3419},[3410,10094,10095],{"class":4462},"# -r linux-x64 вказує цільову платформу\n",[3410,10097,10098],{"class":3412,"line":3425},[3410,10099,10100],{"class":4462},"# --self-contained false означає що на сервері має бути .NET Runtime (ми його вже встановили)\n",[3410,10102,10103],{"class":3412,"line":3431},[3410,10104,10105],{"class":4462},"# -o .\u002Fpublish вказує куди зберегти результат\n",[3410,10107,10108,10110,10113,10116,10119,10122,10125,10128,10131,10134],{"class":3412,"line":3438},[3410,10109,9797],{"class":4399},[3410,10111,10112],{"class":4403}," publish",[3410,10114,10115],{"class":4416}," -c",[3410,10117,10118],{"class":4403}," Release",[3410,10120,10121],{"class":4416}," -r",[3410,10123,10124],{"class":4403}," linux-x64",[3410,10126,10127],{"class":4416}," --self-contained",[3410,10129,10130],{"class":4416}," false",[3410,10132,10133],{"class":4416}," -o",[3410,10135,10136],{"class":4403}," .\u002Fpublish\n",[4876,10138,10140,10149,10153,10157,10161,10168],{"title":10139},"dotnet publish",[4880,10141,10143,3572,10146],{"className":10142},[3412],[3410,10144,4887],{"className":10145},[4886],[3366,10147,10148],{},"dotnet publish -c Release -r linux-x64 --self-contained false -o .\u002Fpublish",[4880,10150,10152],{"className":10151},[3412],"  Determining projects to restore...",[4880,10154,10156],{"className":10155},[3412],"  Restored Ec2LabApi.csproj (2.1s)",[4880,10158,10160],{"className":10159},[3412],"  Ec2LabApi -> .\u002Fbin\u002FRelease\u002Fnet10.0\u002Flinux-x64\u002FEc2LabApi.dll",[4880,10162,10164],{"className":10163},[3412],[3410,10165,10167],{"className":10166},[4926],"  Ec2LabApi -> .\u002Fpublish\u002F",[4880,10169,10171],{"className":10170},[3412],"Build succeeded.",[3547,10173],{},[3584,10175,10177],{"id":10176},"крок-5-копіювання-файлів-на-сервер-через-scp","Крок 5: Копіювання файлів на сервер через SCP",[3348,10179,10180,10183,10184,3373],{},[3366,10181,10182],{},"SCP (Secure Copy Protocol)"," — утиліта для копіювання файлів між комп'ютерами через SSH. Синтаксис: ",[3407,10185,10186],{},"scp [файл-звідки] [куди]",[3348,10188,9825,10189,10191,10192,10195],{},[3366,10190,9828],{}," (в директорії ",[3407,10193,10194],{},"Ec2LabApi","):",[3400,10197,10199],{"className":4390,"code":10198,"language":4392,"meta":3405,"style":3405},"# Копіюємо папку publish на сервер\n# -r означає рекурсивно (разом зі всіма підпапками)\n# -i вказує SSH ключ (той самий, що для ssh)\n# ЗАМІНІТЬ 3.64.185.42 на ваш реальний Public IP\nscp -r -i ~\u002F.ssh\u002Fec2-lab-key.pem .\u002Fpublish ubuntu@3.64.185.42:\u002Ftmp\u002Fec2lab-publish\n",[3407,10200,10201,10206,10211,10216,10221],{"__ignoreMap":3405},[3410,10202,10203],{"class":3412,"line":3413},[3410,10204,10205],{"class":4462},"# Копіюємо папку publish на сервер\n",[3410,10207,10208],{"class":3412,"line":3419},[3410,10209,10210],{"class":4462},"# -r означає рекурсивно (разом зі всіма підпапками)\n",[3410,10212,10213],{"class":3412,"line":3425},[3410,10214,10215],{"class":4462},"# -i вказує SSH ключ (той самий, що для ssh)\n",[3410,10217,10218],{"class":3412,"line":3431},[3410,10219,10220],{"class":4462},"# ЗАМІНІТЬ 3.64.185.42 на ваш реальний Public IP\n",[3410,10222,10223,10226,10228,10230,10232,10235],{"class":3412,"line":3438},[3410,10224,10225],{"class":4399},"scp",[3410,10227,10121],{"class":4416},[3410,10229,8461],{"class":4416},[3410,10231,8464],{"class":4403},[3410,10233,10234],{"class":4403}," .\u002Fpublish",[3410,10236,10237],{"class":4403}," ubuntu@3.64.185.42:\u002Ftmp\u002Fec2lab-publish\n",[4876,10239,10241,10250,10254,10258,10262],{"title":10240},"scp копіювання",[4880,10242,10244,3572,10247],{"className":10243},[3412],[3410,10245,4887],{"className":10246},[4886],[3366,10248,10249],{},"scp -r -i ~\u002F.ssh\u002Fec2-lab-key.pem .\u002Fpublish ubuntu@3.64.185.42:\u002Ftmp\u002Fec2lab-publish",[4880,10251,10253],{"className":10252},[3412],"Ec2LabApi.dll                         100%  182KB   1.2MB\u002Fs   00:00",[4880,10255,10257],{"className":10256},[3412],"Ec2LabApi.pdb                         100%  268KB   1.3MB\u002Fs   00:00",[4880,10259,10261],{"className":10260},[3412],"Ec2LabApi.runtimeconfig.json          100%  151B    12.1KB\u002Fs  00:00",[4880,10263,10265],{"className":10264},[3412],[3410,10266,10268],{"className":10267},[4926],"appsettings.json                       100%  141B    11.3KB\u002Fs  00:00",[3348,10270,10271],{},"Поверніться до SSH-сесії (термінал де ви підключені до сервера). Перемістіть файли:",[3400,10273,10275],{"className":4390,"code":10274,"language":4392,"meta":3405,"style":3405},"# Переміщуємо з тимчасової директорії у постійну\nsudo mv \u002Ftmp\u002Fec2lab-publish \u002Fvar\u002Fapp\n\n# Перевіримо, що файли є\nls -la \u002Fvar\u002Fapp\u002F\n",[3407,10276,10277,10282,10294,10298,10303],{"__ignoreMap":3405},[3410,10278,10279],{"class":3412,"line":3413},[3410,10280,10281],{"class":4462},"# Переміщуємо з тимчасової директорії у постійну\n",[3410,10283,10284,10286,10289,10292],{"class":3412,"line":3419},[3410,10285,6266],{"class":4399},[3410,10287,10288],{"class":4403}," mv",[3410,10290,10291],{"class":4403}," \u002Ftmp\u002Fec2lab-publish",[3410,10293,6939],{"class":4403},[3410,10295,10296],{"class":3412,"line":3425},[3410,10297,3435],{"emptyLinePlaceholder":3434},[3410,10299,10300],{"class":3412,"line":3431},[3410,10301,10302],{"class":4462},"# Перевіримо, що файли є\n",[3410,10304,10305,10308,10311],{"class":3412,"line":3438},[3410,10306,10307],{"class":4399},"ls",[3410,10309,10310],{"class":4416}," -la",[3410,10312,10313],{"class":4403}," \u002Fvar\u002Fapp\u002F\n",[4876,10315,10317,10326,10330,10334,10338,10342,10346],{"title":10316},"Список файлів на сервері",[4880,10318,10320,3572,10323],{"className":10319},[3412],[3410,10321,9592],{"className":10322},[4926],[3366,10324,10325],{},"ls -la \u002Fvar\u002Fapp\u002F",[4880,10327,10329],{"className":10328},[3412],"total 204",[4880,10331,10333],{"className":10332},[3412],"drwxr-xr-x 2 root root   4096 Jan 15 10:30 .",[4880,10335,10337],{"className":10336},[3412],"drwxr-xr-x 8 root root   4096 Jan 15 10:30 ..",[4880,10339,10341],{"className":10340},[3412],"-rwxr-xr-x 1 root root 182456 Jan 15 10:30 Ec2LabApi.dll",[4880,10343,10345],{"className":10344},[3412],"-rw-r--r-- 1 root root    141 Jan 15 10:30 appsettings.json",[4880,10347,10349],{"className":10348},[3412],"-rw-r--r-- 1 root root    151 Jan 15 10:30 Ec2LabApi.runtimeconfig.json",[3547,10351],{},[3584,10353,10355],{"id":10354},"крок-6-запуск-і-тестування","Крок 6: Запуск і тестування",[3400,10357,10359],{"className":4390,"code":10358,"language":4392,"meta":3405,"style":3405},"# Переходимо в директорію додатку\ncd \u002Fvar\u002Fapp\n\n# Запускаємо .NET API\n# ASPNETCORE_URLS вказує на якому порту слухати\n# & в кінці запускає процес у фоновому режимі\nASPNETCORE_URLS=\"http:\u002F\u002F+:5000\" dotnet Ec2LabApi.dll &\n",[3407,10360,10361,10366,10372,10376,10381,10386,10391],{"__ignoreMap":3405},[3410,10362,10363],{"class":3412,"line":3413},[3410,10364,10365],{"class":4462},"# Переходимо в директорію додатку\n",[3410,10367,10368,10370],{"class":3412,"line":3419},[3410,10369,9863],{"class":4399},[3410,10371,6939],{"class":4403},[3410,10373,10374],{"class":3412,"line":3425},[3410,10375,3435],{"emptyLinePlaceholder":3434},[3410,10377,10378],{"class":3412,"line":3431},[3410,10379,10380],{"class":4462},"# Запускаємо .NET API\n",[3410,10382,10383],{"class":3412,"line":3438},[3410,10384,10385],{"class":4462},"# ASPNETCORE_URLS вказує на якому порту слухати\n",[3410,10387,10388],{"class":3412,"line":3444},[3410,10389,10390],{"class":4462},"# & в кінці запускає процес у фоновому режимі\n",[3410,10392,10393,10396,10399,10402,10405,10408],{"class":3412,"line":3450},[3410,10394,10395],{"class":6538},"ASPNETCORE_URLS",[3410,10397,10398],{"class":6300},"=",[3410,10400,10401],{"class":4403},"\"http:\u002F\u002F+:5000\"",[3410,10403,10404],{"class":4399}," dotnet",[3410,10406,10407],{"class":4403}," Ec2LabApi.dll",[3410,10409,10410],{"class":6300}," &\n",[4876,10412,10414,10424,10428,10436,10440,10447],{"title":10413},"Запуск API",[4880,10415,10417,3572,10421],{"className":10416},[3412],[3410,10418,10420],{"className":10419},[4926],"ubuntu@ip-172-31-10-25:\u002Fvar\u002Fapp$",[3366,10422,10423],{},"ASPNETCORE_URLS=\"http:\u002F\u002F+:5000\" dotnet Ec2LabApi.dll &",[4880,10425,10427],{"className":10426},[3412],"[1] 12345",[4880,10429,10431],{"className":10430},[3412],[3410,10432,10435],{"className":10433},[10434],"text-blue-400","info: Microsoft.Hosting.Lifetime[14]",[4880,10437,10439],{"className":10438},[3412],"     Now listening on: http:\u002F\u002F[::]:5000",[4880,10441,10443],{"className":10442},[3412],[3410,10444,10446],{"className":10445},[10434],"info: Microsoft.Hosting.Lifetime[0]",[4880,10448,10450],{"className":10449},[3412],"     Application started. Press Ctrl+C to shut down.",[3348,10452,10453],{},"Перевіримо прямо на сервері:",[3400,10455,10457],{"className":4390,"code":10456,"language":4392,"meta":3405,"style":3405},"# curl — консольний HTTP клієнт\n# Виконуємо HTTP запит до нашого API (який слухає на localhost:5000)\ncurl http:\u002F\u002Flocalhost:5000\u002F\n",[3407,10458,10459,10464,10469],{"__ignoreMap":3405},[3410,10460,10461],{"class":3412,"line":3413},[3410,10462,10463],{"class":4462},"# curl — консольний HTTP клієнт\n",[3410,10465,10466],{"class":3412,"line":3419},[3410,10467,10468],{"class":4462},"# Виконуємо HTTP запит до нашого API (який слухає на localhost:5000)\n",[3410,10470,10471,10473],{"class":3412,"line":3425},[3410,10472,7274],{"class":4399},[3410,10474,10475],{"class":4403}," http:\u002F\u002Flocalhost:5000\u002F\n",[4876,10477,10479,10488],{"title":10478},"curl тест на сервері",[4880,10480,10482,3572,10485],{"className":10481},[3412],[3410,10483,10420],{"className":10484},[4926],[3366,10486,10487],{},"curl http:\u002F\u002Flocalhost:5000\u002F",[4880,10489,10491],{"className":10490},[3412],"{\"message\":\"Hello from EC2!\",\"server\":\"ip-172-31-10-25\",\"dotnetVersion\":\"10.0.7\",\"timestamp\":\"2026-01-15T10:35:00Z\"}",[3348,10493,10494,10495,10498],{},"Тепер перевіримо з вашого ",[3366,10496,10497],{},"локального комп'ютера"," (замініть IP на ваш):",[3400,10500,10502],{"className":4390,"code":10501,"language":4392,"meta":3405,"style":3405},"# ЗАМІНІТЬ 3.64.185.42 на ваш реальний Public IP\ncurl http:\u002F\u002F3.64.185.42:5000\u002F\n# {\"message\":\"Hello from EC2!\",\"server\":\"ip-172-31-10-25\",\"dotnetVersion\":\"10.0.7\",\"timestamp\":\"2026-01-15T10:35:05Z\"}\n",[3407,10503,10504,10508,10515],{"__ignoreMap":3405},[3410,10505,10506],{"class":3412,"line":3413},[3410,10507,10220],{"class":4462},[3410,10509,10510,10512],{"class":3412,"line":3419},[3410,10511,7274],{"class":4399},[3410,10513,10514],{"class":4403}," http:\u002F\u002F3.64.185.42:5000\u002F\n",[3410,10516,10517],{"class":3412,"line":3425},[3410,10518,10519],{"class":4462},"# {\"message\":\"Hello from EC2!\",\"server\":\"ip-172-31-10-25\",\"dotnetVersion\":\"10.0.7\",\"timestamp\":\"2026-01-15T10:35:05Z\"}\n",[3348,10521,10522,10525,10526],{},[3366,10523,10524],{},"API працює у хмарі!"," Можна відкрити у браузері: ",[3407,10527,10528],{},"http:\u002F\u002F3.64.185.42:5000",[3547,10530],{},[3348,10532,10533],{},[3351,10534],{"alt":10535,"className":10536,"src":10537},"Systemd service .NET app auto restart on boot Linux EC2 diagram",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F12.jpg",[3584,10539,10541],{"id":10540},"крок-7-налаштування-systemd-service-автозапуск-після-рестарту","Крок 7: Налаштування Systemd Service — автозапуск після рестарту",[3348,10543,10544,10545,10548,10549,10552],{},"Запуск через ",[3407,10546,10547],{},"&"," — тимчасовий. Якщо сервер перезавантажиться — API не запуститься автоматично. ",[3366,10550,10551],{},"Systemd"," — це система управління сервісами на Linux. Вона запускає сервіси при старті ОС, перезапускає їх при збоях, збирає логи.",[3348,10554,10555],{},"Зупиніть поточний процес:",[3400,10557,10559],{"className":4390,"code":10558,"language":4392,"meta":3405,"style":3405},"# Знайдіть PID (Process ID) запущеного dotnet процесу\n# ps aux — показати всі запущені процеси\n# grep dotnet — відфільтрувати лише рядки зі словом \"dotnet\"\nps aux | grep dotnet\n# Виведе: ubuntu  12345  ... dotnet Ec2LabApi.dll\n\n# Завершіть процес за PID\nkill 12345\n",[3407,10560,10561,10566,10571,10576,10592,10597,10601,10606],{"__ignoreMap":3405},[3410,10562,10563],{"class":3412,"line":3413},[3410,10564,10565],{"class":4462},"# Знайдіть PID (Process ID) запущеного dotnet процесу\n",[3410,10567,10568],{"class":3412,"line":3419},[3410,10569,10570],{"class":4462},"# ps aux — показати всі запущені процеси\n",[3410,10572,10573],{"class":3412,"line":3425},[3410,10574,10575],{"class":4462},"# grep dotnet — відфільтрувати лише рядки зі словом \"dotnet\"\n",[3410,10577,10578,10581,10584,10586,10589],{"class":3412,"line":3431},[3410,10579,10580],{"class":4399},"ps",[3410,10582,10583],{"class":4403}," aux",[3410,10585,7092],{"class":6300},[3410,10587,10588],{"class":4399},"grep",[3410,10590,10591],{"class":4403}," dotnet\n",[3410,10593,10594],{"class":3412,"line":3438},[3410,10595,10596],{"class":4462},"# Виведе: ubuntu  12345  ... dotnet Ec2LabApi.dll\n",[3410,10598,10599],{"class":3412,"line":3444},[3410,10600,3435],{"emptyLinePlaceholder":3434},[3410,10602,10603],{"class":3412,"line":3450},[3410,10604,10605],{"class":4462},"# Завершіть процес за PID\n",[3410,10607,10608,10611],{"class":3412,"line":3456},[3410,10609,10610],{"class":4399},"kill",[3410,10612,10613],{"class":4420}," 12345\n",[3348,10615,10616],{},"Створіть файл unit для systemd:",[3400,10618,10620],{"className":4390,"code":10619,"language":4392,"meta":3405,"style":3405},"# nano — простий текстовий редактор у терміналі\n# Ctrl+O — зберегти, Ctrl+X — вийти\nsudo nano \u002Fetc\u002Fsystemd\u002Fsystem\u002Fec2lab-api.service\n",[3407,10621,10622,10627,10632],{"__ignoreMap":3405},[3410,10623,10624],{"class":3412,"line":3413},[3410,10625,10626],{"class":4462},"# nano — простий текстовий редактор у терміналі\n",[3410,10628,10629],{"class":3412,"line":3419},[3410,10630,10631],{"class":4462},"# Ctrl+O — зберегти, Ctrl+X — вийти\n",[3410,10633,10634,10636,10639],{"class":3412,"line":3425},[3410,10635,6266],{"class":4399},[3410,10637,10638],{"class":4403}," nano",[3410,10640,10641],{"class":4403}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fec2lab-api.service\n",[3348,10643,10644],{},"У відкритому редакторі вставте наступний вміст:",[3400,10646,10650],{"className":10647,"code":10648,"language":10649,"meta":3405,"style":3405},"language-ini shiki shiki-themes light-plus dark-plus dark-plus","[Unit]\nDescription=EC2 Lab .NET API\n# Запускати після того, як мережа буде готова\nAfter=network.target\n\n[Service]\n# Користувач під яким запускається процес\nUser=ubuntu\n# Робоча директорія\nWorkingDirectory=\u002Fvar\u002Fapp\n# Команда запуску\nExecStart=\u002Fusr\u002Fbin\u002Fdotnet \u002Fvar\u002Fapp\u002FEc2LabApi.dll\n# Автоматично перезапускати якщо процес впав\nRestart=always\n# Чекати 10 секунд перед перезапуском\nRestartSec=10\n# Змінні середовища\nEnvironment=ASPNETCORE_ENVIRONMENT=Production\nEnvironment=ASPNETCORE_URLS=http:\u002F\u002F+:5000\n\n[Install]\n# Запускати у стандартному multi-user режимі\nWantedBy=multi-user.target\n","ini",[3407,10651,10652,10657,10665,10670,10678,10682,10687,10692,10700,10705,10713,10718,10726,10731,10739,10744,10752,10757,10769,10780,10784,10789,10794],{"__ignoreMap":3405},[3410,10653,10654],{"class":3412,"line":3413},[3410,10655,10656],{"class":6300},"[Unit]\n",[3410,10658,10659,10662],{"class":3412,"line":3419},[3410,10660,10661],{"class":4416},"Description",[3410,10663,10664],{"class":6300},"=EC2 Lab .NET API\n",[3410,10666,10667],{"class":3412,"line":3425},[3410,10668,10669],{"class":4462},"# Запускати після того, як мережа буде готова\n",[3410,10671,10672,10675],{"class":3412,"line":3431},[3410,10673,10674],{"class":4416},"After",[3410,10676,10677],{"class":6300},"=network.target\n",[3410,10679,10680],{"class":3412,"line":3438},[3410,10681,3435],{"emptyLinePlaceholder":3434},[3410,10683,10684],{"class":3412,"line":3444},[3410,10685,10686],{"class":6300},"[Service]\n",[3410,10688,10689],{"class":3412,"line":3450},[3410,10690,10691],{"class":4462},"# Користувач під яким запускається процес\n",[3410,10693,10694,10697],{"class":3412,"line":3456},[3410,10695,10696],{"class":4416},"User",[3410,10698,10699],{"class":6300},"=ubuntu\n",[3410,10701,10702],{"class":3412,"line":3462},[3410,10703,10704],{"class":4462},"# Робоча директорія\n",[3410,10706,10707,10710],{"class":3412,"line":3468},[3410,10708,10709],{"class":4416},"WorkingDirectory",[3410,10711,10712],{"class":6300},"=\u002Fvar\u002Fapp\n",[3410,10714,10715],{"class":3412,"line":3474},[3410,10716,10717],{"class":4462},"# Команда запуску\n",[3410,10719,10720,10723],{"class":3412,"line":3480},[3410,10721,10722],{"class":4416},"ExecStart",[3410,10724,10725],{"class":6300},"=\u002Fusr\u002Fbin\u002Fdotnet \u002Fvar\u002Fapp\u002FEc2LabApi.dll\n",[3410,10727,10728],{"class":3412,"line":3486},[3410,10729,10730],{"class":4462},"# Автоматично перезапускати якщо процес впав\n",[3410,10732,10733,10736],{"class":3412,"line":3491},[3410,10734,10735],{"class":4416},"Restart",[3410,10737,10738],{"class":6300},"=always\n",[3410,10740,10741],{"class":3412,"line":3497},[3410,10742,10743],{"class":4462},"# Чекати 10 секунд перед перезапуском\n",[3410,10745,10746,10749],{"class":3412,"line":3503},[3410,10747,10748],{"class":4416},"RestartSec",[3410,10750,10751],{"class":6300},"=10\n",[3410,10753,10754],{"class":3412,"line":3508},[3410,10755,10756],{"class":4462},"# Змінні середовища\n",[3410,10758,10759,10761,10763,10766],{"class":3412,"line":3513},[3410,10760,9978],{"class":4416},[3410,10762,10398],{"class":6300},[3410,10764,10765],{"class":4416},"ASPNETCORE_ENVIRONMENT",[3410,10767,10768],{"class":6300},"=Production\n",[3410,10770,10771,10773,10775,10777],{"class":3412,"line":3519},[3410,10772,9978],{"class":4416},[3410,10774,10398],{"class":6300},[3410,10776,10395],{"class":4416},[3410,10778,10779],{"class":6300},"=http:\u002F\u002F+:5000\n",[3410,10781,10782],{"class":3412,"line":3524},[3410,10783,3435],{"emptyLinePlaceholder":3434},[3410,10785,10786],{"class":3412,"line":3530},[3410,10787,10788],{"class":6300},"[Install]\n",[3410,10790,10791],{"class":3412,"line":3536},[3410,10792,10793],{"class":4462},"# Запускати у стандартному multi-user режимі\n",[3410,10795,10796,10799],{"class":3412,"line":3542},[3410,10797,10798],{"class":4416},"WantedBy",[3410,10800,10801],{"class":6300},"=multi-user.target\n",[3348,10803,10804,10805,10808,10809,10812],{},"Збережіть: натисніть ",[3407,10806,10807],{},"Ctrl+O"," (підтвердіть Enter) → ",[3407,10810,10811],{},"Ctrl+X"," для виходу.",[3400,10814,10816],{"className":4390,"code":10815,"language":4392,"meta":3405,"style":3405},"# Перечитати конфігурацію systemd (потрібно після кожної зміни .service файлу)\nsudo systemctl daemon-reload\n\n# Увімкнути автозапуск при старті системи\nsudo systemctl enable ec2lab-api\n\n# Запустити сервіс прямо зараз\nsudo systemctl start ec2lab-api\n\n# Перевірити статус\nsudo systemctl status ec2lab-api\n",[3407,10817,10818,10823,10833,10837,10842,10854,10858,10863,10874,10878,10883],{"__ignoreMap":3405},[3410,10819,10820],{"class":3412,"line":3413},[3410,10821,10822],{"class":4462},"# Перечитати конфігурацію systemd (потрібно після кожної зміни .service файлу)\n",[3410,10824,10825,10827,10830],{"class":3412,"line":3419},[3410,10826,6266],{"class":4399},[3410,10828,10829],{"class":4403}," systemctl",[3410,10831,10832],{"class":4403}," daemon-reload\n",[3410,10834,10835],{"class":3412,"line":3425},[3410,10836,3435],{"emptyLinePlaceholder":3434},[3410,10838,10839],{"class":3412,"line":3431},[3410,10840,10841],{"class":4462},"# Увімкнути автозапуск при старті системи\n",[3410,10843,10844,10846,10848,10851],{"class":3412,"line":3438},[3410,10845,6266],{"class":4399},[3410,10847,10829],{"class":4403},[3410,10849,10850],{"class":4403}," enable",[3410,10852,10853],{"class":4403}," ec2lab-api\n",[3410,10855,10856],{"class":3412,"line":3444},[3410,10857,3435],{"emptyLinePlaceholder":3434},[3410,10859,10860],{"class":3412,"line":3450},[3410,10861,10862],{"class":4462},"# Запустити сервіс прямо зараз\n",[3410,10864,10865,10867,10869,10872],{"class":3412,"line":3456},[3410,10866,6266],{"class":4399},[3410,10868,10829],{"class":4403},[3410,10870,10871],{"class":4403}," start",[3410,10873,10853],{"class":4403},[3410,10875,10876],{"class":3412,"line":3462},[3410,10877,3435],{"emptyLinePlaceholder":3434},[3410,10879,10880],{"class":3412,"line":3468},[3410,10881,10882],{"class":4462},"# Перевірити статус\n",[3410,10884,10885,10887,10889,10892],{"class":3412,"line":3474},[3410,10886,6266],{"class":4399},[3410,10888,10829],{"class":4403},[3410,10890,10891],{"class":4403}," status",[3410,10893,10853],{"class":4403},[4876,10895,10897,10906,10910,10914,10922,10926,10930,10934],{"title":10896},"systemctl status",[4880,10898,10900,3572,10903],{"className":10899},[3412],[3410,10901,4887],{"className":10902},[4886],[3366,10904,10905],{},"sudo systemctl status ec2lab-api",[4880,10907,10909],{"className":10908},[3412],"● ec2lab-api.service - EC2 Lab .NET API",[4880,10911,10913],{"className":10912},[3412],"     Loaded: loaded (\u002Fetc\u002Fsystemd\u002Fsystem\u002Fec2lab-api.service; enabled)",[4880,10915,4898,10917,10921],{"className":10916},[3412],[3410,10918,10920],{"className":10919},[4926],"Active: active (running)"," since Mon 2024-01-15 10:40:00 UTC",[4880,10923,10925],{"className":10924},[3412],"   Main PID: 13456 (dotnet)",[4880,10927,10929],{"className":10928},[3412],"      Tasks: 19 (limit: 1057)",[4880,10931,10933],{"className":10932},[3412],"     Memory: 52.1M",[4880,10935,10937],{"className":10936},[3412],"Jan 15 10:40:01 ip-172-31 dotnet[13456]: info: Lifetime Now listening on: http:\u002F\u002F[::]:5000",[3400,10939,10941],{"className":4390,"code":10940,"language":4392,"meta":3405,"style":3405},"# Переглянути логи сервісу\nsudo journalctl -u ec2lab-api -n 50 --no-pager\n\n# Слідкувати за логами в реальному часі (Ctrl+C щоб вийти)\nsudo journalctl -u ec2lab-api -f\n",[3407,10942,10943,10948,10969,10973,10978],{"__ignoreMap":3405},[3410,10944,10945],{"class":3412,"line":3413},[3410,10946,10947],{"class":4462},"# Переглянути логи сервісу\n",[3410,10949,10950,10952,10955,10958,10961,10963,10966],{"class":3412,"line":3419},[3410,10951,6266],{"class":4399},[3410,10953,10954],{"class":4403}," journalctl",[3410,10956,10957],{"class":4416}," -u",[3410,10959,10960],{"class":4403}," ec2lab-api",[3410,10962,9852],{"class":4416},[3410,10964,10965],{"class":4420}," 50",[3410,10967,10968],{"class":4416}," --no-pager\n",[3410,10970,10971],{"class":3412,"line":3425},[3410,10972,3435],{"emptyLinePlaceholder":3434},[3410,10974,10975],{"class":3412,"line":3431},[3410,10976,10977],{"class":4462},"# Слідкувати за логами в реальному часі (Ctrl+C щоб вийти)\n",[3410,10979,10980,10982,10984,10986,10988],{"class":3412,"line":3438},[3410,10981,6266],{"class":4399},[3410,10983,10954],{"class":4403},[3410,10985,10957],{"class":4416},[3410,10987,10960],{"class":4403},[3410,10989,10990],{"class":4416}," -f\n",[3348,10992,10993],{},"Перезавантажте сервер і переконайтесь, що API стартує автоматично:",[3400,10995,10997],{"className":4390,"code":10996,"language":4392,"meta":3405,"style":3405},"sudo reboot\n# Підключення закриється. Зачекайте 1-2 хвилини і підключіться знову через SSH.\n# Потім перевірте: curl http:\u002F\u002Flocalhost:5000\u002F\n",[3407,10998,10999,11006,11011],{"__ignoreMap":3405},[3410,11000,11001,11003],{"class":3412,"line":3413},[3410,11002,6266],{"class":4399},[3410,11004,11005],{"class":4403}," reboot\n",[3410,11007,11008],{"class":3412,"line":3419},[3410,11009,11010],{"class":4462},"# Підключення закриється. Зачекайте 1-2 хвилини і підключіться знову через SSH.\n",[3410,11012,11013],{"class":3412,"line":3425},[3410,11014,11015],{"class":4462},"# Потім перевірте: curl http:\u002F\u002Flocalhost:5000\u002F\n",[3547,11017],{},[3348,11019,11020],{},[3351,11021],{"alt":11022,"className":11023,"src":11024},"Custom domain pp.ua connected to EC2 with nginx reverse proxy architecture",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F13.png",[3584,11026,11028],{"id":11027},"крок-8-бонус-підключення-безкоштовного-домену-ppua-до-ec2","Крок 8 (бонус): Підключення безкоштовного домену pp.ua до EC2",[3348,11030,11031,11032,11034,11035,3373],{},"Зараз ваш API доступний за IP-адресою (",[3407,11033,10528],{},"). Але IP-адреса — це незручно: вона може змінитись, її важко запам'ятати. Підключимо безкоштовний домен ",[3407,11036,11037],{},"pp.ua",[3348,11039,11040],{},[3366,11041,11042],{},"Загальна схема:",[3400,11044,11047],{"className":11045,"code":11046,"language":8231},[8229],"myapi.pp.ua\n    ↓ A record (DNS)\n3.64.185.42 (Elastic IP вашого EC2)\n    ↓\nEC2 instance → .NET API (порт 80 через nginx)\n",[3407,11048,11046],{"__ignoreMap":3405},[3712,11050,11051,11054,11055,11058],{},[3366,11052,11053],{},"Чому Elastic IP?"," Публічна IP-адреса EC2 instance ",[3366,11056,11057],{},"змінюється"," при кожній зупинці\u002Fзапуску. Якщо прив'язати домен до змінної IP — він «зламається» після рестарту. Elastic IP — стала адреса, що не змінюється. Переконайтесь що ви виділили Elastic IP та прив'язали до instance (Крок «Elastic IP» у теоретичній частині цього модуля).",[11060,11061,11063],"h4",{"id":11062},"_8a-виділення-та-привязка-elastic-ip","8a: Виділення та прив'язка Elastic IP",[7643,11065,11066,11107],{},[7646,11067,11068],{"label":7648},[7586,11069,11070,11081,11090,11101],{},[3622,11071,9476,11072,3994,11075,3994,11078],{},[3366,11073,11074],{},"Elastic IPs",[3366,11076,11077],{},"Allocate Elastic IP address",[3366,11079,11080],{},"Allocate",[3622,11082,11083,11084,3994,11087],{},"Оберіть щойно виділений IP → ",[3366,11085,11086],{},"Actions",[3366,11088,11089],{},"Associate Elastic IP address",[3622,11091,11092,11095,11096,3994,11098],{},[3366,11093,11094],{},"Instance:"," оберіть ваш ",[3407,11097,8624],{},[3366,11099,11100],{},"Associate",[3622,11102,11103,11104,11106],{},"Запишіть Elastic IP (наприклад ",[3407,11105,9497],{},") — саме цю адресу вкажете у DNS",[7646,11108,11109],{"label":7694},[3400,11110,11112],{"className":4390,"code":11111,"language":4392,"meta":3405,"style":3405},"# Виділити Elastic IP\nALLOC_ID=$(aws ec2 allocate-address \\\n    --domain vpc --region eu-central-1 \\\n    --query AllocationId --output text)\n\nELASTIC_IP=$(aws ec2 describe-addresses \\\n    --allocation-ids $ALLOC_ID \\\n    --query \"Addresses[0].PublicIp\" --output text --region eu-central-1)\necho \"Elastic IP: $ELASTIC_IP\"\n\n# Прив'язати до instance (ЗАМІНІТЬ $INSTANCE_ID на ваш)\naws ec2 associate-address \\\n    --instance-id $INSTANCE_ID \\\n    --allocation-id $ALLOC_ID \\\n    --region eu-central-1\n",[3407,11113,11114,11119,11135,11149,11162,11166,11182,11192,11209,11221,11225,11230,11241,11249,11258],{"__ignoreMap":3405},[3410,11115,11116],{"class":3412,"line":3413},[3410,11117,11118],{"class":4462},"# Виділити Elastic IP\n",[3410,11120,11121,11124,11126,11128,11130,11133],{"class":3412,"line":3419},[3410,11122,11123],{"class":6538},"ALLOC_ID",[3410,11125,7352],{"class":6300},[3410,11127,4400],{"class":4399},[3410,11129,4404],{"class":4403},[3410,11131,11132],{"class":4403}," allocate-address",[3410,11134,4411],{"class":4410},[3410,11136,11137,11140,11143,11145,11147],{"class":3412,"line":3425},[3410,11138,11139],{"class":4416},"    --domain",[3410,11141,11142],{"class":4403}," vpc",[3410,11144,4454],{"class":4416},[3410,11146,8833],{"class":4403},[3410,11148,4411],{"class":4410},[3410,11150,11151,11153,11156,11158,11160],{"class":3412,"line":3431},[3410,11152,4438],{"class":4416},[3410,11154,11155],{"class":4403}," AllocationId",[3410,11157,8892],{"class":4416},[3410,11159,4451],{"class":4403},[3410,11161,7378],{"class":6300},[3410,11163,11164],{"class":3412,"line":3438},[3410,11165,3435],{"emptyLinePlaceholder":3434},[3410,11167,11168,11171,11173,11175,11177,11180],{"class":3412,"line":3444},[3410,11169,11170],{"class":6538},"ELASTIC_IP",[3410,11172,7352],{"class":6300},[3410,11174,4400],{"class":4399},[3410,11176,4404],{"class":4403},[3410,11178,11179],{"class":4403}," describe-addresses",[3410,11181,4411],{"class":4410},[3410,11183,11184,11187,11190],{"class":3412,"line":3450},[3410,11185,11186],{"class":4416},"    --allocation-ids",[3410,11188,11189],{"class":6538}," $ALLOC_ID",[3410,11191,4411],{"class":4410},[3410,11193,11194,11196,11199,11201,11203,11205,11207],{"class":3412,"line":3456},[3410,11195,4438],{"class":4416},[3410,11197,11198],{"class":4403}," \"Addresses[0].PublicIp\"",[3410,11200,8892],{"class":4416},[3410,11202,4451],{"class":4403},[3410,11204,4454],{"class":4416},[3410,11206,8833],{"class":4403},[3410,11208,7378],{"class":6300},[3410,11210,11211,11213,11216,11219],{"class":3412,"line":3462},[3410,11212,6953],{"class":4399},[3410,11214,11215],{"class":4403}," \"Elastic IP: ",[3410,11217,11218],{"class":6538},"$ELASTIC_IP",[3410,11220,8848],{"class":4403},[3410,11222,11223],{"class":3412,"line":3468},[3410,11224,3435],{"emptyLinePlaceholder":3434},[3410,11226,11227],{"class":3412,"line":3474},[3410,11228,11229],{"class":4462},"# Прив'язати до instance (ЗАМІНІТЬ $INSTANCE_ID на ваш)\n",[3410,11231,11232,11234,11236,11239],{"class":3412,"line":3480},[3410,11233,4400],{"class":4399},[3410,11235,4404],{"class":4403},[3410,11237,11238],{"class":4403}," associate-address",[3410,11240,4411],{"class":4410},[3410,11242,11243,11245,11247],{"class":3412,"line":3486},[3410,11244,7888],{"class":4416},[3410,11246,7891],{"class":6538},[3410,11248,4411],{"class":4410},[3410,11250,11251,11254,11256],{"class":3412,"line":3491},[3410,11252,11253],{"class":4416},"    --allocation-id",[3410,11255,11189],{"class":6538},[3410,11257,4411],{"class":4410},[3410,11259,11260,11262],{"class":3412,"line":3497},[3410,11261,6606],{"class":4416},[3410,11263,4457],{"class":4403},[11060,11265,11267],{"id":11266},"_8b-встановлення-nginx-як-reverse-proxy-порт-80","8b: Встановлення nginx як reverse proxy (порт 80)",[3348,11269,11270,11271,11274,11275,11278],{},".NET API слухає на порті 5000. Відкривати 5000 публічно — незручно (користувачам доведеться вводити ",[3407,11272,11273],{},"myapi.pp.ua:5000","). Краще поставити ",[3366,11276,11277],{},"nginx"," — lightweight веб-сервер, який приймає запити на порту 80 і проксіює їх на 5000.",[3348,11280,11281],{},"На сервері (через SSH):",[3400,11283,11285],{"className":4390,"code":11284,"language":4392,"meta":3405,"style":3405},"# Встановити nginx\nsudo apt-get install -y nginx\n\n# Створити конфігурацію для нашого API\nsudo nano \u002Fetc\u002Fnginx\u002Fsites-available\u002Fec2lab-api\n",[3407,11286,11287,11292,11305,11309,11314],{"__ignoreMap":3405},[3410,11288,11289],{"class":3412,"line":3413},[3410,11290,11291],{"class":4462},"# Встановити nginx\n",[3410,11293,11294,11296,11298,11300,11302],{"class":3412,"line":3419},[3410,11295,6266],{"class":4399},[3410,11297,6269],{"class":4403},[3410,11299,6272],{"class":4403},[3410,11301,6275],{"class":4416},[3410,11303,11304],{"class":4403}," nginx\n",[3410,11306,11307],{"class":3412,"line":3425},[3410,11308,3435],{"emptyLinePlaceholder":3434},[3410,11310,11311],{"class":3412,"line":3431},[3410,11312,11313],{"class":4462},"# Створити конфігурацію для нашого API\n",[3410,11315,11316,11318,11320],{"class":3412,"line":3438},[3410,11317,6266],{"class":4399},[3410,11319,10638],{"class":4403},[3410,11321,11322],{"class":4403}," \u002Fetc\u002Fnginx\u002Fsites-available\u002Fec2lab-api\n",[3348,11324,11325,11326,11328,11329,11331],{},"Вставте в редакторі (",[3407,11327,10807],{}," зберегти, ",[3407,11330,10811],{}," вийти):",[3400,11333,11336],{"className":11334,"code":11335,"language":11277,"meta":3405,"style":3405},"language-nginx shiki shiki-themes light-plus dark-plus dark-plus","server {\n    listen 80;\n    # ЗАМІНІТЬ myapi.pp.ua на ваш реальний субдомен\n    server_name myapi.pp.ua;\n\n    location \u002F {\n        # Проксіювати запити до .NET API на порту 5000\n        proxy_pass http:\u002F\u002Flocalhost:5000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection keep-alive;\n        # Передати реальний IP клієнта до .NET API\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_cache_bypass $http_upgrade;\n    }\n}\n",[3407,11337,11338,11343,11348,11353,11358,11362,11367,11372,11377,11382,11387,11392,11397,11402,11407,11412,11416],{"__ignoreMap":3405},[3410,11339,11340],{"class":3412,"line":3413},[3410,11341,11342],{},"server {\n",[3410,11344,11345],{"class":3412,"line":3419},[3410,11346,11347],{},"    listen 80;\n",[3410,11349,11350],{"class":3412,"line":3425},[3410,11351,11352],{},"    # ЗАМІНІТЬ myapi.pp.ua на ваш реальний субдомен\n",[3410,11354,11355],{"class":3412,"line":3431},[3410,11356,11357],{},"    server_name myapi.pp.ua;\n",[3410,11359,11360],{"class":3412,"line":3438},[3410,11361,3435],{"emptyLinePlaceholder":3434},[3410,11363,11364],{"class":3412,"line":3444},[3410,11365,11366],{},"    location \u002F {\n",[3410,11368,11369],{"class":3412,"line":3450},[3410,11370,11371],{},"        # Проксіювати запити до .NET API на порту 5000\n",[3410,11373,11374],{"class":3412,"line":3456},[3410,11375,11376],{},"        proxy_pass http:\u002F\u002Flocalhost:5000;\n",[3410,11378,11379],{"class":3412,"line":3462},[3410,11380,11381],{},"        proxy_http_version 1.1;\n",[3410,11383,11384],{"class":3412,"line":3468},[3410,11385,11386],{},"        proxy_set_header Upgrade $http_upgrade;\n",[3410,11388,11389],{"class":3412,"line":3474},[3410,11390,11391],{},"        proxy_set_header Connection keep-alive;\n",[3410,11393,11394],{"class":3412,"line":3480},[3410,11395,11396],{},"        # Передати реальний IP клієнта до .NET API\n",[3410,11398,11399],{"class":3412,"line":3486},[3410,11400,11401],{},"        proxy_set_header Host $host;\n",[3410,11403,11404],{"class":3412,"line":3491},[3410,11405,11406],{},"        proxy_set_header X-Real-IP $remote_addr;\n",[3410,11408,11409],{"class":3412,"line":3497},[3410,11410,11411],{},"        proxy_cache_bypass $http_upgrade;\n",[3410,11413,11414],{"class":3412,"line":3503},[3410,11415,3477],{},[3410,11417,11418],{"class":3412,"line":3508},[3410,11419,3483],{},[3400,11421,11423],{"className":4390,"code":11422,"language":4392,"meta":3405,"style":3405},"# Увімкнути конфігурацію (створити symbolic link)\nsudo ln -s \u002Fetc\u002Fnginx\u002Fsites-available\u002Fec2lab-api \u002Fetc\u002Fnginx\u002Fsites-enabled\u002F\n\n# Видалити дефолтну конфігурацію nginx\nsudo rm \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fdefault\n\n# Перевірити синтаксис конфігурації\nsudo nginx -t\n\n# Перезапустити nginx\nsudo systemctl restart nginx\nsudo systemctl enable nginx\n",[3407,11424,11425,11430,11445,11449,11454,11464,11468,11473,11483,11487,11492,11503],{"__ignoreMap":3405},[3410,11426,11427],{"class":3412,"line":3413},[3410,11428,11429],{"class":4462},"# Увімкнути конфігурацію (створити symbolic link)\n",[3410,11431,11432,11434,11437,11439,11442],{"class":3412,"line":3419},[3410,11433,6266],{"class":4399},[3410,11435,11436],{"class":4403}," ln",[3410,11438,7325],{"class":4416},[3410,11440,11441],{"class":4403}," \u002Fetc\u002Fnginx\u002Fsites-available\u002Fec2lab-api",[3410,11443,11444],{"class":4403}," \u002Fetc\u002Fnginx\u002Fsites-enabled\u002F\n",[3410,11446,11447],{"class":3412,"line":3425},[3410,11448,3435],{"emptyLinePlaceholder":3434},[3410,11450,11451],{"class":3412,"line":3431},[3410,11452,11453],{"class":4462},"# Видалити дефолтну конфігурацію nginx\n",[3410,11455,11456,11458,11461],{"class":3412,"line":3438},[3410,11457,6266],{"class":4399},[3410,11459,11460],{"class":4403}," rm",[3410,11462,11463],{"class":4403}," \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fdefault\n",[3410,11465,11466],{"class":3412,"line":3444},[3410,11467,3435],{"emptyLinePlaceholder":3434},[3410,11469,11470],{"class":3412,"line":3450},[3410,11471,11472],{"class":4462},"# Перевірити синтаксис конфігурації\n",[3410,11474,11475,11477,11480],{"class":3412,"line":3456},[3410,11476,6266],{"class":4399},[3410,11478,11479],{"class":4403}," nginx",[3410,11481,11482],{"class":4416}," -t\n",[3410,11484,11485],{"class":3412,"line":3462},[3410,11486,3435],{"emptyLinePlaceholder":3434},[3410,11488,11489],{"class":3412,"line":3468},[3410,11490,11491],{"class":4462},"# Перезапустити nginx\n",[3410,11493,11494,11496,11498,11501],{"class":3412,"line":3474},[3410,11495,6266],{"class":4399},[3410,11497,10829],{"class":4403},[3410,11499,11500],{"class":4403}," restart",[3410,11502,11304],{"class":4403},[3410,11504,11505,11507,11509,11511],{"class":3412,"line":3480},[3410,11506,6266],{"class":4399},[3410,11508,10829],{"class":4403},[3410,11510,10850],{"class":4403},[3410,11512,11304],{"class":4403},[4876,11514,11516,11525,11529],{"title":11515},"nginx -t перевірка конфігурації",[4880,11517,11519,3572,11522],{"className":11518},[3412],[3410,11520,9592],{"className":11521},[4926],[3366,11523,11524],{},"sudo nginx -t",[4880,11526,11528],{"className":11527},[3412],"nginx: the configuration file \u002Fetc\u002Fnginx\u002Fnginx.conf syntax is ok",[4880,11530,11532],{"className":11531},[3412],[3410,11533,11535],{"className":11534},[4926],"nginx: configuration file \u002Fetc\u002Fnginx\u002Fnginx.conf test is successful",[3348,11537,11538],{},"Також переконайтесь, що Security Group дозволяє HTTP (порт 80) — він вже мав бути відкритий при створенні instance.",[11060,11540,11542],{"id":11541},"_8c-реєстрація-субдомену-на-ppua-через-nicua","8c: Реєстрація субдомену на pp.ua через nic.ua",[3348,11544,11545,11548,11549,11552,11553,11556,11557,11560,11561,11564],{},[3366,11546,11547],{},"Що таке pp.ua?"," Це безкоштовна зона субдоменів в українському домені ",[3407,11550,11551],{},".ua",". Зона ",[3407,11554,11555],{},".pp.ua"," (Personal Page) дозволяє кожному отримати безкоштовний домен виду ",[3407,11558,11559],{},"yourname.pp.ua"," без оплати і без прив'язки до хостинг-провайдера. Реєстрація та DNS-управління здійснюється через ",[3366,11562,11563],{},"nic.ua"," — офіційний реєстр доменних імен України.",[3348,11566,11567],{},[3366,11568,11569],{},"Крок 1: Створення акаунту на nic.ua",[7586,11571,11572,11581,11593,11621,11626],{},[3622,11573,11574,11575],{},"Перейдіть на ",[11576,11577,11578],"a",{"href":11578,"rel":11579},"https:\u002F\u002Fnic.ua",[11580],"nofollow",[3622,11582,8634,11583,11586,11587,3994,11590,7086],{},[3366,11584,11585],{},"«Реєстрація»"," (або ",[3366,11588,11589],{},"«Увійти»",[3366,11591,11592],{},"«Зареєструватися»",[3622,11594,11595,11596],{},"Заповніть форму реєстрації:\n",[3619,11597,11598,11604,11609,11615],{},[3622,11599,11600,11603],{},[3366,11601,11602],{},"Email"," — ваша поштова адреса (важлива, підтвердження прийде сюди)",[3622,11605,11606,11608],{},[3366,11607,8340],{}," — мінімум 8 символів",[3622,11610,11611,11614],{},[3366,11612,11613],{},"Ім'я та прізвище"," — ваші реальні дані (потрібні для домену)",[3622,11616,11617,11620],{},[3366,11618,11619],{},"Телефон"," — може знадобитись для верифікації",[3622,11622,8634,11623],{},[3366,11624,11625],{},"«Зареєструватись»",[3622,11627,11628,11629],{},"Перейдіть у свою пошту → відкрийте лист від nic.ua → натисніть ",[3366,11630,11631],{},"посилання підтвердження",[3712,11633,11634,11635,11637],{},"Акаунт nic.ua безкоштовний. Вам не потрібно вводити дані картки для реєстрації безкоштовних ",[3407,11636,11555],{}," доменів.",[3348,11639,11640],{},[3366,11641,11642],{},"Крок 2: Пошук та реєстрація домену",[7586,11644,11645,11651,11657,11667,11672,11681,11686,11689],{},[3622,11646,11647,11648],{},"Після входу в акаунт — у пошуковому рядку на головній сторінці введіть бажаний субдомен: ",[3407,11649,11650],{},"myapi.pp.ua",[3622,11652,8634,11653,11656],{},[3366,11654,11655],{},"«Перевірити»"," або клавішу Enter",[3622,11658,11659,11660,11663,11664],{},"Якщо домен вільний — ви побачите статус ",[3366,11661,11662],{},"«Доступний»"," та кнопку ",[3366,11665,11666],{},"«Замовити»",[3622,11668,8634,11669,11671],{},[3366,11670,11666],{}," → додасться в корзину",[3622,11673,11674,11677,11678,11680],{},[3366,11675,11676],{},"Ціна: 0 грн"," — ",[3407,11679,11037],{}," домени безкоштовні",[3622,11682,8634,11683],{},[3366,11684,11685],{},"«Оформити замовлення»",[3622,11687,11688],{},"Підтвердіть дані реєстранта (власника домену) — вони підтягнуться з вашого профілю",[3622,11690,8634,11691,7434,11694],{},[3366,11692,11693],{},"«Підтвердити»",[3366,11695,11696],{},"«Зареєструвати»",[4147,11698,11699,11700,3599,11703,3599,11706,3373],{},"Вибирайте коротке запам'ятовуване ім'я. Субдомен може містити лише латинські букви, цифри та дефіс. Не може починатись або закінчуватись дефісом. Наприклад: ",[3407,11701,11702],{},"myapi",[3407,11704,11705],{},"dotnet-lab",[3407,11707,11708],{},"ec2-demo",[3348,11710,11711],{},[3366,11712,11713],{},"Крок 3: Перехід до DNS Management",[3348,11715,11716],{},"Після реєстрації домен з'явиться у вашому особистому кабінеті:",[7586,11718,11719,11729,11735,11738],{},[3622,11720,8634,11721,11724,11725,11728],{},[3366,11722,11723],{},"«Мої домени»"," або перейдіть до розділу ",[3366,11726,11727],{},"«Домени»"," в боковому меню",[3622,11730,11731,11732,11734],{},"Знайдіть ваш ",[3407,11733,11650],{}," у списку",[3622,11736,11737],{},"Натисніть на назву домену → відкриється сторінка управління",[3622,11739,11740,11741,7434,11744],{},"Перейдіть на вкладку ",[3366,11742,11743],{},"«DNS»",[3366,11745,11746],{},"«Управління DNS»",[3712,11748,11749],{},"За замовчуванням nic.ua виступає DNS-хостом для вашого домену. Вам не потрібно змінювати NS-сервери — ви вже можете додавати записи безпосередньо в їхній панелі.",[11060,11751,11753],{"id":11752},"_8d-додавання-a-record-у-dns-панелі-nicua","8d: Додавання A record у DNS панелі nic.ua",[3348,11755,11756,11757,11759,11760,7434,11763,11766],{},"У розділі ",[3366,11758,11743],{}," вашого домену натисніть ",[3366,11761,11762],{},"«Додати запис»",[3366,11764,11765],{},"«Add Record»"," і заповніть:",[4049,11768,11769,11778],{},[4052,11770,11771],{},[4055,11772,11773,11775],{},[4058,11774,5342],{},[4058,11776,11777],{},"Значення",[4075,11779,11780,11790,11805,11819],{},[4055,11781,11782,11787],{},[4080,11783,11784],{},[3366,11785,11786],{},"Тип \u002F Type",[4080,11788,11789],{},"A",[4055,11791,11792,11797],{},[4080,11793,11794],{},[3366,11795,11796],{},"Ім'я \u002F Name",[4080,11798,11799,11802,11803,7086],{},[3407,11800,11801],{},"@"," (або залиште порожнім — для кореневого ",[3407,11804,11650],{},[4055,11806,11807,11812],{},[4080,11808,11809],{},[3366,11810,11811],{},"Значення \u002F IP",[4080,11813,11814,3572,11816],{},[3407,11815,9497],{},[8752,11817,11818],{},"(ваш Elastic IP)",[4055,11820,11821,11826],{},[4080,11822,11823],{},[3366,11824,11825],{},"TTL",[4080,11827,11828],{},"300",[3348,11830,8634,11831,7434,11834,3373],{},[3366,11832,11833],{},"«Зберегти»",[3366,11835,11836],{},"«Додати»",[3348,11838,11839,11842,11843,11845,11846,11848,11849,11851],{},[3366,11840,11841],{},"Що таке A record?"," DNS запис типу A (Address) вказує браузеру яку IP-адресу використовувати для домену. Коли браузер відкриває ",[3407,11844,11650],{}," — він спочатку запитує DNS: «яка IP-адреса у ",[3407,11847,11650],{},"?» → отримує ",[3407,11850,9497],{}," → підключається до цього IP.",[4147,11853,11854,11855,11858,11859,11861,11862,11865,11866,11868,11869,11871,11872,3373],{},"Поле ",[3366,11856,11857],{},"«Ім'я»"," у DNS панелі nic.ua вже містить суфікс домену. Якщо ваш домен ",[3407,11860,11650],{},", а ви хочете налаштувати саме цей домен (не підсубдомен виду ",[3407,11863,11864],{},"www.myapi.pp.ua",") — вводьте ",[3407,11867,11801],{}," або залишайте порожнім. Якщо хочете ",[3407,11870,11864],{}," — введіть ",[3407,11873,11874],{},"www",[3348,11876,11877,11878,11881],{},"Зачекайте ",[3366,11879,11880],{},"1–10 хвилин"," поки DNS оновиться. Перевірка:",[4876,11883,11885,11894,11898,11902,11909,11916,11919,11928],{"title":11884},"DNS перевірка через nslookup",[4880,11886,11888,3572,11891],{"className":11887},[3412],[3410,11889,4887],{"className":11890},[4886],[3366,11892,11893],{},"nslookup myapi.pp.ua",[4880,11895,11897],{"className":11896},[3412],"Server: 1.1.1.1",[4880,11899,11901],{"className":11900},[3412],"Non-authoritative answer:",[4880,11903,11905],{"className":11904},[3412],[3410,11906,11908],{"className":11907},[4926],"Name: myapi.pp.ua",[4880,11910,11912],{"className":11911},[3412],[3410,11913,11915],{"className":11914},[4926],"Address: 3.64.185.42",[4880,11917],{"className":11918},[3412],[4880,11920,11922,3572,11925],{"className":11921},[3412],[3410,11923,4887],{"className":11924},[4886],[3366,11926,11927],{},"curl http:\u002F\u002Fmyapi.pp.ua\u002F",[4880,11929,11931],{"className":11930},[3412],"{\"message\":\"Hello from EC2!\",\"server\":\"ip-172-31-10-25\",...}",[3348,11933,8606,11934,11937],{},[3407,11935,11936],{},"http:\u002F\u002Fmyapi.pp.ua"," у браузері — ваш .NET API доступний через зручний домен!",[11060,11939,11941],{"id":11940},"_8e-https-через-lets-encrypt-та-certbot","8e: HTTPS через Let's Encrypt та Certbot",[3712,11943,11944,11947,11948,11951,11952,11955,11956,3373],{},[3366,11945,11946],{},"Чому не ACM?"," AWS Certificate Manager (ACM) — безкоштовний SSL-сервіс AWS, але його сертифікати не можна встановити безпосередньо на EC2. ACM працює лише через ",[3366,11949,11950],{},"ALB"," (Application Load Balancer) та ",[3366,11953,11954],{},"CloudFront",". Для HTTPS безпосередньо на EC2 — використовується ",[3366,11957,11958],{},"Let's Encrypt",[3348,11960,11961,11964,11965,11968,11969,11972],{},[3366,11962,11963],{},"Що таке Let's Encrypt?"," Це безкоштовний, автоматизований та відкритий центр сертифікації (CA), що видає TLS\u002FSSL сертифікати. Сертифікати дійсні ",[3366,11966,11967],{},"90 днів"," і оновлюються автоматично. ",[3366,11970,11971],{},"Certbot"," — офіційний клієнт Let's Encrypt, який автоматично отримує сертифікат і налаштовує nginx.",[3348,11974,11975,11978,11979,11982,11983,11986],{},[3366,11976,11977],{},"Як Let's Encrypt перевіряє що ви власник домену?"," Через ",[3366,11980,11981],{},"HTTP-01 challenge",": Certbot створює тимчасовий файл на сервері за адресою ",[3407,11984,11985],{},"http:\u002F\u002Fmyapi.pp.ua\u002F.well-known\u002Facme-challenge\u002F...",", сервери Let's Encrypt перевіряють його доступність через HTTP (порт 80) → якщо файл доступний — ви підтверджуєте права на домен → видається сертифікат.",[4003,11988,11989,11994],{},[3348,11990,11991],{},[3366,11992,11993],{},"Передумови перед запуском Certbot:",[3619,11995,11996,12002,12008],{},[3622,11997,11998,11999,12001],{},"Ваш домен ",[3407,12000,11650],{}," вже вказує на Elastic IP вашого EC2 (A record налаштований, DNS розповсюдився)",[3622,12003,12004,12005,7086],{},"nginx запущений і відповідає на HTTP запити (",[3407,12006,12007],{},"curl http:\u002F\u002Fmyapi.pp.ua",[3622,12009,12010,12011,12014,12015,12018],{},"У Security Group відкриті порти ",[3366,12012,12013],{},"80"," (HTTP) та ",[3366,12016,12017],{},"443"," (HTTPS) — перевірте зараз",[3348,12020,12021],{},[3366,12022,12023],{},"Крок 1: Відкрити порт 443 у Security Group",[3348,12025,12026,12027],{},"Перейдіть: ",[3366,12028,12029],{},"EC2 → Instances → ваш instance → Security → Security groups → Edit inbound rules → Add rule:",[4049,12031,12032,12045],{},[4052,12033,12034],{},[4055,12035,12036,12038,12040,12043],{},[4058,12037,5355],{},[4058,12039,5366],{},[4058,12041,12042],{},"Port",[4058,12044,5388],{},[4075,12046,12047],{},[4055,12048,12049,12052,12055,12057],{},[4080,12050,12051],{},"HTTPS",[4080,12053,12054],{},"TCP",[4080,12056,12017],{},[4080,12058,5402],{},[3348,12060,12061],{},"Або через AWS CLI:",[3400,12063,12065],{"className":4390,"code":12064,"language":4392,"meta":3405,"style":3405},"# Отримати ID вашої Security Group\naws ec2 describe-instances \\\n  --instance-ids i-0abc123def456789 \\\n  --query \"Reservations[0].Instances[0].SecurityGroups[0].GroupId\" \\\n  --output text\n\n# Додати правило для HTTPS\naws ec2 authorize-security-group-ingress \\\n  --group-id sg-0123456789abcdef0 \\\n  --protocol tcp \\\n  --port 443 \\\n  --cidr 0.0.0.0\u002F0\n",[3407,12066,12067,12072,12082,12092,12102,12110,12114,12119,12129,12139,12148,12158],{"__ignoreMap":3405},[3410,12068,12069],{"class":3412,"line":3413},[3410,12070,12071],{"class":4462},"# Отримати ID вашої Security Group\n",[3410,12073,12074,12076,12078,12080],{"class":3412,"line":3419},[3410,12075,4400],{"class":4399},[3410,12077,4404],{"class":4403},[3410,12079,9518],{"class":4403},[3410,12081,4411],{"class":4410},[3410,12083,12084,12087,12090],{"class":3412,"line":3425},[3410,12085,12086],{"class":4416},"  --instance-ids",[3410,12088,12089],{"class":4403}," i-0abc123def456789",[3410,12091,4411],{"class":4410},[3410,12093,12094,12097,12100],{"class":3412,"line":3431},[3410,12095,12096],{"class":4416},"  --query",[3410,12098,12099],{"class":4403}," \"Reservations[0].Instances[0].SecurityGroups[0].GroupId\"",[3410,12101,4411],{"class":4410},[3410,12103,12104,12107],{"class":3412,"line":3438},[3410,12105,12106],{"class":4416},"  --output",[3410,12108,12109],{"class":4403}," text\n",[3410,12111,12112],{"class":3412,"line":3444},[3410,12113,3435],{"emptyLinePlaceholder":3434},[3410,12115,12116],{"class":3412,"line":3450},[3410,12117,12118],{"class":4462},"# Додати правило для HTTPS\n",[3410,12120,12121,12123,12125,12127],{"class":3412,"line":3456},[3410,12122,4400],{"class":4399},[3410,12124,4404],{"class":4403},[3410,12126,9010],{"class":4403},[3410,12128,4411],{"class":4410},[3410,12130,12131,12134,12137],{"class":3412,"line":3462},[3410,12132,12133],{"class":4416},"  --group-id",[3410,12135,12136],{"class":4403}," sg-0123456789abcdef0",[3410,12138,4411],{"class":4410},[3410,12140,12141,12144,12146],{"class":3412,"line":3468},[3410,12142,12143],{"class":4416},"  --protocol",[3410,12145,9030],{"class":4403},[3410,12147,4411],{"class":4410},[3410,12149,12150,12153,12156],{"class":3412,"line":3474},[3410,12151,12152],{"class":4416},"  --port",[3410,12154,12155],{"class":4420}," 443",[3410,12157,4411],{"class":4410},[3410,12159,12160,12163],{"class":3412,"line":3480},[3410,12161,12162],{"class":4416},"  --cidr",[3410,12164,12165],{"class":4403}," 0.0.0.0\u002F0\n",[3348,12167,12168],{},[3366,12169,12170],{},"Крок 2: Встановити Certbot з плагіном nginx",[3400,12172,12174],{"className":4390,"code":12173,"language":4392,"meta":3405,"style":3405},"sudo apt-get update\nsudo apt-get install -y certbot python3-certbot-nginx\n",[3407,12175,12176,12185],{"__ignoreMap":3405},[3410,12177,12178,12180,12182],{"class":3412,"line":3413},[3410,12179,6266],{"class":4399},[3410,12181,6269],{"class":4403},[3410,12183,12184],{"class":4403}," update\n",[3410,12186,12187,12189,12191,12193,12195,12198],{"class":3412,"line":3419},[3410,12188,6266],{"class":4399},[3410,12190,6269],{"class":4403},[3410,12192,6272],{"class":4403},[3410,12194,6275],{"class":4416},[3410,12196,12197],{"class":4403}," certbot",[3410,12199,12200],{"class":4403}," python3-certbot-nginx\n",[4876,12202,12204,12213,12216,12219,12222,12226,12233],{"title":12203},"Встановлення Certbot",[4880,12205,12207,3572,12210],{"className":12206},[3412],[3410,12208,9592],{"className":12209},[4926],[3366,12211,12212],{},"sudo apt-get install -y certbot python3-certbot-nginx",[4880,12214,9759],{"className":12215},[3412],[4880,12217,9763],{"className":12218},[3412],[4880,12220,9767],{"className":12221},[3412],[4880,12223,12225],{"className":12224},[3412],"  certbot python3-certbot python3-certbot-nginx python3-acme",[4880,12227,12229],{"className":12228},[3412],[3410,12230,12232],{"className":12231},[4926],"Setting up certbot (2.12.0-1) ...",[4880,12234,12236],{"className":12235},[3412],[3410,12237,12239],{"className":12238},[4926],"Setting up python3-certbot-nginx (2.12.0-1) ...",[3348,12241,12242],{},[3366,12243,12244],{},"Крок 3: Отримати SSL сертифікат",[3400,12246,12248],{"className":4390,"code":12247,"language":4392,"meta":3405,"style":3405},"# ЗАМІНІТЬ myapi.pp.ua на ваш реальний домен\nsudo certbot --nginx -d myapi.pp.ua\n",[3407,12249,12250,12255],{"__ignoreMap":3405},[3410,12251,12252],{"class":3412,"line":3413},[3410,12253,12254],{"class":4462},"# ЗАМІНІТЬ myapi.pp.ua на ваш реальний домен\n",[3410,12256,12257,12259,12261,12264,12267],{"class":3412,"line":3419},[3410,12258,6266],{"class":4399},[3410,12260,12197],{"class":4403},[3410,12262,12263],{"class":4416}," --nginx",[3410,12265,12266],{"class":4416}," -d",[3410,12268,12269],{"class":4403}," myapi.pp.ua\n",[3348,12271,12272],{},"Certbot задасть вам кілька запитань в інтерактивному режимі:",[4876,12274,12276,12285,12289,12292,12299,12307,12314,12317,12324,12331,12338,12344,12347,12354,12361,12368,12371,12378,12382,12386,12390,12394,12401,12408,12415,12418,12425,12428,12432,12436,12444,12448,12455,12464],{"title":12275},"Запити Certbot під час отримання сертифікату",[4880,12277,12279,3572,12282],{"className":12278},[3412],[3410,12280,9592],{"className":12281},[4926],[3366,12283,12284],{},"sudo certbot --nginx -d myapi.pp.ua",[4880,12286,12288],{"className":12287},[3412],"Saving debug log to \u002Fvar\u002Flog\u002Fletsencrypt\u002Fletsencrypt.log",[4880,12290],{"className":12291},[3412],[4880,12293,12295],{"className":12294},[3412],[3410,12296,12298],{"className":12297},[4991],"Enter email address (for urgent renewal\u002Fsecurity notices):",[4880,12300,12302],{"className":12301},[3412],[3410,12303,12306],{"className":12304},[12305],"opacity-60","# Введіть ваш email → натисніть Enter",[4880,12308,12310],{"className":12309},[3412],[3410,12311,12313],{"className":12312},[4991],"your@email.com",[4880,12315],{"className":12316},[3412],[4880,12318,12320],{"className":12319},[3412],[3410,12321,12323],{"className":12322},[4991],"Please read the Terms of Service at https:\u002F\u002Fletsencrypt.org\u002Fdocuments\u002FLE-SA-v1.4-April-3-2024.pdf",[4880,12325,12327],{"className":12326},[3412],[3410,12328,12330],{"className":12329},[4991],"(A)gree\u002F(C)ancel:",[4880,12332,12334],{"className":12333},[3412],[3410,12335,12337],{"className":12336},[12305],"# Введіть: A",[4880,12339,12341],{"className":12340},[3412],[3410,12342,11789],{"className":12343},[4991],[4880,12345],{"className":12346},[3412],[4880,12348,12350],{"className":12349},[3412],[3410,12351,12353],{"className":12352},[4991],"Would you be willing to share your email address with EFF? (Y)es\u002F(N)o:",[4880,12355,12357],{"className":12356},[3412],[3410,12358,12360],{"className":12359},[12305],"# Введіть: N (або Y — на ваш вибір)",[4880,12362,12364],{"className":12363},[3412],[3410,12365,12367],{"className":12366},[4991],"N",[4880,12369],{"className":12370},[3412],[4880,12372,12374],{"className":12373},[3412],[3410,12375,12377],{"className":12376},[12305],"# Certbot автоматично верифікує домен через HTTP-01 challenge...",[4880,12379,12381],{"className":12380},[3412],"Obtaining a new certificate",[4880,12383,12385],{"className":12384},[3412],"Performing the following challenges:",[4880,12387,12389],{"className":12388},[3412],"http-01 challenge for myapi.pp.ua",[4880,12391,12393],{"className":12392},[3412],"Waiting for verification...",[4880,12395,12397],{"className":12396},[3412],[3410,12398,12400],{"className":12399},[4926],"Cleaning up challenges",[4880,12402,12404],{"className":12403},[3412],[3410,12405,12407],{"className":12406},[4926],"Deploying certificate to VirtualHost \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fec2lab-api",[4880,12409,12411],{"className":12410},[3412],[3410,12412,12414],{"className":12413},[4926],"Redirecting all traffic on port 80 to ssl in \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fec2lab-api",[4880,12416],{"className":12417},[3412],[4880,12419,12421],{"className":12420},[3412],[3410,12422,12424],{"className":12423},[4926],"Congratulations! You have successfully enabled https:\u002F\u002Fmyapi.pp.ua",[4880,12426],{"className":12427},[3412],[4880,12429,12431],{"className":12430},[3412],"IMPORTANT NOTES:",[4880,12433,12435],{"className":12434},[3412]," - Congratulations! Your certificate and chain have been saved at:",[4880,12437,12439,12440],{"className":12438},[3412],"   ",[3410,12441,12443],{"className":12442},[4926],"\u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Ffullchain.pem",[4880,12445,12447],{"className":12446},[3412],"   Your key file has been saved at:",[4880,12449,12439,12451],{"className":12450},[3412],[3410,12452,12454],{"className":12453},[4926],"\u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Fprivkey.pem",[4880,12456,12458,12459,12463],{"className":12457},[3412],"   Your certificate will expire on ",[3410,12460,12462],{"className":12461},[4991],"2026-08-19",". Make sure to renew",[4880,12465,12467],{"className":12466},[3412],"   it before then.",[3348,12469,12470,12473,12474,12477],{},[3366,12471,12472],{},"Що Certbot зробив автоматично?"," Він модифікував ваш файл ",[3407,12475,12476],{},"\u002Fetc\u002Fnginx\u002Fsites-available\u002Fec2lab-api"," — додав SSL директиви та редирект з HTTP на HTTPS:",[3400,12479,12481],{"className":11334,"code":12480,"language":11277,"meta":3405,"style":3405},"server {\n    # Certbot додав: слухати порт 443 з SSL\n    listen 443 ssl;\n    server_name myapi.pp.ua;\n\n    # Certbot додав: шляхи до сертифікатів\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Fprivkey.pem;\n    include \u002Fetc\u002Fletsencrypt\u002Foptions-ssl-nginx.conf;\n    ssl_dhparam \u002Fetc\u002Fletsencrypt\u002Fssl-dhparams.pem;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002Flocalhost:5000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection keep-alive;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_cache_bypass $http_upgrade;\n    }\n}\n\n# Certbot додав: редирект HTTP → HTTPS\nserver {\n    listen 80;\n    server_name myapi.pp.ua;\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n",[3407,12482,12483,12487,12492,12497,12501,12505,12510,12515,12520,12525,12530,12534,12538,12542,12546,12550,12554,12558,12562,12566,12570,12574,12578,12583,12587,12591,12595,12600],{"__ignoreMap":3405},[3410,12484,12485],{"class":3412,"line":3413},[3410,12486,11342],{},[3410,12488,12489],{"class":3412,"line":3419},[3410,12490,12491],{},"    # Certbot додав: слухати порт 443 з SSL\n",[3410,12493,12494],{"class":3412,"line":3425},[3410,12495,12496],{},"    listen 443 ssl;\n",[3410,12498,12499],{"class":3412,"line":3431},[3410,12500,11357],{},[3410,12502,12503],{"class":3412,"line":3438},[3410,12504,3435],{"emptyLinePlaceholder":3434},[3410,12506,12507],{"class":3412,"line":3444},[3410,12508,12509],{},"    # Certbot додав: шляхи до сертифікатів\n",[3410,12511,12512],{"class":3412,"line":3450},[3410,12513,12514],{},"    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Ffullchain.pem;\n",[3410,12516,12517],{"class":3412,"line":3456},[3410,12518,12519],{},"    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Fprivkey.pem;\n",[3410,12521,12522],{"class":3412,"line":3462},[3410,12523,12524],{},"    include \u002Fetc\u002Fletsencrypt\u002Foptions-ssl-nginx.conf;\n",[3410,12526,12527],{"class":3412,"line":3468},[3410,12528,12529],{},"    ssl_dhparam \u002Fetc\u002Fletsencrypt\u002Fssl-dhparams.pem;\n",[3410,12531,12532],{"class":3412,"line":3474},[3410,12533,3435],{"emptyLinePlaceholder":3434},[3410,12535,12536],{"class":3412,"line":3480},[3410,12537,11366],{},[3410,12539,12540],{"class":3412,"line":3486},[3410,12541,11376],{},[3410,12543,12544],{"class":3412,"line":3491},[3410,12545,11381],{},[3410,12547,12548],{"class":3412,"line":3497},[3410,12549,11386],{},[3410,12551,12552],{"class":3412,"line":3503},[3410,12553,11391],{},[3410,12555,12556],{"class":3412,"line":3508},[3410,12557,11401],{},[3410,12559,12560],{"class":3412,"line":3513},[3410,12561,11406],{},[3410,12563,12564],{"class":3412,"line":3519},[3410,12565,11411],{},[3410,12567,12568],{"class":3412,"line":3524},[3410,12569,3477],{},[3410,12571,12572],{"class":3412,"line":3530},[3410,12573,3483],{},[3410,12575,12576],{"class":3412,"line":3536},[3410,12577,3435],{"emptyLinePlaceholder":3434},[3410,12579,12580],{"class":3412,"line":3542},[3410,12581,12582],{},"# Certbot додав: редирект HTTP → HTTPS\n",[3410,12584,12585],{"class":3412,"line":3891},[3410,12586,11342],{},[3410,12588,12589],{"class":3412,"line":3897},[3410,12590,11347],{},[3410,12592,12593],{"class":3412,"line":3903},[3410,12594,11357],{},[3410,12596,12597],{"class":3412,"line":3909},[3410,12598,12599],{},"    return 301 https:\u002F\u002F$host$request_uri;\n",[3410,12601,12602],{"class":3412,"line":3915},[3410,12603,3483],{},[3348,12605,12606],{},[3366,12607,12608],{},"Крок 4: Перевірити що HTTPS працює",[3400,12610,12612],{"className":4390,"code":12611,"language":4392,"meta":3405,"style":3405},"# Перевірити що nginx запущений після змін Certbot\nsudo systemctl status nginx\n\n# Перевірити відповідь через HTTPS\ncurl -I https:\u002F\u002Fmyapi.pp.ua\u002F\n\n# Перевірити деталі сертифікату\ncurl -v https:\u002F\u002Fmyapi.pp.ua\u002F 2>&1 | grep -A5 \"SSL connection\"\n",[3407,12613,12614,12619,12629,12633,12638,12648,12652,12657],{"__ignoreMap":3405},[3410,12615,12616],{"class":3412,"line":3413},[3410,12617,12618],{"class":4462},"# Перевірити що nginx запущений після змін Certbot\n",[3410,12620,12621,12623,12625,12627],{"class":3412,"line":3419},[3410,12622,6266],{"class":4399},[3410,12624,10829],{"class":4403},[3410,12626,10891],{"class":4403},[3410,12628,11304],{"class":4403},[3410,12630,12631],{"class":3412,"line":3425},[3410,12632,3435],{"emptyLinePlaceholder":3434},[3410,12634,12635],{"class":3412,"line":3431},[3410,12636,12637],{"class":4462},"# Перевірити відповідь через HTTPS\n",[3410,12639,12640,12642,12645],{"class":3412,"line":3438},[3410,12641,7274],{"class":4399},[3410,12643,12644],{"class":4416}," -I",[3410,12646,12647],{"class":4403}," https:\u002F\u002Fmyapi.pp.ua\u002F\n",[3410,12649,12650],{"class":3412,"line":3444},[3410,12651,3435],{"emptyLinePlaceholder":3434},[3410,12653,12654],{"class":3412,"line":3450},[3410,12655,12656],{"class":4462},"# Перевірити деталі сертифікату\n",[3410,12658,12659,12661,12664,12667,12670,12672,12675],{"class":3412,"line":3456},[3410,12660,7274],{"class":4399},[3410,12662,12663],{"class":4416}," -v",[3410,12665,12666],{"class":4403}," https:\u002F\u002Fmyapi.pp.ua\u002F",[3410,12668,12669],{"class":6300}," 2>&1 | ",[3410,12671,10588],{"class":4399},[3410,12673,12674],{"class":4416}," -A5",[3410,12676,12677],{"class":4403}," \"SSL connection\"\n",[4876,12679,12681,12690,12697,12701,12705,12709,12712,12721,12728,12735],{"title":12680},"Перевірка HTTPS через curl",[4880,12682,12684,3572,12687],{"className":12683},[3412],[3410,12685,9592],{"className":12686},[4926],[3366,12688,12689],{},"curl -I https:\u002F\u002Fmyapi.pp.ua\u002F",[4880,12691,12693],{"className":12692},[3412],[3410,12694,12696],{"className":12695},[4926],"HTTP\u002F2 200",[4880,12698,12700],{"className":12699},[3412],"server: nginx\u002F1.26.0 (Ubuntu)",[4880,12702,12704],{"className":12703},[3412],"content-type: application\u002Fjson; charset=utf-8",[4880,12706,12708],{"className":12707},[3412],"date: Wed, 21 May 2026 14:30:00 GMT",[4880,12710],{"className":12711},[3412],[4880,12713,12715,3572,12718],{"className":12714},[3412],[3410,12716,9592],{"className":12717},[4926],[3366,12719,12720],{},"curl -I http:\u002F\u002Fmyapi.pp.ua\u002F",[4880,12722,12724],{"className":12723},[3412],[3410,12725,12727],{"className":12726},[4991],"HTTP\u002F1.1 301 Moved Permanently",[4880,12729,12731],{"className":12730},[3412],[3410,12732,12734],{"className":12733},[4991],"Location: https:\u002F\u002Fmyapi.pp.ua\u002F",[4880,12736,12738],{"className":12737},[3412],[3410,12739,12741],{"className":12740},[12305],"# HTTP автоматично перенаправляє на HTTPS ✓",[4147,12743,8606,12744,12747,12748,3994,12751,12754,12755,12758],{},[3407,12745,12746],{},"https:\u002F\u002Fmyapi.pp.ua"," у браузері — ви побачите замочок у адресному рядку. Клацніть на замочок → ",[3366,12749,12750],{},"«Connection is secure»",[3366,12752,12753],{},"«Certificate is valid»"," → там буде вказано ",[3366,12756,12757],{},"«Let's Encrypt»"," як видавця і дата закінчення дії.",[3348,12760,12761],{},[3366,12762,12763],{},"Крок 5: Перевірити автоматичне оновлення сертифікатів",[3348,12765,12766,12767,12770],{},"Let's Encrypt сертифікати дійсні 90 днів. Certbot при встановленні автоматично налаштовує ",[3366,12768,12769],{},"systemd timer"," для щоденної перевірки і оновлення (якщо залишилось менше 30 днів).",[3400,12772,12774],{"className":4390,"code":12773,"language":4392,"meta":3405,"style":3405},"# Перевірити що timer активний\nsudo systemctl status certbot.timer\n\n# Перевірити коли наступне оновлення\nsudo systemctl list-timers certbot.timer\n\n# Протестувати оновлення без реальних змін (dry run)\nsudo certbot renew --dry-run\n",[3407,12775,12776,12781,12792,12796,12801,12812,12816,12821],{"__ignoreMap":3405},[3410,12777,12778],{"class":3412,"line":3413},[3410,12779,12780],{"class":4462},"# Перевірити що timer активний\n",[3410,12782,12783,12785,12787,12789],{"class":3412,"line":3419},[3410,12784,6266],{"class":4399},[3410,12786,10829],{"class":4403},[3410,12788,10891],{"class":4403},[3410,12790,12791],{"class":4403}," certbot.timer\n",[3410,12793,12794],{"class":3412,"line":3425},[3410,12795,3435],{"emptyLinePlaceholder":3434},[3410,12797,12798],{"class":3412,"line":3431},[3410,12799,12800],{"class":4462},"# Перевірити коли наступне оновлення\n",[3410,12802,12803,12805,12807,12810],{"class":3412,"line":3438},[3410,12804,6266],{"class":4399},[3410,12806,10829],{"class":4403},[3410,12808,12809],{"class":4403}," list-timers",[3410,12811,12791],{"class":4403},[3410,12813,12814],{"class":3412,"line":3444},[3410,12815,3435],{"emptyLinePlaceholder":3434},[3410,12817,12818],{"class":3412,"line":3450},[3410,12819,12820],{"class":4462},"# Протестувати оновлення без реальних змін (dry run)\n",[3410,12822,12823,12825,12827,12830],{"class":3412,"line":3456},[3410,12824,6266],{"class":4399},[3410,12826,12197],{"class":4403},[3410,12828,12829],{"class":4403}," renew",[3410,12831,12832],{"class":4416}," --dry-run\n",[4876,12834,12836,12845,12852,12856,12863,12867,12870,12879,12882,12886,12890,12893,12900,12907,12910],{"title":12835},"Перевірка certbot.timer та dry-run тест",[4880,12837,12839,3572,12842],{"className":12838},[3412],[3410,12840,9592],{"className":12841},[4926],[3366,12843,12844],{},"sudo systemctl status certbot.timer",[4880,12846,12848],{"className":12847},[3412],[3410,12849,12851],{"className":12850},[4926],"● certbot.timer - Run certbot twice daily",[4880,12853,12855],{"className":12854},[3412],"     Loaded: loaded (\u002Flib\u002Fsystemd\u002Fsystem\u002Fcertbot.timer; enabled)",[4880,12857,4898,12859],{"className":12858},[3412],[3410,12860,12862],{"className":12861},[4926],"Active: active (waiting)",[4880,12864,12866],{"className":12865},[3412],"    Trigger: Thu 2026-05-22 00:00:00 UTC; 9h left",[4880,12868],{"className":12869},[3412],[4880,12871,12873,3572,12876],{"className":12872},[3412],[3410,12874,9592],{"className":12875},[4926],[3366,12877,12878],{},"sudo certbot renew --dry-run",[4880,12880,12288],{"className":12881},[3412],[4880,12883,12885],{"className":12884},[3412],"- - - - - - - - - - - - - - - - - - - - - - - - -",[4880,12887,12889],{"className":12888},[3412],"Processing \u002Fetc\u002Fletsencrypt\u002Frenewal\u002Fmyapi.pp.ua.conf",[4880,12891,12885],{"className":12892},[3412],[4880,12894,12896],{"className":12895},[3412],[3410,12897,12899],{"className":12898},[4926],"Congratulations, all renewals succeeded. The following certs have been renewed:",[4880,12901,12903],{"className":12902},[3412],[3410,12904,12906],{"className":12905},[4926],"  \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002Ffullchain.pem (success)",[4880,12908,12885],{"className":12909},[3412],[4880,12911,12913],{"className":12912},[3412],[3410,12914,12916],{"className":12915},[4991],"** DRY RUN: simulating 'certbot renew' close to cert expiry **",[3348,12918,12919],{},[3366,12920,12921],{},"Де зберігаються сертифікати?",[3400,12923,12925],{"className":4390,"code":12924,"language":4392,"meta":3405,"style":3405},"ls -la \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002F\n",[3407,12926,12927],{"__ignoreMap":3405},[3410,12928,12929,12931,12933],{"class":3412,"line":3413},[3410,12930,10307],{"class":4399},[3410,12932,10310],{"class":4416},[3410,12934,12935],{"class":4403}," \u002Fetc\u002Fletsencrypt\u002Flive\u002Fmyapi.pp.ua\u002F\n",[4049,12937,12938,12947],{},[4052,12939,12940],{},[4055,12941,12942,12945],{},[4058,12943,12944],{},"Файл",[4058,12946,5168],{},[4075,12948,12949,12959,12969,12979],{},[4055,12950,12951,12956],{},[4080,12952,12953],{},[3407,12954,12955],{},"fullchain.pem",[4080,12957,12958],{},"Ваш сертифікат + проміжний ланцюжок CA (для nginx\u002FApache)",[4055,12960,12961,12966],{},[4080,12962,12963],{},[3407,12964,12965],{},"privkey.pem",[4080,12967,12968],{},"Приватний ключ (тримайте в секреті, не передавайте)",[4055,12970,12971,12976],{},[4080,12972,12973],{},[3407,12974,12975],{},"cert.pem",[4080,12977,12978],{},"Лише ваш сертифікат (без ланцюжка)",[4055,12980,12981,12986],{},[4080,12982,12983],{},[3407,12984,12985],{},"chain.pem",[4080,12987,12988],{},"Лише проміжний ланцюжок Let's Encrypt",[4003,12990,12991,12992,12995],{},"Всі файли в ",[3407,12993,12994],{},"\u002Fetc\u002Fletsencrypt\u002Flive\u002F"," — це симлінки на актуальні версії. Ніколи не копіюйте і не переміщуйте їх вручну. При оновленні сертифікату Certbot автоматично оновлює файли, на які вказують ці симлінки.",[3348,12997,12998],{},[3366,12999,13000],{},"Типові помилки та рішення:",[4049,13002,13003,13016],{},[4052,13004,13005],{},[4055,13006,13007,13010,13013],{},[4058,13008,13009],{},"Помилка",[4058,13011,13012],{},"Причина",[4058,13014,13015],{},"Рішення",[4075,13017,13018,13036,13052,13069],{},[4055,13019,13020,13028,13031],{},[4080,13021,13022,6178,13025],{},[3407,13023,13024],{},"Connection refused",[3407,13026,13027],{},"Timeout during connect",[4080,13029,13030],{},"Порт 80 закритий у Security Group",[4080,13032,13033,13034],{},"Додайте inbound rule HTTP (80) для ",[3407,13035,5402],{},[4055,13037,13038,13043,13046],{},[4080,13039,13040],{},[3407,13041,13042],{},"DNS problem: NXDOMAIN looking up A for myapi.pp.ua",[4080,13044,13045],{},"DNS ще не розповсюдився або A record неправильний",[4080,13047,13048,13049,13051],{},"Перевірте ",[3407,13050,11893],{},", зачекайте 5-10 хвилин",[4055,13053,13054,13059,13062],{},[4080,13055,13056],{},[3407,13057,13058],{},"too many certificates already issued for pp.ua",[4080,13060,13061],{},"Rate limit Let's Encrypt (5 сертифікатів\u002Fтиждень на домен)",[4080,13063,13064,13065,13068],{},"Зачекайте тиждень або використайте ",[3407,13066,13067],{},"--staging"," для тестів",[4055,13070,13071,13076,13082],{},[4080,13072,13073],{},[3407,13074,13075],{},"Error: The requested nginx plugin does not appear to be installed",[4080,13077,13078,13079],{},"Не встановлено ",[3407,13080,13081],{},"python3-certbot-nginx",[4080,13083,13084],{},[3407,13085,13086],{},"sudo apt-get install python3-certbot-nginx",[3547,13088],{},[3348,13090,13091],{},[3351,13092],{"alt":13093,"className":13094,"src":13095},"Windows Server EC2 IIS ASP.NET Core deployment with RDP and PowerShell",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F14.png",[3358,13097,13099],{"id":13098},"практичний-приклад-aspnet-core-з-iis-на-windows-server","Практичний приклад: ASP.NET Core з IIS на Windows Server",[3348,13101,13102],{},"Windows Server EC2 підходить для випадків, коли потрібен IIS (Internet Information Services) — веб-сервер Microsoft, або для legacy .NET Framework додатків.",[3584,13104,13106],{"id":13105},"крок-1-запуск-windows-server-ec2","Крок 1: Запуск Windows Server EC2",[7643,13108,13109,13191],{},[7646,13110,13111],{"label":7648},[7586,13112,13113,13117,13124,13146,13155,13166,13182,13187],{},[3622,13114,9476,13115],{},[3366,13116,8616],{},[3622,13118,13119,3572,13121],{},[3366,13120,8621],{},[3407,13122,13123],{},"windows-iis-server",[3622,13125,13126,13129,13130,9479,13132,13135],{},[3366,13127,13128],{},"AMI:"," У пошуку введіть ",[3407,13131,4331],{},[3366,13133,13134],{},"Microsoft Windows Server 2022 Base",[3619,13136,13137],{},[3622,13138,13139,13140,13143,13144,7086],{},"Увага: Windows AMI позначені як ",[3366,13141,13142],{},"Paid"," — вартість Windows-ліцензії включена в ціну instance (~$0.05\u002Fгод для ",[3407,13145,3607],{},[3622,13147,13148,3572,13150,3572,13152],{},[3366,13149,8654],{},[3407,13151,3607],{},[8752,13153,13154],{},"(мінімум для Windows Server + IIS + .NET)",[3622,13156,13157,13160,13161,13163,13164],{},[3366,13158,13159],{},"Key pair:"," оберіть існуючий ",[3407,13162,8678],{}," або створіть новий у форматі ",[3407,13165,8262],{},[3622,13167,13168,13171],{},[3366,13169,13170],{},"Network settings → Create security group:",[3619,13172,13173,13179],{},[3622,13174,13175,13176,13178],{},"✅ Allow RDP traffic from: ",[3366,13177,8750],{}," (порт 3389 — Remote Desktop Protocol)",[3622,13180,13181],{},"✅ Allow HTTP traffic from the internet (порт 80)",[3622,13183,13184,13186],{},[3366,13185,8765],{}," 50 GB gp3 (Windows займає більше місця)",[3622,13188,13189],{},[3366,13190,8771],{},[7646,13192,13193],{"label":7694},[3400,13194,13196],{"className":4390,"code":13195,"language":4392,"meta":3405,"style":3405},"# Знайдіть актуальний Windows Server 2022 AMI\nWIN_AMI=$(aws ec2 describe-images \\\n    --owners amazon \\\n    --filters \\\n        \"Name=name,Values=Windows_Server-2022-English-Full-Base-*\" \\\n        \"Name=state,Values=available\" \\\n    --query \"sort_by(Images, &CreationDate)[-1].ImageId\" \\\n    --output text --region eu-central-1)\necho \"Windows AMI: $WIN_AMI\"\n\n# Створіть Security Group для Windows\nWIN_SG=$(aws ec2 create-security-group \\\n    --group-name windows-iis-sg \\\n    --description \"Windows IIS Security Group\" \\\n    --vpc-id $VPC_ID \\\n    --region eu-central-1 \\\n    --query GroupId --output text)\n\n# RDP тільки з вашого IP\nMY_IP=$(curl -s https:\u002F\u002Fcheckip.amazonaws.com)\naws ec2 authorize-security-group-ingress \\\n    --group-id $WIN_SG --protocol tcp --port 3389 \\\n    --cidr \"${MY_IP}\u002F32\" --region eu-central-1\n\n# HTTP публічно\naws ec2 authorize-security-group-ingress \\\n    --group-id $WIN_SG --protocol tcp --port 80 \\\n    --cidr 0.0.0.0\u002F0 --region eu-central-1\n\n# Запуск Windows instance\nWIN_INSTANCE=$(aws ec2 run-instances \\\n    --image-id $WIN_AMI \\\n    --instance-type t3.medium \\\n    --key-name ec2-lab-key \\\n    --security-group-ids $WIN_SG \\\n    --region eu-central-1 \\\n    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=windows-iis-server}]' \\\n    --query \"Instances[0].InstanceId\" --output text)\necho \"Windows Instance: $WIN_INSTANCE\"\n",[3407,13197,13198,13203,13218,13227,13233,13240,13247,13255,13267,13279,13283,13288,13303,13312,13321,13329,13337,13349,13353,13358,13372,13382,13401,13415,13419,13424,13434,13450,13460,13464,13469,13484,13493,13502,13510,13518,13526,13535,13547],{"__ignoreMap":3405},[3410,13199,13200],{"class":3412,"line":3413},[3410,13201,13202],{"class":4462},"# Знайдіть актуальний Windows Server 2022 AMI\n",[3410,13204,13205,13208,13210,13212,13214,13216],{"class":3412,"line":3419},[3410,13206,13207],{"class":6538},"WIN_AMI",[3410,13209,7352],{"class":6300},[3410,13211,4400],{"class":4399},[3410,13213,4404],{"class":4403},[3410,13215,4407],{"class":4403},[3410,13217,4411],{"class":4410},[3410,13219,13220,13222,13225],{"class":3412,"line":3425},[3410,13221,4417],{"class":4416},[3410,13223,13224],{"class":4403}," amazon",[3410,13226,4411],{"class":4410},[3410,13228,13229,13231],{"class":3412,"line":3431},[3410,13230,4428],{"class":4416},[3410,13232,4411],{"class":4410},[3410,13234,13235,13238],{"class":3412,"line":3438},[3410,13236,13237],{"class":4403},"        \"Name=name,Values=Windows_Server-2022-English-Full-Base-*\"",[3410,13239,4411],{"class":4410},[3410,13241,13242,13245],{"class":3412,"line":3444},[3410,13243,13244],{"class":4403},"        \"Name=state,Values=available\"",[3410,13246,4411],{"class":4410},[3410,13248,13249,13251,13253],{"class":3412,"line":3450},[3410,13250,4438],{"class":4416},[3410,13252,4441],{"class":4403},[3410,13254,4411],{"class":4410},[3410,13256,13257,13259,13261,13263,13265],{"class":3412,"line":3456},[3410,13258,4448],{"class":4416},[3410,13260,4451],{"class":4403},[3410,13262,4454],{"class":4416},[3410,13264,8833],{"class":4403},[3410,13266,7378],{"class":6300},[3410,13268,13269,13271,13274,13277],{"class":3412,"line":3462},[3410,13270,6953],{"class":4399},[3410,13272,13273],{"class":4403}," \"Windows AMI: ",[3410,13275,13276],{"class":6538},"$WIN_AMI",[3410,13278,8848],{"class":4403},[3410,13280,13281],{"class":3412,"line":3468},[3410,13282,3435],{"emptyLinePlaceholder":3434},[3410,13284,13285],{"class":3412,"line":3474},[3410,13286,13287],{"class":4462},"# Створіть Security Group для Windows\n",[3410,13289,13290,13293,13295,13297,13299,13301],{"class":3412,"line":3480},[3410,13291,13292],{"class":6538},"WIN_SG",[3410,13294,7352],{"class":6300},[3410,13296,4400],{"class":4399},[3410,13298,4404],{"class":4403},[3410,13300,8923],{"class":4403},[3410,13302,4411],{"class":4410},[3410,13304,13305,13307,13310],{"class":3412,"line":3486},[3410,13306,8930],{"class":4416},[3410,13308,13309],{"class":4403}," windows-iis-sg",[3410,13311,4411],{"class":4410},[3410,13313,13314,13316,13319],{"class":3412,"line":3491},[3410,13315,8940],{"class":4416},[3410,13317,13318],{"class":4403}," \"Windows IIS Security Group\"",[3410,13320,4411],{"class":4410},[3410,13322,13323,13325,13327],{"class":3412,"line":3497},[3410,13324,8950],{"class":4416},[3410,13326,8953],{"class":6538},[3410,13328,4411],{"class":4410},[3410,13330,13331,13333,13335],{"class":3412,"line":3503},[3410,13332,6606],{"class":4416},[3410,13334,8833],{"class":4403},[3410,13336,4411],{"class":4410},[3410,13338,13339,13341,13343,13345,13347],{"class":3412,"line":3508},[3410,13340,4438],{"class":4416},[3410,13342,8970],{"class":4403},[3410,13344,8892],{"class":4416},[3410,13346,4451],{"class":4403},[3410,13348,7378],{"class":6300},[3410,13350,13351],{"class":3412,"line":3513},[3410,13352,3435],{"emptyLinePlaceholder":3434},[3410,13354,13355],{"class":3412,"line":3519},[3410,13356,13357],{"class":4462},"# RDP тільки з вашого IP\n",[3410,13359,13360,13362,13364,13366,13368,13370],{"class":3412,"line":3524},[3410,13361,8990],{"class":6538},[3410,13363,7352],{"class":6300},[3410,13365,7274],{"class":4399},[3410,13367,7325],{"class":4416},[3410,13369,8999],{"class":4403},[3410,13371,7378],{"class":6300},[3410,13373,13374,13376,13378,13380],{"class":3412,"line":3530},[3410,13375,4400],{"class":4399},[3410,13377,4404],{"class":4403},[3410,13379,9010],{"class":4403},[3410,13381,4411],{"class":4410},[3410,13383,13384,13386,13389,13392,13394,13396,13399],{"class":3412,"line":3536},[3410,13385,9017],{"class":4416},[3410,13387,13388],{"class":6538}," $WIN_SG",[3410,13390,13391],{"class":4416}," --protocol",[3410,13393,9030],{"class":4403},[3410,13395,9033],{"class":4416},[3410,13397,13398],{"class":4420}," 3389",[3410,13400,4411],{"class":4410},[3410,13402,13403,13405,13407,13409,13411,13413],{"class":3412,"line":3542},[3410,13404,9043],{"class":4416},[3410,13406,9046],{"class":4403},[3410,13408,8990],{"class":6538},[3410,13410,9051],{"class":4403},[3410,13412,4454],{"class":4416},[3410,13414,4457],{"class":4403},[3410,13416,13417],{"class":3412,"line":3891},[3410,13418,3435],{"emptyLinePlaceholder":3434},[3410,13420,13421],{"class":3412,"line":3897},[3410,13422,13423],{"class":4462},"# HTTP публічно\n",[3410,13425,13426,13428,13430,13432],{"class":3412,"line":3903},[3410,13427,4400],{"class":4399},[3410,13429,4404],{"class":4403},[3410,13431,9010],{"class":4403},[3410,13433,4411],{"class":4410},[3410,13435,13436,13438,13440,13442,13444,13446,13448],{"class":3412,"line":3909},[3410,13437,9017],{"class":4416},[3410,13439,13388],{"class":6538},[3410,13441,13391],{"class":4416},[3410,13443,9030],{"class":4403},[3410,13445,9033],{"class":4416},[3410,13447,6569],{"class":4420},[3410,13449,4411],{"class":4410},[3410,13451,13452,13454,13456,13458],{"class":3412,"line":3915},[3410,13453,9043],{"class":4416},[3410,13455,9102],{"class":4403},[3410,13457,4454],{"class":4416},[3410,13459,4457],{"class":4403},[3410,13461,13462],{"class":3412,"line":3921},[3410,13463,3435],{"emptyLinePlaceholder":3434},[3410,13465,13466],{"class":3412,"line":5681},[3410,13467,13468],{"class":4462},"# Запуск Windows instance\n",[3410,13470,13471,13474,13476,13478,13480,13482],{"class":3412,"line":5687},[3410,13472,13473],{"class":6538},"WIN_INSTANCE",[3410,13475,7352],{"class":6300},[3410,13477,4400],{"class":4399},[3410,13479,4404],{"class":4403},[3410,13481,9271],{"class":4403},[3410,13483,4411],{"class":4410},[3410,13485,13486,13488,13491],{"class":3412,"line":5692},[3410,13487,9279],{"class":4416},[3410,13489,13490],{"class":6538}," $WIN_AMI",[3410,13492,4411],{"class":4410},[3410,13494,13495,13497,13500],{"class":3412,"line":9097},[3410,13496,9290],{"class":4416},[3410,13498,13499],{"class":4403}," t3.medium",[3410,13501,4411],{"class":4410},[3410,13503,13504,13506,13508],{"class":3412,"line":9109},[3410,13505,9191],{"class":4416},[3410,13507,9194],{"class":4403},[3410,13509,4411],{"class":4410},[3410,13511,13512,13514,13516],{"class":3412,"line":9114},[3410,13513,9310],{"class":4416},[3410,13515,13388],{"class":6538},[3410,13517,4411],{"class":4410},[3410,13519,13520,13522,13524],{"class":3412,"line":9120},[3410,13521,6606],{"class":4416},[3410,13523,8833],{"class":4403},[3410,13525,4411],{"class":4410},[3410,13527,13528,13530,13533],{"class":3412,"line":9131},[3410,13529,9329],{"class":4416},[3410,13531,13532],{"class":4403}," 'ResourceType=instance,Tags=[{Key=Name,Value=windows-iis-server}]'",[3410,13534,4411],{"class":4410},[3410,13536,13537,13539,13541,13543,13545],{"class":3412,"line":9140},[3410,13538,4438],{"class":4416},[3410,13540,9342],{"class":4403},[3410,13542,8892],{"class":4416},[3410,13544,4451],{"class":4403},[3410,13546,7378],{"class":6300},[3410,13548,13549,13551,13554,13557],{"class":3412,"line":9154},[3410,13550,6953],{"class":4399},[3410,13552,13553],{"class":4403}," \"Windows Instance: ",[3410,13555,13556],{"class":6538},"$WIN_INSTANCE",[3410,13558,8848],{"class":4403},[3547,13560],{},[3584,13562,13564],{"id":13563},"крок-2-отримання-пароля-адміністратора-та-підключення-через-rdp","Крок 2: Отримання пароля адміністратора та підключення через RDP",[3348,13566,13567,13568,13571],{},"Windows EC2 використовує ",[3366,13569,13570],{},"RDP (Remote Desktop Protocol)"," замість SSH. Пароль адміністратора генерується автоматично і шифрується вашим SSH ключем.",[3348,13573,13574,13577,13578,13581],{},[3366,13575,13576],{},"Важливо:"," пароль стає доступним лише через ",[3366,13579,13580],{},"4–15 хвилин"," після запуску instance (Windows завершує ініціалізацію).",[7643,13583,13584,13640],{},[7646,13585,13586],{"label":7648},[7586,13587,13588,13602,13611,13617,13632],{},[3622,13589,9476,13590,3994,13592,3994,13594,3994,13596,3994,13599],{},[3366,13591,8613],{},[3407,13593,13123],{},[3366,13595,11086],{},[3366,13597,13598],{},"Security",[3366,13600,13601],{},"Get Windows password",[3622,13603,8634,13604,13607,13608],{},[3366,13605,13606],{},"Upload private key file"," → завантажте ваш ",[3407,13609,13610],{},"ec2-lab-key.pem",[3622,13612,8634,13613,13616],{},[3366,13614,13615],{},"Decrypt password"," → скопіюйте пароль",[3622,13618,13619,8112,13621,3994,13624,13627,13628,13631],{},[3366,13620,8111],{},[3366,13622,13623],{},"RDP client",[3366,13625,13626],{},"Download remote desktop file"," (завантажить ",[3407,13629,13630],{},".rdp"," файл)",[3622,13633,8606,13634,13636,13637,7086],{},[3407,13635,13630],{}," файл → введіть пароль (логін: ",[3407,13638,13639],{},"Administrator",[7646,13641,13642,13810],{"label":7694},[3400,13643,13645],{"className":4390,"code":13644,"language":4392,"meta":3405,"style":3405},"# Отримати зашифрований пароль (ЗАМІНІТЬ Instance ID)\nENCRYPTED_PASS=$(aws ec2 get-password-data \\\n    --instance-id $WIN_INSTANCE \\\n    --region eu-central-1 \\\n    --query \"PasswordData\" --output text)\n\n# Розшифрувати пароль за допомогою приватного ключа\necho \"$ENCRYPTED_PASS\" | base64 -d | openssl rsautl \\\n    -decrypt -inkey ~\u002F.ssh\u002Fec2-lab-key.pem\n\n# Отримати публічний IP для підключення\nWIN_IP=$(aws ec2 describe-instances \\\n    --instance-ids $WIN_INSTANCE \\\n    --query \"Reservations[0].Instances[0].PublicIpAddress\" \\\n    --output text --region eu-central-1)\necho \"Windows Server IP: $WIN_IP\"\n",[3407,13646,13647,13652,13668,13677,13685,13698,13702,13707,13736,13746,13750,13755,13770,13778,13786,13798],{"__ignoreMap":3405},[3410,13648,13649],{"class":3412,"line":3413},[3410,13650,13651],{"class":4462},"# Отримати зашифрований пароль (ЗАМІНІТЬ Instance ID)\n",[3410,13653,13654,13657,13659,13661,13663,13666],{"class":3412,"line":3419},[3410,13655,13656],{"class":6538},"ENCRYPTED_PASS",[3410,13658,7352],{"class":6300},[3410,13660,4400],{"class":4399},[3410,13662,4404],{"class":4403},[3410,13664,13665],{"class":4403}," get-password-data",[3410,13667,4411],{"class":4410},[3410,13669,13670,13672,13675],{"class":3412,"line":3425},[3410,13671,7888],{"class":4416},[3410,13673,13674],{"class":6538}," $WIN_INSTANCE",[3410,13676,4411],{"class":4410},[3410,13678,13679,13681,13683],{"class":3412,"line":3431},[3410,13680,6606],{"class":4416},[3410,13682,8833],{"class":4403},[3410,13684,4411],{"class":4410},[3410,13686,13687,13689,13692,13694,13696],{"class":3412,"line":3438},[3410,13688,4438],{"class":4416},[3410,13690,13691],{"class":4403}," \"PasswordData\"",[3410,13693,8892],{"class":4416},[3410,13695,4451],{"class":4403},[3410,13697,7378],{"class":6300},[3410,13699,13700],{"class":3412,"line":3444},[3410,13701,3435],{"emptyLinePlaceholder":3434},[3410,13703,13704],{"class":3412,"line":3450},[3410,13705,13706],{"class":4462},"# Розшифрувати пароль за допомогою приватного ключа\n",[3410,13708,13709,13711,13714,13717,13719,13721,13724,13726,13728,13731,13734],{"class":3412,"line":3456},[3410,13710,6953],{"class":4399},[3410,13712,13713],{"class":4403}," \"",[3410,13715,13716],{"class":6538},"$ENCRYPTED_PASS",[3410,13718,7089],{"class":4403},[3410,13720,7092],{"class":6300},[3410,13722,13723],{"class":4399},"base64",[3410,13725,12266],{"class":4416},[3410,13727,7092],{"class":6300},[3410,13729,13730],{"class":4399},"openssl",[3410,13732,13733],{"class":4403}," rsautl",[3410,13735,4411],{"class":4410},[3410,13737,13738,13741,13744],{"class":3412,"line":3462},[3410,13739,13740],{"class":4416},"    -decrypt",[3410,13742,13743],{"class":4416}," -inkey",[3410,13745,9245],{"class":4403},[3410,13747,13748],{"class":3412,"line":3468},[3410,13749,3435],{"emptyLinePlaceholder":3434},[3410,13751,13752],{"class":3412,"line":3474},[3410,13753,13754],{"class":4462},"# Отримати публічний IP для підключення\n",[3410,13756,13757,13760,13762,13764,13766,13768],{"class":3412,"line":3480},[3410,13758,13759],{"class":6538},"WIN_IP",[3410,13761,7352],{"class":6300},[3410,13763,4400],{"class":4399},[3410,13765,4404],{"class":4403},[3410,13767,9518],{"class":4403},[3410,13769,4411],{"class":4410},[3410,13771,13772,13774,13776],{"class":3412,"line":3486},[3410,13773,9525],{"class":4416},[3410,13775,13674],{"class":6538},[3410,13777,4411],{"class":4410},[3410,13779,13780,13782,13784],{"class":3412,"line":3491},[3410,13781,4438],{"class":4416},[3410,13783,9536],{"class":4403},[3410,13785,4411],{"class":4410},[3410,13787,13788,13790,13792,13794,13796],{"class":3412,"line":3497},[3410,13789,4448],{"class":4416},[3410,13791,4451],{"class":4403},[3410,13793,4454],{"class":4416},[3410,13795,8833],{"class":4403},[3410,13797,7378],{"class":6300},[3410,13799,13800,13802,13805,13808],{"class":3412,"line":3503},[3410,13801,6953],{"class":4399},[3410,13803,13804],{"class":4403}," \"Windows Server IP: ",[3410,13806,13807],{"class":6538},"$WIN_IP",[3410,13809,8848],{"class":4403},[4876,13811,13813,13822,13829,13832,13841],{"title":13812},"декодування пароля Windows Server та отримання IP",[4880,13814,13816,3572,13819],{"className":13815},[3412],[3410,13817,4887],{"className":13818},[4886],[3366,13820,13821],{},"echo \"$ENCRYPTED_PASS\" | base64 -d | openssl rsautl -decrypt -inkey ~\u002F.ssh\u002Fec2-lab-key.pem",[4880,13823,13825],{"className":13824},[3412],[3410,13826,13828],{"className":13827},[4926],"Str0ngP@ssw0rd!",[4880,13830],{"className":13831},[3412],[4880,13833,13835,3572,13838],{"className":13834},[3412],[3410,13836,4887],{"className":13837},[4886],[3366,13839,13840],{},"echo \"Windows Server IP: $WIN_IP\"",[4880,13842,13844],{"className":13843},[3412],[3410,13845,13847],{"className":13846},[4926],"Windows Server IP: 52.29.45.178",[3348,13849,13850],{},"Підключення через RDP (замініть IP та пароль):",[3619,13852,13853,13859],{},[3622,13854,13855,13858],{},[3366,13856,13857],{},"Windows:"," відкрийте «Remote Desktop Connection» → введіть IP",[3622,13860,13861,13864],{},[3366,13862,13863],{},"Mac:"," встановіть «Microsoft Remote Desktop» з App Store → New Connection",[3348,13866,13867],{},"::",[3348,13869,13867],{},[3547,13871],{},[3584,13873,13875],{"id":13874},"крок-3-встановлення-iis-та-net-10-hosting-bundle-на-windows-server","Крок 3: Встановлення IIS та .NET 10 Hosting Bundle на Windows Server",[3348,13877,13878,13879,13882],{},"Після підключення через RDP ви бачите звичайний робочий стіл Windows Server. Відкрийте ",[3366,13880,13881],{},"PowerShell"," від імені адміністратора:",[3400,13884,13886],{"className":6976,"code":13885,"language":6978,"meta":3405,"style":3405},"# Встановити IIS (Internet Information Services) — веб-сервер Microsoft\n# Web-Server — базовий IIS\n# Web-Asp-Net45 — підтримка ASP.NET\n# Web-Mgmt-Console — графічний менеджер IIS\nInstall-WindowsFeature -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console `\n    -IncludeManagementTools -Restart:$false\n",[3407,13887,13888,13893,13898,13903,13908,13915],{"__ignoreMap":3405},[3410,13889,13890],{"class":3412,"line":3413},[3410,13891,13892],{"class":4462},"# Встановити IIS (Internet Information Services) — веб-сервер Microsoft\n",[3410,13894,13895],{"class":3412,"line":3419},[3410,13896,13897],{"class":4462},"# Web-Server — базовий IIS\n",[3410,13899,13900],{"class":3412,"line":3425},[3410,13901,13902],{"class":4462},"# Web-Asp-Net45 — підтримка ASP.NET\n",[3410,13904,13905],{"class":3412,"line":3431},[3410,13906,13907],{"class":4462},"# Web-Mgmt-Console — графічний менеджер IIS\n",[3410,13909,13910,13912],{"class":3412,"line":3438},[3410,13911,7060],{"class":4399},[3410,13913,13914],{"class":6300}," -Name Web-Server, Web-Asp-Net45, Web-Mgmt-Console `\n",[3410,13916,13917,13920],{"class":3412,"line":3444},[3410,13918,13919],{"class":6300},"    -IncludeManagementTools -Restart:",[3410,13921,13922],{"class":4416},"$false\n",[4876,13924,13926,13930,13934],{"title":13925},"Встановлення IIS",[4880,13927,13929],{"className":13928},[3412],"Success Restart Needed Exit Code Feature Result",[4880,13931,13933],{"className":13932},[3412],"------- -------------- --------- --------------",[4880,13935,13937,13941],{"className":13936},[3412],[3410,13938,13940],{"className":13939},[4926],"True    No             Success","   {Common HTTP Features, Default Document...}",[3400,13943,13945],{"className":6976,"code":13944,"language":6978,"meta":3405,"style":3405},"# Завантажити та встановити .NET 10 ASP.NET Core Hosting Bundle\n# Hosting Bundle включає: .NET Runtime + ASP.NET Core Runtime + IIS Module\n$url = \"https:\u002F\u002Fdownload.microsoft.com\u002Fdownload\u002Fdotnet\u002F10.0\u002Fdotnet-hosting-10.0.0-win.exe\"\n$installer = \"$env:TEMP\\dotnet-hosting-10.0.0-win.exe\"\n\nWrite-Host \"Завантажуємо .NET 10 Hosting Bundle...\"\nInvoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing\n\nWrite-Host \"Встановлюємо...\"\n# \u002Fquiet — без GUI, \u002Fnorestart — без автоматичного рестарту\nStart-Process -FilePath $installer -ArgumentList \"\u002Fquiet \u002Fnorestart\" -Wait\n\nWrite-Host \"Перезапускаємо IIS...\"\nnet stop was \u002Fy\nnet start w3svc\n\nWrite-Host \"Перевірка встановлення:\"\ndotnet --version\n",[3407,13946,13947,13952,13957,13966,13980,13984,13992,14007,14011,14018,14023,14037,14041,14048,14053,14058,14062,14069],{"__ignoreMap":3405},[3410,13948,13949],{"class":3412,"line":3413},[3410,13950,13951],{"class":4462},"# Завантажити та встановити .NET 10 ASP.NET Core Hosting Bundle\n",[3410,13953,13954],{"class":3412,"line":3419},[3410,13955,13956],{"class":4462},"# Hosting Bundle включає: .NET Runtime + ASP.NET Core Runtime + IIS Module\n",[3410,13958,13959,13961,13963],{"class":3412,"line":3425},[3410,13960,6995],{"class":6538},[3410,13962,6998],{"class":6300},[3410,13964,13965],{"class":4403},"\"https:\u002F\u002Fdownload.microsoft.com\u002Fdownload\u002Fdotnet\u002F10.0\u002Fdotnet-hosting-10.0.0-win.exe\"\n",[3410,13967,13968,13970,13972,13974,13977],{"class":3412,"line":3431},[3410,13969,7006],{"class":6538},[3410,13971,6998],{"class":6300},[3410,13973,7089],{"class":4403},[3410,13975,13976],{"class":6538},"$env:TEMP",[3410,13978,13979],{"class":4403},"\\dotnet-hosting-10.0.0-win.exe\"\n",[3410,13981,13982],{"class":3412,"line":3438},[3410,13983,3435],{"emptyLinePlaceholder":3434},[3410,13985,13986,13989],{"class":3412,"line":3444},[3410,13987,13988],{"class":4399},"Write-Host",[3410,13990,13991],{"class":4403}," \"Завантажуємо .NET 10 Hosting Bundle...\"\n",[3410,13993,13994,13996,13998,14000,14002,14004],{"class":3412,"line":3450},[3410,13995,7016],{"class":4399},[3410,13997,7019],{"class":6300},[3410,13999,6995],{"class":6538},[3410,14001,7024],{"class":6300},[3410,14003,7006],{"class":6538},[3410,14005,14006],{"class":6300}," -UseBasicParsing\n",[3410,14008,14009],{"class":3412,"line":3456},[3410,14010,3435],{"emptyLinePlaceholder":3434},[3410,14012,14013,14015],{"class":3412,"line":3462},[3410,14014,13988],{"class":4399},[3410,14016,14017],{"class":4403}," \"Встановлюємо...\"\n",[3410,14019,14020],{"class":3412,"line":3468},[3410,14021,14022],{"class":4462},"# \u002Fquiet — без GUI, \u002Fnorestart — без автоматичного рестарту\n",[3410,14024,14025,14027,14029,14031,14033,14035],{"class":3412,"line":3474},[3410,14026,7032],{"class":4399},[3410,14028,7035],{"class":6300},[3410,14030,7006],{"class":6538},[3410,14032,7040],{"class":6300},[3410,14034,7043],{"class":4403},[3410,14036,7046],{"class":6300},[3410,14038,14039],{"class":3412,"line":3480},[3410,14040,3435],{"emptyLinePlaceholder":3434},[3410,14042,14043,14045],{"class":3412,"line":3486},[3410,14044,13988],{"class":4399},[3410,14046,14047],{"class":4403}," \"Перезапускаємо IIS...\"\n",[3410,14049,14050],{"class":3412,"line":3491},[3410,14051,14052],{"class":6300},"net stop was \u002Fy\n",[3410,14054,14055],{"class":3412,"line":3497},[3410,14056,14057],{"class":6300},"net start w3svc\n",[3410,14059,14060],{"class":3412,"line":3503},[3410,14061,3435],{"emptyLinePlaceholder":3434},[3410,14063,14064,14066],{"class":3412,"line":3508},[3410,14065,13988],{"class":4399},[3410,14067,14068],{"class":4403}," \"Перевірка встановлення:\"\n",[3410,14070,14071],{"class":3412,"line":3513},[3410,14072,14073],{"class":6300},"dotnet --version\n",[3547,14075],{},[3584,14077,14079],{"id":14078},"крок-4-публікація-та-деплой-на-iis","Крок 4: Публікація та деплой на IIS",[3348,14081,9825,14082,14084],{},[3366,14083,9828],{}," (створіть або використайте той самий проєкт):",[3400,14086,14088],{"className":4390,"code":14087,"language":4392,"meta":3405,"style":3405},"# Публікуємо для Windows\ndotnet publish -c Release -r win-x64 --self-contained false -o .\u002Fpublish-win\n",[3407,14089,14090,14095],{"__ignoreMap":3405},[3410,14091,14092],{"class":3412,"line":3413},[3410,14093,14094],{"class":4462},"# Публікуємо для Windows\n",[3410,14096,14097,14099,14101,14103,14105,14107,14110,14112,14114,14116],{"class":3412,"line":3419},[3410,14098,9797],{"class":4399},[3410,14100,10112],{"class":4403},[3410,14102,10115],{"class":4416},[3410,14104,10118],{"class":4403},[3410,14106,10121],{"class":4416},[3410,14108,14109],{"class":4403}," win-x64",[3410,14111,10127],{"class":4416},[3410,14113,10130],{"class":4416},[3410,14115,10133],{"class":4416},[3410,14117,14118],{"class":4403}," .\u002Fpublish-win\n",[3348,14120,14121,14122,14125],{},"Скопіюйте папку ",[3407,14123,14124],{},"publish-win"," на Windows Server. Варіанти:",[3619,14127,14128,14131],{},[3622,14129,14130],{},"Через RDP — просто перетягніть папку у вікно RDP (якщо включено clipboard)",[3622,14132,14133],{},"Через S3: завантажте в S3 bucket і завантажте через PowerShell на сервері",[3348,14135,14136],{},[3366,14137,14138],{},"Через S3 (рекомендовано):",[3400,14140,14142],{"className":4390,"code":14141,"language":4392,"meta":3405,"style":3405},"# На локальному комп'ютері — завантажте в S3\n# ЗАМІНІТЬ your-bucket-name на ваш S3 bucket (або створіть через Console)\naws s3 sync .\u002Fpublish-win s3:\u002F\u002Fyour-bucket-name\u002Fec2lab-api\u002F\n",[3407,14143,14144,14149,14154],{"__ignoreMap":3405},[3410,14145,14146],{"class":3412,"line":3413},[3410,14147,14148],{"class":4462},"# На локальному комп'ютері — завантажте в S3\n",[3410,14150,14151],{"class":3412,"line":3419},[3410,14152,14153],{"class":4462},"# ЗАМІНІТЬ your-bucket-name на ваш S3 bucket (або створіть через Console)\n",[3410,14155,14156,14158,14161,14164,14167],{"class":3412,"line":3425},[3410,14157,4400],{"class":4399},[3410,14159,14160],{"class":4403}," s3",[3410,14162,14163],{"class":4403}," sync",[3410,14165,14166],{"class":4403}," .\u002Fpublish-win",[3410,14168,14169],{"class":4403}," s3:\u002F\u002Fyour-bucket-name\u002Fec2lab-api\u002F\n",[3348,14171,14172],{},"На Windows Server (PowerShell):",[3400,14174,14176],{"className":6976,"code":14175,"language":6978,"meta":3405,"style":3405},"# Завантажити з S3 (AWS SDK вбудований у PowerShell на Amazon AMI)\n# ЗАМІНІТЬ your-bucket-name\n$destPath = \"C:\\inetpub\\ec2lab-api\"\nNew-Item -ItemType Directory -Path $destPath -Force\n\n# Якщо немає AWS CLI — встановіть\n# Invoke-WebRequest \"https:\u002F\u002Fawscli.amazonaws.com\u002FAWSCLIV2.msi\" -OutFile \"$env:TEMP\\AWSCLIV2.msi\"\n# Start-Process msiexec.exe -Wait -ArgumentList \"\u002FI $env:TEMP\\AWSCLIV2.msi \u002Fquiet\"\n\naws s3 sync s3:\u002F\u002Fyour-bucket-name\u002Fec2lab-api\u002F $destPath\n",[3407,14177,14178,14183,14188,14198,14211,14215,14220,14225,14230,14234],{"__ignoreMap":3405},[3410,14179,14180],{"class":3412,"line":3413},[3410,14181,14182],{"class":4462},"# Завантажити з S3 (AWS SDK вбудований у PowerShell на Amazon AMI)\n",[3410,14184,14185],{"class":3412,"line":3419},[3410,14186,14187],{"class":4462},"# ЗАМІНІТЬ your-bucket-name\n",[3410,14189,14190,14193,14195],{"class":3412,"line":3425},[3410,14191,14192],{"class":6538},"$destPath",[3410,14194,6998],{"class":6300},[3410,14196,14197],{"class":4403},"\"C:\\inetpub\\ec2lab-api\"\n",[3410,14199,14200,14203,14206,14208],{"class":3412,"line":3431},[3410,14201,14202],{"class":4399},"New-Item",[3410,14204,14205],{"class":6300}," -ItemType Directory -Path ",[3410,14207,14192],{"class":6538},[3410,14209,14210],{"class":6300}," -Force\n",[3410,14212,14213],{"class":3412,"line":3438},[3410,14214,3435],{"emptyLinePlaceholder":3434},[3410,14216,14217],{"class":3412,"line":3444},[3410,14218,14219],{"class":4462},"# Якщо немає AWS CLI — встановіть\n",[3410,14221,14222],{"class":3412,"line":3450},[3410,14223,14224],{"class":4462},"# Invoke-WebRequest \"https:\u002F\u002Fawscli.amazonaws.com\u002FAWSCLIV2.msi\" -OutFile \"$env:TEMP\\AWSCLIV2.msi\"\n",[3410,14226,14227],{"class":3412,"line":3456},[3410,14228,14229],{"class":4462},"# Start-Process msiexec.exe -Wait -ArgumentList \"\u002FI $env:TEMP\\AWSCLIV2.msi \u002Fquiet\"\n",[3410,14231,14232],{"class":3412,"line":3462},[3410,14233,3435],{"emptyLinePlaceholder":3434},[3410,14235,14236,14239],{"class":3412,"line":3468},[3410,14237,14238],{"class":6300},"aws s3 sync s3:\u002F\u002Fyour-bucket-name\u002Fec2lab-api\u002F ",[3410,14240,14241],{"class":6538},"$destPath\n",[3348,14243,14244],{},"Налаштуйте сайт у IIS через PowerShell:",[3400,14246,14248],{"className":6976,"code":14247,"language":6978,"meta":3405,"style":3405},"Import-Module WebAdministration\n\n# Створіть Application Pool для .NET 10\nNew-WebAppPool -Name \"Ec2LabApiPool\"\n$pool = Get-Item \"IIS:\\AppPools\\Ec2LabApiPool\"\n$pool.managedRuntimeVersion = \"\"  # No Managed Code (для .NET Core\u002F10)\n$pool | Set-Item\n\n# Видаліть Default Web Site (якщо є)\nRemove-Website -Name \"Default Web Site\" -ErrorAction SilentlyContinue\n\n# Створіть новий сайт\nNew-Website -Name \"Ec2LabApi\" `\n    -Port 80 `\n    -PhysicalPath \"C:\\inetpub\\ec2lab-api\" `\n    -ApplicationPool \"Ec2LabApiPool\"\n\n# Запустіть сайт\nStart-Website -Name \"Ec2LabApi\"\n\nWrite-Host \"Сайт запущено! Перейдіть: http:\u002F\u002Flocalhost\"\n",[3407,14249,14250,14258,14262,14267,14278,14291,14306,14315,14319,14324,14337,14341,14346,14359,14368,14378,14385,14389,14394,14404,14408],{"__ignoreMap":3405},[3410,14251,14252,14255],{"class":3412,"line":3413},[3410,14253,14254],{"class":4399},"Import-Module",[3410,14256,14257],{"class":6300}," WebAdministration\n",[3410,14259,14260],{"class":3412,"line":3419},[3410,14261,3435],{"emptyLinePlaceholder":3434},[3410,14263,14264],{"class":3412,"line":3425},[3410,14265,14266],{"class":4462},"# Створіть Application Pool для .NET 10\n",[3410,14268,14269,14272,14275],{"class":3412,"line":3431},[3410,14270,14271],{"class":4399},"New-WebAppPool",[3410,14273,14274],{"class":6300}," -Name ",[3410,14276,14277],{"class":4403},"\"Ec2LabApiPool\"\n",[3410,14279,14280,14283,14285,14288],{"class":3412,"line":3438},[3410,14281,14282],{"class":6538},"$pool",[3410,14284,6998],{"class":6300},[3410,14286,14287],{"class":4399},"Get-Item",[3410,14289,14290],{"class":4403}," \"IIS:\\AppPools\\Ec2LabApiPool\"\n",[3410,14292,14293,14295,14298,14300,14303],{"class":3412,"line":3444},[3410,14294,14282],{"class":6538},[3410,14296,14297],{"class":4399},".managedRuntimeVersion",[3410,14299,6998],{"class":6300},[3410,14301,14302],{"class":4403},"\"\"",[3410,14304,14305],{"class":4462},"  # No Managed Code (для .NET Core\u002F10)\n",[3410,14307,14308,14310,14312],{"class":3412,"line":3450},[3410,14309,14282],{"class":6538},[3410,14311,7092],{"class":6300},[3410,14313,14314],{"class":4399},"Set-Item\n",[3410,14316,14317],{"class":3412,"line":3456},[3410,14318,3435],{"emptyLinePlaceholder":3434},[3410,14320,14321],{"class":3412,"line":3462},[3410,14322,14323],{"class":4462},"# Видаліть Default Web Site (якщо є)\n",[3410,14325,14326,14329,14331,14334],{"class":3412,"line":3468},[3410,14327,14328],{"class":4399},"Remove-Website",[3410,14330,14274],{"class":6300},[3410,14332,14333],{"class":4403},"\"Default Web Site\"",[3410,14335,14336],{"class":6300}," -ErrorAction SilentlyContinue\n",[3410,14338,14339],{"class":3412,"line":3474},[3410,14340,3435],{"emptyLinePlaceholder":3434},[3410,14342,14343],{"class":3412,"line":3480},[3410,14344,14345],{"class":4462},"# Створіть новий сайт\n",[3410,14347,14348,14351,14353,14356],{"class":3412,"line":3486},[3410,14349,14350],{"class":4399},"New-Website",[3410,14352,14274],{"class":6300},[3410,14354,14355],{"class":4403},"\"Ec2LabApi\"",[3410,14357,14358],{"class":6300}," `\n",[3410,14360,14361,14364,14366],{"class":3412,"line":3491},[3410,14362,14363],{"class":6300},"    -Port ",[3410,14365,12013],{"class":4420},[3410,14367,14358],{"class":6300},[3410,14369,14370,14373,14376],{"class":3412,"line":3497},[3410,14371,14372],{"class":6300},"    -PhysicalPath ",[3410,14374,14375],{"class":4403},"\"C:\\inetpub\\ec2lab-api\"",[3410,14377,14358],{"class":6300},[3410,14379,14380,14383],{"class":3412,"line":3503},[3410,14381,14382],{"class":6300},"    -ApplicationPool ",[3410,14384,14277],{"class":4403},[3410,14386,14387],{"class":3412,"line":3508},[3410,14388,3435],{"emptyLinePlaceholder":3434},[3410,14390,14391],{"class":3412,"line":3513},[3410,14392,14393],{"class":4462},"# Запустіть сайт\n",[3410,14395,14396,14399,14401],{"class":3412,"line":3519},[3410,14397,14398],{"class":4399},"Start-Website",[3410,14400,14274],{"class":6300},[3410,14402,14403],{"class":4403},"\"Ec2LabApi\"\n",[3410,14405,14406],{"class":3412,"line":3524},[3410,14407,3435],{"emptyLinePlaceholder":3434},[3410,14409,14410,14412],{"class":3412,"line":3530},[3410,14411,13988],{"class":4399},[3410,14413,14414],{"class":4403}," \"Сайт запущено! Перейдіть: http:\u002F\u002Flocalhost\"\n",[3348,14416,14417,14418],{},"Перевірте у браузері на вашому комп'ютері: ",[3407,14419,14420],{},"http:\u002F\u002FWINDOWS_IP\u002F",[3547,14422],{},[3584,14424,14426],{"id":14425},"крок-5-створення-custom-ami","Крок 5: Створення Custom AMI",[3348,14428,14429],{},"Тепер, коли сервер налаштований (встановлений .NET, IIS, задеплоєний додаток) — створимо AMI. Це дозволить у майбутньому запускати новий сервер з тим самим станом без повторного встановлення.",[7643,14431,14432,14488],{},[7646,14433,14434],{"label":7648},[7586,14435,14436,14449,14457,14465,14471,14475],{},[3622,14437,9476,14438,14440,14441,3994,14443,3994,14446],{},[3366,14439,8613],{}," → оберіть instance → ",[3366,14442,11086],{},[3366,14444,14445],{},"Image and templates",[3366,14447,14448],{},"Create image",[3622,14450,14451,3572,14454],{},[3366,14452,14453],{},"Image name:",[3407,14455,14456],{},"dotnet-iis-ready-v1",[3622,14458,14459,3572,14462],{},[3366,14460,14461],{},"Image description:",[3407,14463,14464],{},"Windows Server 2022 + IIS + .NET 10 Hosting Bundle",[3622,14466,14467,14470],{},[3366,14468,14469],{},"No reboot:"," можна залишити unchecked (перезавантаження гарантує консистентність)",[3622,14472,14473],{},[3366,14474,14448],{},[3622,14476,14477,14478,14481,14482,14484,14485],{},"Прогрес: EC2 → ",[3366,14479,14480],{},"AMIs"," → ваша AMI буде у стані ",[3407,14483,9401],{}," → за 5–15 хвилин стане ",[3407,14486,14487],{},"available",[7646,14489,14490],{"label":7694},[3400,14491,14493],{"className":4390,"code":14492,"language":4392,"meta":3405,"style":3405},"# ЗАМІНІТЬ Instance ID на ваш реальний\naws ec2 create-image \\\n    --instance-id i-1234567890abcdef0 \\\n    --name \"dotnet-iis-ready-v1\" \\\n    --description \"Windows Server 2022 + IIS + .NET 10 Hosting Bundle\" \\\n    --region eu-central-1\n\n# Перевірити статус AMI (виконайте через кілька хвилин)\naws ec2 describe-images \\\n    --owners self \\\n    --filters \"Name=name,Values=dotnet-iis-ready-v1\" \\\n    --query \"Images[0].{ID:ImageId,State:State}\" \\\n    --output table --region eu-central-1\n",[3407,14494,14495,14500,14511,14520,14530,14539,14545,14549,14554,14564,14573,14582,14591],{"__ignoreMap":3405},[3410,14496,14497],{"class":3412,"line":3413},[3410,14498,14499],{"class":4462},"# ЗАМІНІТЬ Instance ID на ваш реальний\n",[3410,14501,14502,14504,14506,14509],{"class":3412,"line":3419},[3410,14503,4400],{"class":4399},[3410,14505,4404],{"class":4403},[3410,14507,14508],{"class":4403}," create-image",[3410,14510,4411],{"class":4410},[3410,14512,14513,14515,14518],{"class":3412,"line":3425},[3410,14514,7888],{"class":4416},[3410,14516,14517],{"class":4403}," i-1234567890abcdef0",[3410,14519,4411],{"class":4410},[3410,14521,14522,14525,14528],{"class":3412,"line":3431},[3410,14523,14524],{"class":4416},"    --name",[3410,14526,14527],{"class":4403}," \"dotnet-iis-ready-v1\"",[3410,14529,4411],{"class":4410},[3410,14531,14532,14534,14537],{"class":3412,"line":3438},[3410,14533,8940],{"class":4416},[3410,14535,14536],{"class":4403}," \"Windows Server 2022 + IIS + .NET 10 Hosting Bundle\"",[3410,14538,4411],{"class":4410},[3410,14540,14541,14543],{"class":3412,"line":3444},[3410,14542,6606],{"class":4416},[3410,14544,4457],{"class":4403},[3410,14546,14547],{"class":3412,"line":3450},[3410,14548,3435],{"emptyLinePlaceholder":3434},[3410,14550,14551],{"class":3412,"line":3456},[3410,14552,14553],{"class":4462},"# Перевірити статус AMI (виконайте через кілька хвилин)\n",[3410,14555,14556,14558,14560,14562],{"class":3412,"line":3462},[3410,14557,4400],{"class":4399},[3410,14559,4404],{"class":4403},[3410,14561,4407],{"class":4403},[3410,14563,4411],{"class":4410},[3410,14565,14566,14568,14571],{"class":3412,"line":3468},[3410,14567,4417],{"class":4416},[3410,14569,14570],{"class":4403}," self",[3410,14572,4411],{"class":4410},[3410,14574,14575,14577,14580],{"class":3412,"line":3474},[3410,14576,4428],{"class":4416},[3410,14578,14579],{"class":4403}," \"Name=name,Values=dotnet-iis-ready-v1\"",[3410,14581,4411],{"class":4410},[3410,14583,14584,14586,14589],{"class":3412,"line":3480},[3410,14585,4438],{"class":4416},[3410,14587,14588],{"class":4403}," \"Images[0].{ID:ImageId,State:State}\"",[3410,14590,4411],{"class":4410},[3410,14592,14593,14595,14598,14600],{"class":3412,"line":3486},[3410,14594,4448],{"class":4416},[3410,14596,14597],{"class":4403}," table",[3410,14599,4454],{"class":4416},[3410,14601,4457],{"class":4403},[3547,14603],{},[3584,14605,14607],{"id":14606},"крок-6-обовязково-очищення-ресурсів","Крок 6: ОБОВ'ЯЗКОВО — Очищення ресурсів",[4003,14609,14610,14611,14613],{},"Windows Server EC2 (",[3407,14612,3607],{},") коштує ~$0.065\u002Fгод без зупинки — це ~$47\u002Fмісяць. Зупиніть або видаліть instance після завершення роботи!",[7643,14615,14616,14666],{},[7646,14617,14618],{"label":7648},[7586,14619,14620,14639,14647,14659],{},[3622,14621,9476,14622,14440,14624,3994,14627,14630],{},[3366,14623,8613],{},[3366,14625,14626],{},"Instance state",[3366,14628,14629],{},"Terminate instance",[3619,14631,14632],{},[3622,14633,14634,14635,14638],{},"Або ",[3366,14636,14637],{},"Stop instance"," якщо плануєте продовжити пізніше (за зупинений instance EBS ще тарифікується, але менше)",[3622,14640,14641,14642,3994,14644],{},"Якщо створювали Elastic IP — EC2 → ",[3366,14643,11074],{},[3366,14645,14646],{},"Release Elastic IP address",[3622,14648,14649,14650,14652,14653,3994,14655,14658],{},"AMI: EC2 → ",[3366,14651,14480],{}," → ваша AMI → ",[3366,14654,11086],{},[3366,14656,14657],{},"Deregister AMI"," (опціонально)",[3622,14660,14661,14662,14665],{},"EBS Snapshots від AMI: EC2 → ",[3366,14663,14664],{},"Snapshots"," → видаліть пов'язані",[7646,14667,14668],{"label":7694},[3400,14669,14671],{"className":4390,"code":14670,"language":4392,"meta":3405,"style":3405},"REGION=\"eu-central-1\"\n# ЗАМІНІТЬ на ваші реальні ID\n\n# Зупинити (платите лише за EBS)\naws ec2 stop-instances --instance-ids $INSTANCE_ID --region $REGION\n\n# Або видалити повністю\naws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION\n\n# Звільнити Elastic IP (якщо виділяли)\n# aws ec2 release-address --allocation-id eipalloc-xxx --region $REGION\n",[3407,14672,14673,14683,14688,14692,14697,14716,14720,14725,14742,14746,14751],{"__ignoreMap":3405},[3410,14674,14675,14678,14680],{"class":3412,"line":3413},[3410,14676,14677],{"class":6538},"REGION",[3410,14679,10398],{"class":6300},[3410,14681,14682],{"class":4403},"\"eu-central-1\"\n",[3410,14684,14685],{"class":3412,"line":3419},[3410,14686,14687],{"class":4462},"# ЗАМІНІТЬ на ваші реальні ID\n",[3410,14689,14690],{"class":3412,"line":3425},[3410,14691,3435],{"emptyLinePlaceholder":3434},[3410,14693,14694],{"class":3412,"line":3431},[3410,14695,14696],{"class":4462},"# Зупинити (платите лише за EBS)\n",[3410,14698,14699,14701,14703,14706,14709,14711,14713],{"class":3412,"line":3438},[3410,14700,4400],{"class":4399},[3410,14702,4404],{"class":4403},[3410,14704,14705],{"class":4403}," stop-instances",[3410,14707,14708],{"class":4416}," --instance-ids",[3410,14710,7891],{"class":6538},[3410,14712,4454],{"class":4416},[3410,14714,14715],{"class":6538}," $REGION\n",[3410,14717,14718],{"class":3412,"line":3444},[3410,14719,3435],{"emptyLinePlaceholder":3434},[3410,14721,14722],{"class":3412,"line":3450},[3410,14723,14724],{"class":4462},"# Або видалити повністю\n",[3410,14726,14727,14729,14731,14734,14736,14738,14740],{"class":3412,"line":3456},[3410,14728,4400],{"class":4399},[3410,14730,4404],{"class":4403},[3410,14732,14733],{"class":4403}," terminate-instances",[3410,14735,14708],{"class":4416},[3410,14737,7891],{"class":6538},[3410,14739,4454],{"class":4416},[3410,14741,14715],{"class":6538},[3410,14743,14744],{"class":3412,"line":3462},[3410,14745,3435],{"emptyLinePlaceholder":3434},[3410,14747,14748],{"class":3412,"line":3468},[3410,14749,14750],{"class":4462},"# Звільнити Elastic IP (якщо виділяли)\n",[3410,14752,14753],{"class":3412,"line":3474},[3410,14754,14755],{"class":4462},"# aws ec2 release-address --allocation-id eipalloc-xxx --region $REGION\n",[3547,14757],{},[3348,14759,14760],{},[3351,14761],{"alt":14762,"className":14763,"src":14764},"Dokploy self-hosted PaaS platform deployment automation Docker Traefik on EC2",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F17.png",[3358,14766,14768],{"id":14767},"практичний-приклад-dokploy-власна-paas-платформа-на-ec2","Практичний приклад: Dokploy — власна PaaS-платформа на EC2",[3348,14770,14771],{},"Попередні приклади показали «класичний» підхід деплою: SSH-підключення, ручне копіювання файлів через SCP, налаштування systemd-сервісів. Цей підхід прозорий і надійний, але вимагає значної ручної роботи при кожному оновленні застосунку — ви повинні перебудувати проєкт, скопіювати файли на сервер, перезапустити сервіс. З ростом кількості застосунків це перетворюється на рутинну операцію, яка займає час і відволікає від розробки.",[3348,14773,14774,14777],{},[3366,14775,14776],{},"Dokploy"," — це безкоштовна open-source PaaS-платформа (Platform as a Service), яку ви встановлюєте на власний EC2 instance. Після встановлення вона надає зручний веб-інтерфейс для деплою застосунків — схожий за концепцією на Heroku або Railway, але повністю під вашим контролем, без абонентської плати за платформу і без залежності від стороннього сервісу.",[3348,14779,14780],{},[3366,14781,14782],{},"Ключові можливості Dokploy:",[3619,14784,14785,14795,14801,14807,14813,14819,14825],{},[3622,14786,14787,14790,14791,14794],{},[3366,14788,14789],{},"Автоматичний деплой з GitHub"," — після кожного ",[3407,14792,14793],{},"git push"," застосунок автоматично перебудовується і перезапускається без вашої участі",[3622,14796,14797,14800],{},[3366,14798,14799],{},"SSL-сертифікати через Let's Encrypt"," — Traefik автоматично отримує та оновлює сертифікати, жодних скриптів не потрібно",[3622,14802,14803,14806],{},[3366,14804,14805],{},"Веб-інтерфейс для логів"," — переглядайте логи контейнерів прямо у браузері в реальному часі",[3622,14808,14809,14812],{},[3366,14810,14811],{},"Docker та Docker Compose"," — підтримка будь-якого стека: .NET, Node.js, Python, Go, PHP",[3622,14814,14815,14818],{},[3366,14816,14817],{},"Нульовий downtime"," — новий контейнер запускається до зупинки старого (rolling deploy)",[3622,14820,14821,14824],{},[3366,14822,14823],{},"Управління змінними середовища"," — зберігайте секрети та конфігурацію окремо від коду",[3622,14826,14827,14830],{},[3366,14828,14829],{},"Rollback одним кліком"," — повернення до будь-якої попередньої версії з повною історією деплоїв",[3348,14832,14833],{},"У цьому прикладі ми встановимо Dokploy на Ubuntu EC2, задеплоїмо ASP.NET Core API через GitHub repository та налаштуємо автоматичний CI\u002FCD.",[3397,14835,14836],{},[3400,14837,14839],{"className":3402,"code":14838,"language":3404,"meta":3405,"style":3405},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Розробник\" as DEV\n\nrectangle \"EC2 Instance (t3.medium)\\nUbuntu 26.04\" as EC2 #dbeafe {\n    rectangle \"Dokploy\\n:3000 (UI + API)\" as DOKPLOY #bbf7d0 {\n        rectangle \"Docker Engine\" as DOCKER #d1fae5\n        rectangle \"Traefik\\n:80 \u002F :443\" as TRAEFIK #fef3c7\n    }\n    rectangle \".NET API Container\\n:8080 (внутрішній)\" as APP #e0e7ff\n}\n\ncloud \"GitHub\\nRepository\" as GH #f3f4f6\nrectangle \"Let's Encrypt\\n(SSL)\" as LE #fde68a\nactor \"Користувач\" as USER\n\nDEV -right-> GH : git push\nGH -down-> DOKPLOY : webhook → auto deploy\nDOKPLOY -down-> DOCKER : docker build\nDOCKER -right-> APP : docker run\nTRAEFIK -down-> APP : proxy :443 → :8080\nLE -up-> TRAEFIK : TLS-сертифікат\nUSER -right-> TRAEFIK : https:\u002F\u002Fmyapi.pp.ua\n\nnote right of DOKPLOY\n  Встановлення — одна команда.\n  Dokploy UI доступний на :3000.\n  Traefik — вбудований reverse proxy\n  з автоматичним Let's Encrypt.\nend note\n@enduml\n",[3407,14840,14841,14845,14849,14853,14857,14862,14866,14871,14876,14881,14886,14890,14895,14899,14903,14908,14913,14918,14922,14927,14932,14937,14942,14947,14952,14957,14961,14966,14971,14976,14981,14986,14990],{"__ignoreMap":3405},[3410,14842,14843],{"class":3412,"line":3413},[3410,14844,3416],{},[3410,14846,14847],{"class":3412,"line":3419},[3410,14848,3422],{},[3410,14850,14851],{"class":3412,"line":3425},[3410,14852,3428],{},[3410,14854,14855],{"class":3412,"line":3431},[3410,14856,3435],{"emptyLinePlaceholder":3434},[3410,14858,14859],{"class":3412,"line":3438},[3410,14860,14861],{},"actor \"Розробник\" as DEV\n",[3410,14863,14864],{"class":3412,"line":3444},[3410,14865,3435],{"emptyLinePlaceholder":3434},[3410,14867,14868],{"class":3412,"line":3450},[3410,14869,14870],{},"rectangle \"EC2 Instance (t3.medium)\\nUbuntu 26.04\" as EC2 #dbeafe {\n",[3410,14872,14873],{"class":3412,"line":3456},[3410,14874,14875],{},"    rectangle \"Dokploy\\n:3000 (UI + API)\" as DOKPLOY #bbf7d0 {\n",[3410,14877,14878],{"class":3412,"line":3462},[3410,14879,14880],{},"        rectangle \"Docker Engine\" as DOCKER #d1fae5\n",[3410,14882,14883],{"class":3412,"line":3468},[3410,14884,14885],{},"        rectangle \"Traefik\\n:80 \u002F :443\" as TRAEFIK #fef3c7\n",[3410,14887,14888],{"class":3412,"line":3474},[3410,14889,3477],{},[3410,14891,14892],{"class":3412,"line":3480},[3410,14893,14894],{},"    rectangle \".NET API Container\\n:8080 (внутрішній)\" as APP #e0e7ff\n",[3410,14896,14897],{"class":3412,"line":3486},[3410,14898,3483],{},[3410,14900,14901],{"class":3412,"line":3491},[3410,14902,3435],{"emptyLinePlaceholder":3434},[3410,14904,14905],{"class":3412,"line":3497},[3410,14906,14907],{},"cloud \"GitHub\\nRepository\" as GH #f3f4f6\n",[3410,14909,14910],{"class":3412,"line":3503},[3410,14911,14912],{},"rectangle \"Let's Encrypt\\n(SSL)\" as LE #fde68a\n",[3410,14914,14915],{"class":3412,"line":3508},[3410,14916,14917],{},"actor \"Користувач\" as USER\n",[3410,14919,14920],{"class":3412,"line":3513},[3410,14921,3435],{"emptyLinePlaceholder":3434},[3410,14923,14924],{"class":3412,"line":3519},[3410,14925,14926],{},"DEV -right-> GH : git push\n",[3410,14928,14929],{"class":3412,"line":3524},[3410,14930,14931],{},"GH -down-> DOKPLOY : webhook → auto deploy\n",[3410,14933,14934],{"class":3412,"line":3530},[3410,14935,14936],{},"DOKPLOY -down-> DOCKER : docker build\n",[3410,14938,14939],{"class":3412,"line":3536},[3410,14940,14941],{},"DOCKER -right-> APP : docker run\n",[3410,14943,14944],{"class":3412,"line":3542},[3410,14945,14946],{},"TRAEFIK -down-> APP : proxy :443 → :8080\n",[3410,14948,14949],{"class":3412,"line":3891},[3410,14950,14951],{},"LE -up-> TRAEFIK : TLS-сертифікат\n",[3410,14953,14954],{"class":3412,"line":3897},[3410,14955,14956],{},"USER -right-> TRAEFIK : https:\u002F\u002Fmyapi.pp.ua\n",[3410,14958,14959],{"class":3412,"line":3903},[3410,14960,3435],{"emptyLinePlaceholder":3434},[3410,14962,14963],{"class":3412,"line":3909},[3410,14964,14965],{},"note right of DOKPLOY\n",[3410,14967,14968],{"class":3412,"line":3915},[3410,14969,14970],{},"  Встановлення — одна команда.\n",[3410,14972,14973],{"class":3412,"line":3921},[3410,14974,14975],{},"  Dokploy UI доступний на :3000.\n",[3410,14977,14978],{"class":3412,"line":5681},[3410,14979,14980],{},"  Traefik — вбудований reverse proxy\n",[3410,14982,14983],{"class":3412,"line":5687},[3410,14984,14985],{},"  з автоматичним Let's Encrypt.\n",[3410,14987,14988],{"class":3412,"line":5692},[3410,14989,3918],{},[3410,14991,14992],{"class":3412,"line":9097},[3410,14993,3545],{},[3584,14995,14997],{"id":14996},"крок-1-запуск-ec2-instance-для-dokploy","Крок 1: Запуск EC2 instance для Dokploy",[3348,14999,15000],{},"Dokploy запускає кілька Docker-контейнерів власної інфраструктури (застосунок, Traefik, PostgreSQL, Redis) ще до того, як ви задеплоїте перший сервіс. Тому мінімальні вимоги вищі, ніж для звичайного застосунку.",[4003,15002,15003,15005,15006,15009,15010,15012,15013,15015],{},[3407,15004,3581],{}," (1 GB RAM) ",[3366,15007,15008],{},"недостатньо"," для Dokploy. Під час встановлення або після нього система почне використовувати swap, контейнери зависатимуть. Мінімум — ",[3407,15011,3604],{}," (2 GB RAM) для одного-двох застосунків. Для комфортної роботи з кількома сервісами використовуйте ",[3407,15014,3607],{}," (4 GB RAM).",[7643,15017,15018,15178],{},[7646,15019,15020],{"label":7648},[7586,15021,15022,15026,15033,15051,15063,15071,15164,15174],{},[3622,15023,9476,15024],{},[3366,15025,8616],{},[3622,15027,15028,3572,15030],{},[3366,15029,8621],{},[3407,15031,15032],{},"dokploy-server",[3622,15034,15035,15037],{},[3366,15036,8629],{},[3619,15038,15039,15043,15047],{},[3622,15040,8634,15041,8638],{},[3366,15042,8637],{},[3622,15044,7686,15045],{},[3366,15046,8643],{},[3622,15048,8646,15049],{},[3366,15050,8649],{},[3622,15052,15053,3572,15055,3572,15057],{},[3366,15054,8654],{},[3407,15056,3607],{},[8752,15058,15059,15060,15062],{},"(рекомендовано; мінімум ",[3407,15061,3604],{}," для тестування)",[3622,15064,15065,13160,15067,13163,15069],{},[3366,15066,13159],{},[3407,15068,8678],{},[3407,15070,8262],{},[3622,15072,15073,15076],{},[3366,15074,15075],{},"Network settings → Edit → Create security group:",[3619,15077,15078,15083,15106,15126,15144],{},[3622,15079,8741,15080],{},[3407,15081,15082],{},"dokploy-sg",[3622,15084,15085,15088],{},[3366,15086,15087],{},"Правило 1 — SSH:",[3619,15089,15090],{},[3622,15091,15092,15093,15096,15097,15100,15101,3572,15103],{},"Type: ",[3366,15094,15095],{},"SSH",", Port: ",[3366,15098,15099],{},"22",", Source: ",[3366,15102,8750],{},[8752,15104,15105],{},"(лише ви)",[3622,15107,15108,15111],{},[3366,15109,15110],{},"Правило 2 — HTTP:",[3619,15112,15113],{},[3622,15114,15092,15115,15096,15118,15100,15120,3572,15123],{},[3366,15116,15117],{},"HTTP",[3366,15119,12013],{},[3366,15121,15122],{},"Anywhere",[8752,15124,15125],{},"(потрібно для Let's Encrypt верифікації та HTTP→HTTPS редиректу)",[3622,15127,15128,15131],{},[3366,15129,15130],{},"Правило 3 — HTTPS:",[3619,15132,15133],{},[3622,15134,15092,15135,15096,15137,15100,15139,3572,15141],{},[3366,15136,12051],{},[3366,15138,12017],{},[3366,15140,15122],{},[8752,15142,15143],{},"(основний трафік застосунків)",[3622,15145,15146,15149],{},[3366,15147,15148],{},"Правило 4 — Dokploy UI:",[3619,15150,15151],{},[3622,15152,15092,15153,15096,15156,15100,15159,3572,15161],{},[3366,15154,15155],{},"Custom TCP",[3366,15157,15158],{},"3000",[3366,15160,8750],{},[8752,15162,15163],{},"(веб-інтерфейс лише для адміністратора)",[3622,15165,15166,3572,15168,3572,15171],{},[3366,15167,8765],{},[3366,15169,15170],{},"30 GB gp3",[8752,15172,15173],{},"(Docker образи .NET займають ~2–3 GB кожен; 20 GB мінімум, 30 GB рекомендовано)",[3622,15175,8634,15176],{},[3366,15177,8771],{},[7646,15179,15180,15684],{"label":7694},[3400,15181,15183],{"className":4390,"code":15182,"language":4392,"meta":3405,"style":3405},"# Знайдіть Ubuntu 26.04 AMI\nAMI_ID=$(aws ec2 describe-images \\\n    --owners 099720109477 \\\n    --filters \"Name=name,Values=ubuntu\u002Fimages\u002Fhvm-ssd-gp3\u002Fubuntu-resolute-26.04-amd64-server-*\" \\\n    --query \"sort_by(Images, &CreationDate)[-1].ImageId\" \\\n    --output text --region eu-central-1)\necho \"AMI: $AMI_ID\"\n\n# Отримайте default VPC\nVPC_ID=$(aws ec2 describe-vpcs \\\n    --filters \"Name=isDefault,Values=true\" \\\n    --query \"Vpcs[0].VpcId\" --output text --region eu-central-1)\n\n# Створіть Security Group\nSG_ID=$(aws ec2 create-security-group \\\n    --group-name dokploy-sg \\\n    --description \"Dokploy PaaS Security Group\" \\\n    --vpc-id $VPC_ID \\\n    --region eu-central-1 \\\n    --query GroupId --output text)\n\n# Ваш поточний IP\nMY_IP=$(curl -s https:\u002F\u002Fcheckip.amazonaws.com)\n\n# SSH лише з вашого IP\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID --protocol tcp --port 22 \\\n    --cidr \"${MY_IP}\u002F32\" --region eu-central-1\n\n# HTTP публічно (Let's Encrypt + редирект)\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID --protocol tcp --port 80 \\\n    --cidr 0.0.0.0\u002F0 --region eu-central-1\n\n# HTTPS публічно (трафік застосунків)\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID --protocol tcp --port 443 \\\n    --cidr 0.0.0.0\u002F0 --region eu-central-1\n\n# Dokploy UI лише з вашого IP\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID --protocol tcp --port 3000 \\\n    --cidr \"${MY_IP}\u002F32\" --region eu-central-1\n\n# Запуск instance з 30 GB диском\nINSTANCE_ID=$(aws ec2 run-instances \\\n    --image-id $AMI_ID \\\n    --instance-type t3.medium \\\n    --key-name ec2-lab-key \\\n    --security-group-ids $SG_ID \\\n    --block-device-mappings '[{\"DeviceName\":\"\u002Fdev\u002Fsda1\",\"Ebs\":{\"VolumeSize\":30,\"VolumeType\":\"gp3\"}}]' \\\n    --region eu-central-1 \\\n    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=dokploy-server}]' \\\n    --query \"Instances[0].InstanceId\" --output text)\necho \"Instance: $INSTANCE_ID\"\n",[3407,15184,15185,15190,15204,15212,15220,15228,15240,15251,15255,15260,15274,15282,15298,15302,15307,15321,15330,15339,15347,15355,15367,15371,15376,15390,15394,15399,15409,15425,15439,15443,15448,15458,15474,15484,15488,15493,15503,15519,15529,15533,15538,15548,15565,15579,15583,15588,15602,15610,15618,15626,15634,15644,15652,15661,15673],{"__ignoreMap":3405},[3410,15186,15187],{"class":3412,"line":3413},[3410,15188,15189],{"class":4462},"# Знайдіть Ubuntu 26.04 AMI\n",[3410,15191,15192,15194,15196,15198,15200,15202],{"class":3412,"line":3419},[3410,15193,8788],{"class":6538},[3410,15195,7352],{"class":6300},[3410,15197,4400],{"class":4399},[3410,15199,4404],{"class":4403},[3410,15201,4407],{"class":4403},[3410,15203,4411],{"class":4410},[3410,15205,15206,15208,15210],{"class":3412,"line":3425},[3410,15207,4417],{"class":4416},[3410,15209,4421],{"class":4420},[3410,15211,4411],{"class":4410},[3410,15213,15214,15216,15218],{"class":3412,"line":3431},[3410,15215,4428],{"class":4416},[3410,15217,4431],{"class":4403},[3410,15219,4411],{"class":4410},[3410,15221,15222,15224,15226],{"class":3412,"line":3438},[3410,15223,4438],{"class":4416},[3410,15225,4441],{"class":4403},[3410,15227,4411],{"class":4410},[3410,15229,15230,15232,15234,15236,15238],{"class":3412,"line":3444},[3410,15231,4448],{"class":4416},[3410,15233,4451],{"class":4403},[3410,15235,4454],{"class":4416},[3410,15237,8833],{"class":4403},[3410,15239,7378],{"class":6300},[3410,15241,15242,15244,15247,15249],{"class":3412,"line":3450},[3410,15243,6953],{"class":4399},[3410,15245,15246],{"class":4403}," \"AMI: ",[3410,15248,8845],{"class":6538},[3410,15250,8848],{"class":4403},[3410,15252,15253],{"class":3412,"line":3456},[3410,15254,3435],{"emptyLinePlaceholder":3434},[3410,15256,15257],{"class":3412,"line":3462},[3410,15258,15259],{"class":4462},"# Отримайте default VPC\n",[3410,15261,15262,15264,15266,15268,15270,15272],{"class":3412,"line":3468},[3410,15263,8862],{"class":6538},[3410,15265,7352],{"class":6300},[3410,15267,4400],{"class":4399},[3410,15269,4404],{"class":4403},[3410,15271,8871],{"class":4403},[3410,15273,4411],{"class":4410},[3410,15275,15276,15278,15280],{"class":3412,"line":3474},[3410,15277,4428],{"class":4416},[3410,15279,8880],{"class":4403},[3410,15281,4411],{"class":4410},[3410,15283,15284,15286,15288,15290,15292,15294,15296],{"class":3412,"line":3480},[3410,15285,4438],{"class":4416},[3410,15287,8889],{"class":4403},[3410,15289,8892],{"class":4416},[3410,15291,4451],{"class":4403},[3410,15293,4454],{"class":4416},[3410,15295,8833],{"class":4403},[3410,15297,7378],{"class":6300},[3410,15299,15300],{"class":3412,"line":3486},[3410,15301,3435],{"emptyLinePlaceholder":3434},[3410,15303,15304],{"class":3412,"line":3491},[3410,15305,15306],{"class":4462},"# Створіть Security Group\n",[3410,15308,15309,15311,15313,15315,15317,15319],{"class":3412,"line":3497},[3410,15310,8914],{"class":6538},[3410,15312,7352],{"class":6300},[3410,15314,4400],{"class":4399},[3410,15316,4404],{"class":4403},[3410,15318,8923],{"class":4403},[3410,15320,4411],{"class":4410},[3410,15322,15323,15325,15328],{"class":3412,"line":3503},[3410,15324,8930],{"class":4416},[3410,15326,15327],{"class":4403}," dokploy-sg",[3410,15329,4411],{"class":4410},[3410,15331,15332,15334,15337],{"class":3412,"line":3508},[3410,15333,8940],{"class":4416},[3410,15335,15336],{"class":4403}," \"Dokploy PaaS Security Group\"",[3410,15338,4411],{"class":4410},[3410,15340,15341,15343,15345],{"class":3412,"line":3513},[3410,15342,8950],{"class":4416},[3410,15344,8953],{"class":6538},[3410,15346,4411],{"class":4410},[3410,15348,15349,15351,15353],{"class":3412,"line":3519},[3410,15350,6606],{"class":4416},[3410,15352,8833],{"class":4403},[3410,15354,4411],{"class":4410},[3410,15356,15357,15359,15361,15363,15365],{"class":3412,"line":3524},[3410,15358,4438],{"class":4416},[3410,15360,8970],{"class":4403},[3410,15362,8892],{"class":4416},[3410,15364,4451],{"class":4403},[3410,15366,7378],{"class":6300},[3410,15368,15369],{"class":3412,"line":3530},[3410,15370,3435],{"emptyLinePlaceholder":3434},[3410,15372,15373],{"class":3412,"line":3536},[3410,15374,15375],{"class":4462},"# Ваш поточний IP\n",[3410,15377,15378,15380,15382,15384,15386,15388],{"class":3412,"line":3542},[3410,15379,8990],{"class":6538},[3410,15381,7352],{"class":6300},[3410,15383,7274],{"class":4399},[3410,15385,7325],{"class":4416},[3410,15387,8999],{"class":4403},[3410,15389,7378],{"class":6300},[3410,15391,15392],{"class":3412,"line":3891},[3410,15393,3435],{"emptyLinePlaceholder":3434},[3410,15395,15396],{"class":3412,"line":3897},[3410,15397,15398],{"class":4462},"# SSH лише з вашого IP\n",[3410,15400,15401,15403,15405,15407],{"class":3412,"line":3903},[3410,15402,4400],{"class":4399},[3410,15404,4404],{"class":4403},[3410,15406,9010],{"class":4403},[3410,15408,4411],{"class":4410},[3410,15410,15411,15413,15415,15417,15419,15421,15423],{"class":3412,"line":3909},[3410,15412,9017],{"class":4416},[3410,15414,9020],{"class":6538},[3410,15416,13391],{"class":4416},[3410,15418,9030],{"class":4403},[3410,15420,9033],{"class":4416},[3410,15422,9036],{"class":4420},[3410,15424,4411],{"class":4410},[3410,15426,15427,15429,15431,15433,15435,15437],{"class":3412,"line":3915},[3410,15428,9043],{"class":4416},[3410,15430,9046],{"class":4403},[3410,15432,8990],{"class":6538},[3410,15434,9051],{"class":4403},[3410,15436,4454],{"class":4416},[3410,15438,4457],{"class":4403},[3410,15440,15441],{"class":3412,"line":3921},[3410,15442,3435],{"emptyLinePlaceholder":3434},[3410,15444,15445],{"class":3412,"line":5681},[3410,15446,15447],{"class":4462},"# HTTP публічно (Let's Encrypt + редирект)\n",[3410,15449,15450,15452,15454,15456],{"class":3412,"line":5687},[3410,15451,4400],{"class":4399},[3410,15453,4404],{"class":4403},[3410,15455,9010],{"class":4403},[3410,15457,4411],{"class":4410},[3410,15459,15460,15462,15464,15466,15468,15470,15472],{"class":3412,"line":5692},[3410,15461,9017],{"class":4416},[3410,15463,9020],{"class":6538},[3410,15465,13391],{"class":4416},[3410,15467,9030],{"class":4403},[3410,15469,9033],{"class":4416},[3410,15471,6569],{"class":4420},[3410,15473,4411],{"class":4410},[3410,15475,15476,15478,15480,15482],{"class":3412,"line":9097},[3410,15477,9043],{"class":4416},[3410,15479,9102],{"class":4403},[3410,15481,4454],{"class":4416},[3410,15483,4457],{"class":4403},[3410,15485,15486],{"class":3412,"line":9109},[3410,15487,3435],{"emptyLinePlaceholder":3434},[3410,15489,15490],{"class":3412,"line":9114},[3410,15491,15492],{"class":4462},"# HTTPS публічно (трафік застосунків)\n",[3410,15494,15495,15497,15499,15501],{"class":3412,"line":9120},[3410,15496,4400],{"class":4399},[3410,15498,4404],{"class":4403},[3410,15500,9010],{"class":4403},[3410,15502,4411],{"class":4410},[3410,15504,15505,15507,15509,15511,15513,15515,15517],{"class":3412,"line":9131},[3410,15506,9017],{"class":4416},[3410,15508,9020],{"class":6538},[3410,15510,13391],{"class":4416},[3410,15512,9030],{"class":4403},[3410,15514,9033],{"class":4416},[3410,15516,12155],{"class":4420},[3410,15518,4411],{"class":4410},[3410,15520,15521,15523,15525,15527],{"class":3412,"line":9140},[3410,15522,9043],{"class":4416},[3410,15524,9102],{"class":4403},[3410,15526,4454],{"class":4416},[3410,15528,4457],{"class":4403},[3410,15530,15531],{"class":3412,"line":9154},[3410,15532,3435],{"emptyLinePlaceholder":3434},[3410,15534,15535],{"class":3412,"line":9165},[3410,15536,15537],{"class":4462},"# Dokploy UI лише з вашого IP\n",[3410,15539,15540,15542,15544,15546],{"class":3412,"line":9170},[3410,15541,4400],{"class":4399},[3410,15543,4404],{"class":4403},[3410,15545,9010],{"class":4403},[3410,15547,4411],{"class":4410},[3410,15549,15550,15552,15554,15556,15558,15560,15563],{"class":3412,"line":9176},[3410,15551,9017],{"class":4416},[3410,15553,9020],{"class":6538},[3410,15555,13391],{"class":4416},[3410,15557,9030],{"class":4403},[3410,15559,9033],{"class":4416},[3410,15561,15562],{"class":4420}," 3000",[3410,15564,4411],{"class":4410},[3410,15566,15567,15569,15571,15573,15575,15577],{"class":3412,"line":9188},[3410,15568,9043],{"class":4416},[3410,15570,9046],{"class":4403},[3410,15572,8990],{"class":6538},[3410,15574,9051],{"class":4403},[3410,15576,4454],{"class":4416},[3410,15578,4457],{"class":4403},[3410,15580,15581],{"class":3412,"line":9199},[3410,15582,3435],{"emptyLinePlaceholder":3434},[3410,15584,15585],{"class":3412,"line":9208},[3410,15586,15587],{"class":4462},"# Запуск instance з 30 GB диском\n",[3410,15589,15590,15592,15594,15596,15598,15600],{"class":3412,"line":9225},[3410,15591,9262],{"class":6538},[3410,15593,7352],{"class":6300},[3410,15595,4400],{"class":4399},[3410,15597,4404],{"class":4403},[3410,15599,9271],{"class":4403},[3410,15601,4411],{"class":4410},[3410,15603,15604,15606,15608],{"class":3412,"line":9230},[3410,15605,9279],{"class":4416},[3410,15607,9282],{"class":6538},[3410,15609,4411],{"class":4410},[3410,15611,15612,15614,15616],{"class":3412,"line":9236},[3410,15613,9290],{"class":4416},[3410,15615,13499],{"class":4403},[3410,15617,4411],{"class":4410},[3410,15619,15620,15622,15624],{"class":3412,"line":9248},[3410,15621,9191],{"class":4416},[3410,15623,9194],{"class":4403},[3410,15625,4411],{"class":4410},[3410,15627,15628,15630,15632],{"class":3412,"line":9253},[3410,15629,9310],{"class":4416},[3410,15631,9020],{"class":6538},[3410,15633,4411],{"class":4410},[3410,15635,15636,15639,15642],{"class":3412,"line":9259},[3410,15637,15638],{"class":4416},"    --block-device-mappings",[3410,15640,15641],{"class":4403}," '[{\"DeviceName\":\"\u002Fdev\u002Fsda1\",\"Ebs\":{\"VolumeSize\":30,\"VolumeType\":\"gp3\"}}]'",[3410,15643,4411],{"class":4410},[3410,15645,15646,15648,15650],{"class":3412,"line":9276},[3410,15647,6606],{"class":4416},[3410,15649,8833],{"class":4403},[3410,15651,4411],{"class":4410},[3410,15653,15654,15656,15659],{"class":3412,"line":9287},[3410,15655,9329],{"class":4416},[3410,15657,15658],{"class":4403}," 'ResourceType=instance,Tags=[{Key=Name,Value=dokploy-server}]'",[3410,15660,4411],{"class":4410},[3410,15662,15663,15665,15667,15669,15671],{"class":3412,"line":9298},[3410,15664,4438],{"class":4416},[3410,15666,9342],{"class":4403},[3410,15668,8892],{"class":4416},[3410,15670,4451],{"class":4403},[3410,15672,7378],{"class":6300},[3410,15674,15675,15677,15680,15682],{"class":3412,"line":9307},[3410,15676,6953],{"class":4399},[3410,15678,15679],{"class":4403}," \"Instance: ",[3410,15681,6539],{"class":6538},[3410,15683,8848],{"class":4403},[4876,15685,15686,15694,15702,15710],{"title":9368},[4880,15687,15689,3572,15692],{"className":15688},[3412],[3410,15690,4887],{"className":15691},[4886],[3366,15693,9377],{},[4880,15695,15697,4898,15700],{"className":15696},[3412],[3410,15698,4897],{"className":15699},[4886],[3366,15701,9386],{},[4880,15703,15705,4898,15708],{"className":15704},[3412],[3410,15706,4897],{"className":15707},[4886],[3366,15709,4919],{},[4880,15711,15713],{"className":15712},[3412],[3410,15714,4160],{"className":15715},[4926],[3348,15717,13867],{},[3348,15719,13867],{},[3547,15721],{},[3584,15723,15725],{"id":15724},"крок-2-виділення-elastic-ip-та-налаштування-dns","Крок 2: Виділення Elastic IP та налаштування DNS",[3348,15727,15728,15729,15732,15733,15736],{},"Dokploy використовує ",[3366,15730,15731],{},"Traefik"," для автоматичного отримання SSL-сертифікатів від Let's Encrypt. Let's Encrypt верифікує, що ви дійсно контролюєте домен, звернувшись до вашого сервера через порт 80. Для цього потрібна ",[3366,15734,15735],{},"стала IP-адреса",", яка не змінюється після рестартів, — саме таку надає Elastic IP.",[7643,15738,15739,15788],{},[7646,15740,15741],{"label":7648},[7586,15742,15743,15760,15783],{},[3622,15744,9476,15745,3994,15747,15749],{},[3366,15746,11074],{},[3366,15748,11077],{},[3619,15750,15751,15756],{},[3622,15752,15753,15754],{},"Network Border Group: ",[3407,15755,4376],{},[3622,15757,8634,15758],{},[3366,15759,11080],{},[3622,15761,11083,15762,3994,15764,15766],{},[3366,15763,11086],{},[3366,15765,11089],{},[3619,15767,15768,15774,15779],{},[3622,15769,15770,15771],{},"Resource type: ",[3366,15772,15773],{},"Instance",[3622,15775,15776,15777],{},"Instance: оберіть ",[3407,15778,15032],{},[3622,15780,8634,15781],{},[3366,15782,11100],{},[3622,15784,15785,15786,7086],{},"Запишіть виділений IP (далі у прикладах — ",[3407,15787,9497],{},[7646,15789,15790],{"label":7694},[3400,15791,15793],{"className":4390,"code":15792,"language":4392,"meta":3405,"style":3405},"# Виділити Elastic IP\nALLOC_ID=$(aws ec2 allocate-address \\\n    --domain vpc \\\n    --region eu-central-1 \\\n    --query AllocationId --output text)\n\n# Прив'язати до instance\naws ec2 associate-address \\\n    --instance-id $INSTANCE_ID \\\n    --allocation-id $ALLOC_ID \\\n    --region eu-central-1\n\n# Дізнатись виділений IP\nEIP=$(aws ec2 describe-addresses \\\n    --allocation-ids $ALLOC_ID \\\n    --query \"Addresses[0].PublicIp\" \\\n    --output text --region eu-central-1)\necho \"Elastic IP: $EIP\"\n",[3407,15794,15795,15799,15813,15821,15829,15841,15845,15850,15860,15868,15876,15882,15886,15891,15906,15914,15922,15934],{"__ignoreMap":3405},[3410,15796,15797],{"class":3412,"line":3413},[3410,15798,11118],{"class":4462},[3410,15800,15801,15803,15805,15807,15809,15811],{"class":3412,"line":3419},[3410,15802,11123],{"class":6538},[3410,15804,7352],{"class":6300},[3410,15806,4400],{"class":4399},[3410,15808,4404],{"class":4403},[3410,15810,11132],{"class":4403},[3410,15812,4411],{"class":4410},[3410,15814,15815,15817,15819],{"class":3412,"line":3425},[3410,15816,11139],{"class":4416},[3410,15818,11142],{"class":4403},[3410,15820,4411],{"class":4410},[3410,15822,15823,15825,15827],{"class":3412,"line":3431},[3410,15824,6606],{"class":4416},[3410,15826,8833],{"class":4403},[3410,15828,4411],{"class":4410},[3410,15830,15831,15833,15835,15837,15839],{"class":3412,"line":3438},[3410,15832,4438],{"class":4416},[3410,15834,11155],{"class":4403},[3410,15836,8892],{"class":4416},[3410,15838,4451],{"class":4403},[3410,15840,7378],{"class":6300},[3410,15842,15843],{"class":3412,"line":3444},[3410,15844,3435],{"emptyLinePlaceholder":3434},[3410,15846,15847],{"class":3412,"line":3450},[3410,15848,15849],{"class":4462},"# Прив'язати до instance\n",[3410,15851,15852,15854,15856,15858],{"class":3412,"line":3456},[3410,15853,4400],{"class":4399},[3410,15855,4404],{"class":4403},[3410,15857,11238],{"class":4403},[3410,15859,4411],{"class":4410},[3410,15861,15862,15864,15866],{"class":3412,"line":3462},[3410,15863,7888],{"class":4416},[3410,15865,7891],{"class":6538},[3410,15867,4411],{"class":4410},[3410,15869,15870,15872,15874],{"class":3412,"line":3468},[3410,15871,11253],{"class":4416},[3410,15873,11189],{"class":6538},[3410,15875,4411],{"class":4410},[3410,15877,15878,15880],{"class":3412,"line":3474},[3410,15879,6606],{"class":4416},[3410,15881,4457],{"class":4403},[3410,15883,15884],{"class":3412,"line":3480},[3410,15885,3435],{"emptyLinePlaceholder":3434},[3410,15887,15888],{"class":3412,"line":3486},[3410,15889,15890],{"class":4462},"# Дізнатись виділений IP\n",[3410,15892,15893,15896,15898,15900,15902,15904],{"class":3412,"line":3491},[3410,15894,15895],{"class":6538},"EIP",[3410,15897,7352],{"class":6300},[3410,15899,4400],{"class":4399},[3410,15901,4404],{"class":4403},[3410,15903,11179],{"class":4403},[3410,15905,4411],{"class":4410},[3410,15907,15908,15910,15912],{"class":3412,"line":3497},[3410,15909,11186],{"class":4416},[3410,15911,11189],{"class":6538},[3410,15913,4411],{"class":4410},[3410,15915,15916,15918,15920],{"class":3412,"line":3503},[3410,15917,4438],{"class":4416},[3410,15919,11198],{"class":4403},[3410,15921,4411],{"class":4410},[3410,15923,15924,15926,15928,15930,15932],{"class":3412,"line":3508},[3410,15925,4448],{"class":4416},[3410,15927,4451],{"class":4403},[3410,15929,4454],{"class":4416},[3410,15931,8833],{"class":4403},[3410,15933,7378],{"class":6300},[3410,15935,15936,15938,15940,15943],{"class":3412,"line":3513},[3410,15937,6953],{"class":4399},[3410,15939,11215],{"class":4403},[3410,15941,15942],{"class":6538},"$EIP",[3410,15944,8848],{"class":4403},[4876,15946,15948,15957],{"title":15947},"aws ec2 describe-addresses — перевірка Elastic IP",[4880,15949,15951,3572,15954],{"className":15950},[3412],[3410,15952,4887],{"className":15953},[4886],[3366,15955,15956],{},"echo \"Elastic IP: $EIP\"",[4880,15958,15960],{"className":15959},[3412],[3410,15961,15963],{"className":15962},[4926],"Elastic IP: 3.64.185.42",[3348,15965,15966,15969,15970,8197],{},[3366,15967,15968],{},"Налаштування DNS:"," зайдіть у панель вашого реєстратора доменів та додайте ",[3366,15971,15972],{},"A-запис",[4049,15974,15975,15986],{},[4052,15976,15977],{},[4055,15978,15979,15981,15983],{},[4058,15980,5342],{},[4058,15982,11777],{},[4058,15984,15985],{},"Пояснення",[4075,15987,15988,16003,16017,16030],{},[4055,15989,15990,15995,16000],{},[4080,15991,15992],{},[3366,15993,15994],{},"Ім'я",[4080,15996,15997],{},[3407,15998,15999],{},"dokploy",[4080,16001,16002],{},"Субдомен для самого Dokploy UI",[4055,16004,16005,16010,16014],{},[4080,16006,16007],{},[3366,16008,16009],{},"Тип",[4080,16011,16012],{},[3407,16013,11789],{},[4080,16015,16016],{},"Прямий запис IP-адреси",[4055,16018,16019,16023,16027],{},[4080,16020,16021],{},[3366,16022,11777],{},[4080,16024,16025],{},[3407,16026,9497],{},[4080,16028,16029],{},"Ваш Elastic IP",[4055,16031,16032,16036,16040],{},[4080,16033,16034],{},[3366,16035,11825],{},[4080,16037,16038],{},[3407,16039,11828],{},[4080,16041,16042],{},"Час кешування (5 хв)",[3348,16044,16045,16046,16048,16049,16051,16052,16055,16056,16059,16060,16062],{},"Якщо ваш домен — ",[3407,16047,11037],{},", а ім'я — ",[3407,16050,15999],{},", то Dokploy UI буде доступний за ",[3407,16053,16054],{},"https:\u002F\u002Fdokploy.pp.ua",". Для застосунків додайте окремий A-запис або wildcard-запис ",[3407,16057,16058],{},"* → 3.64.185.42",", щоб субдомени на кшталт ",[3407,16061,11650],{}," теж вказували на сервер.",[4147,16064,16065,16066,16069,16070,16075],{},"Перевірте поширення DNS командою ",[3407,16067,16068],{},"nslookup dokploy.pp.ua"," або сервісом ",[11576,16071,16074],{"href":16072,"rel":16073},"https:\u002F\u002Fwww.whatsmydns.net",[11580],"whatsmydns.net",". DNS-зміни набирають чинності від кількох хвилин до 48 годин, але зазвичай — менш ніж 5–15 хвилин.",[3547,16077],{},[3584,16079,16081],{"id":16080},"крок-3-встановлення-dokploy","Крок 3: Встановлення Dokploy",[3348,16083,16084],{},"Підключіться до сервера через SSH та виконайте встановлення:",[4876,16086,16088,16096,16099],{"title":16087},"SSH підключення до dokploy-server",[4880,16089,16091,3572,16094],{"className":16090},[3412],[3410,16092,4887],{"className":16093},[4886],[3366,16095,9563],{},[4880,16097,9582],{"className":16098},[3412],[4880,16100,16102],{"className":16101},[3412],[3410,16103,9592],{"className":16104},[4926],[3348,16106,16107],{},"Dokploy встановлюється однією командою. Інсталятор автоматично завантажить Docker, Docker Compose та всі необхідні образи. Жодних попередніх налаштувань не потрібно:",[4876,16109,16111,16120,16124,16132,16136,16143,16147,16154,16158,16166,16173,16180,16187,16191,16198,16201,16209],{"title":16110},"curl -sSL https:\u002F\u002Fdokploy.com\u002Finstall.sh | sh — встановлення Dokploy",[4880,16112,16114,3572,16117],{"className":16113},[3412],[3410,16115,9592],{"className":16116},[4886],[3366,16118,16119],{},"sudo curl -sSL https:\u002F\u002Fdokploy.com\u002Finstall.sh | sudo sh",[4880,16121,16123],{"className":16122},[3412],"Dokploy Installer v0.4.x",[4880,16125,16127,16128],{"className":16126},[3412],"Detecting OS... ",[3410,16129,16131],{"className":16130},[4926],"Ubuntu 26.04 LTS",[4880,16133,16135],{"className":16134},[3412],"Installing Docker Engine...",[4880,16137,16139],{"className":16138},[3412],[3410,16140,16142],{"className":16141},[4926],"✓ Docker installed (v26.x)",[4880,16144,16146],{"className":16145},[3412],"Installing Docker Compose Plugin...",[4880,16148,16150],{"className":16149},[3412],[3410,16151,16153],{"className":16152},[4926],"✓ Docker Compose installed",[4880,16155,16157],{"className":16156},[3412],"Pulling Dokploy service images...",[4880,16159,16161,16162],{"className":16160},[3412],"  dokploy\u002Fdokploy:latest          ... ",[3410,16163,16165],{"className":16164},[4926],"done",[4880,16167,16169,16170],{"className":16168},[3412],"  traefik:v3.x                     ... ",[3410,16171,16165],{"className":16172},[4926],[4880,16174,16176,16177],{"className":16175},[3412],"  postgres:16                      ... ",[3410,16178,16165],{"className":16179},[4926],[4880,16181,16183,16184],{"className":16182},[3412],"  redis:7-alpine                   ... ",[3410,16185,16165],{"className":16186},[4926],[4880,16188,16190],{"className":16189},[3412],"Starting Dokploy services...",[4880,16192,16194],{"className":16193},[3412],[3410,16195,16197],{"className":16196},[4926],"✓ All services started successfully",[4880,16199],{"className":16200},[3412],[4880,16202,16204,16205],{"className":16203},[3412],"🚀 Dokploy is running at: ",[3410,16206,16208],{"className":16207},[4926],"http:\u002F\u002F3.64.185.42:3000",[4880,16210,16212],{"className":16211},[3412],"Open this URL in your browser to complete the initial setup.",[3712,16214,16215,16216,16219],{},"Інсталяція займає ",[3366,16217,16218],{},"3–7 хвилин"," залежно від швидкості з'єднання (потрібно завантажити ~1.5 GB Docker образів). Команда блокує термінал до завершення — не закривайте SSH-сесію.",[4003,16221,16222,16233,16242,16248,16254,16261,16266,16372,16377,16392,16398,16403,16406,16434,16439,16442],{},[3348,16223,16224],{},[3366,16225,16226,16227,7434,16230],{},"Проблема: скрипт падає з помилкою ",[3407,16228,16229],{},"docker: not found",[3407,16231,16232],{},"E: Unable to locate package docker-ce",[3348,16234,16235,16236,16239,16240,3373],{},"Це трапляється, коли ваша Ubuntu має нестандартну кодову назву (наприклад, ",[3407,16237,16238],{},"resolute",") — офіційний репозиторій Docker не містить пакетів для такої назви, тому встановлення Docker збоїть, і наступний крок ініціалізації Docker Swarm видає ",[3407,16241,16229],{},[3348,16243,16244,16247],{},[3366,16245,16246],{},"Діагностика:"," якщо у логах ви бачите рядок на кшталт:",[3400,16249,16252],{"className":16250,"code":16251,"language":8231},[8229],"https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu resolute stable\n",[3407,16253,16251],{"__ignoreMap":3405},[3348,16255,16256,16257,16260],{},"і потім помилки ",[3407,16258,16259],{},"E: Unable to locate package"," — ви зіткнулись саме з цим.",[3348,16262,16263],{},[3366,16264,16265],{},"Крок 1: Встановіть Docker вручну",[3400,16267,16269],{"className":4390,"code":16268,"language":4392,"meta":3405,"style":3405},"# 1. Видаліть зіпсований файл репозиторію, який створив скрипт\nsudo rm -f \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list\n\n# 2. Додайте офіційний репозиторій Docker зі стабільною кодовою назвою jammy\necho \"deb [arch=$(dpkg --print-architecture) signed-by=\u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu jammy stable\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list\n\n# 3. Оновіть списки пакетів\nsudo apt-get update\n\n# 4. Встановіть Docker\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n",[3407,16270,16271,16276,16288,16292,16297,16321,16325,16330,16338,16342,16347],{"__ignoreMap":3405},[3410,16272,16273],{"class":3412,"line":3413},[3410,16274,16275],{"class":4462},"# 1. Видаліть зіпсований файл репозиторію, який створив скрипт\n",[3410,16277,16278,16280,16282,16285],{"class":3412,"line":3419},[3410,16279,6266],{"class":4399},[3410,16281,11460],{"class":4403},[3410,16283,16284],{"class":4416}," -f",[3410,16286,16287],{"class":4403}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list\n",[3410,16289,16290],{"class":3412,"line":3425},[3410,16291,3435],{"emptyLinePlaceholder":3434},[3410,16293,16294],{"class":3412,"line":3431},[3410,16295,16296],{"class":4462},"# 2. Додайте офіційний репозиторій Docker зі стабільною кодовою назвою jammy\n",[3410,16298,16299,16301,16304,16307,16310,16313,16315,16317,16319],{"class":3412,"line":3438},[3410,16300,6953],{"class":4399},[3410,16302,16303],{"class":4403}," \"deb [arch=$(",[3410,16305,16306],{"class":4399},"dpkg",[3410,16308,16309],{"class":4416}," --print-architecture",[3410,16311,16312],{"class":4403},") signed-by=\u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu jammy stable\"",[3410,16314,7092],{"class":6300},[3410,16316,6266],{"class":4399},[3410,16318,6294],{"class":4403},[3410,16320,16287],{"class":4403},[3410,16322,16323],{"class":3412,"line":3444},[3410,16324,3435],{"emptyLinePlaceholder":3434},[3410,16326,16327],{"class":3412,"line":3450},[3410,16328,16329],{"class":4462},"# 3. Оновіть списки пакетів\n",[3410,16331,16332,16334,16336],{"class":3412,"line":3456},[3410,16333,6266],{"class":4399},[3410,16335,6269],{"class":4403},[3410,16337,12184],{"class":4403},[3410,16339,16340],{"class":3412,"line":3462},[3410,16341,3435],{"emptyLinePlaceholder":3434},[3410,16343,16344],{"class":3412,"line":3468},[3410,16345,16346],{"class":4462},"# 4. Встановіть Docker\n",[3410,16348,16349,16351,16353,16355,16357,16360,16363,16366,16369],{"class":3412,"line":3474},[3410,16350,6266],{"class":4399},[3410,16352,6269],{"class":4403},[3410,16354,6272],{"class":4403},[3410,16356,6275],{"class":4416},[3410,16358,16359],{"class":4403}," docker-ce",[3410,16361,16362],{"class":4403}," docker-ce-cli",[3410,16364,16365],{"class":4403}," containerd.io",[3410,16367,16368],{"class":4403}," docker-buildx-plugin",[3410,16370,16371],{"class":4403}," docker-compose-plugin\n",[3348,16373,16374],{},[3366,16375,16376],{},"Крок 2: Перевірте, що Docker працює",[3400,16378,16380],{"className":4390,"code":16379,"language":4392,"meta":3405,"style":3405},"sudo docker version\n",[3407,16381,16382],{"__ignoreMap":3405},[3410,16383,16384,16386,16389],{"class":3412,"line":3413},[3410,16385,6266],{"class":4399},[3410,16387,16388],{"class":4403}," docker",[3410,16390,16391],{"class":4403}," version\n",[3348,16393,16394,16395,3373],{},"Має вивести інформацію про клієнт та сервер без помилок ",[3407,16396,16397],{},"not found",[3348,16399,16400],{},[3366,16401,16402],{},"Крок 3: Ініціалізуйте Docker Swarm вручну",[3348,16404,16405],{},"Dokploy базується на Docker Swarm. Скрипт впав саме на цьому кроці, тому ініціалізуємо Swarm самостійно. Підставте IP-адресу вашого instance (вона видна у логах скрипта або у AWS Console):",[3400,16407,16409],{"className":4390,"code":16408,"language":4392,"meta":3405,"style":3405},"# ЗАМІНІТЬ на вашу реальну приватну IP-адресу instance\nsudo docker swarm init --advertise-addr 172.31.41.246\n",[3407,16410,16411,16416],{"__ignoreMap":3405},[3410,16412,16413],{"class":3412,"line":3413},[3410,16414,16415],{"class":4462},"# ЗАМІНІТЬ на вашу реальну приватну IP-адресу instance\n",[3410,16417,16418,16420,16422,16425,16428,16431],{"class":3412,"line":3419},[3410,16419,6266],{"class":4399},[3410,16421,16388],{"class":4403},[3410,16423,16424],{"class":4403}," swarm",[3410,16426,16427],{"class":4403}," init",[3410,16429,16430],{"class":4416}," --advertise-addr",[3410,16432,16433],{"class":4420}," 172.31.41.246\n",[3348,16435,16436],{},[3366,16437,16438],{},"Крок 4: Запустіть скрипт Dokploy знову",[3348,16440,16441],{},"Тепер, коли Docker встановлений і Swarm активований, скрипт знайде все необхідне і просто розгорне контейнери без повторного встановлення Docker:",[3400,16443,16445],{"className":4390,"code":16444,"language":4392,"meta":3405,"style":3405},"curl -sSL https:\u002F\u002Fdokploy.com\u002Finstall.sh | sudo sh\n",[3407,16446,16447],{"__ignoreMap":3405},[3410,16448,16449,16451,16454,16457,16459,16461],{"class":3412,"line":3413},[3410,16450,7274],{"class":4399},[3410,16452,16453],{"class":4416}," -sSL",[3410,16455,16456],{"class":4403}," https:\u002F\u002Fdokploy.com\u002Finstall.sh",[3410,16458,7092],{"class":6300},[3410,16460,6266],{"class":4399},[3410,16462,16463],{"class":4403}," sh\n",[3348,16465,16466],{},"Перевірте, що всі чотири контейнери Dokploy запущені та здорові:",[4876,16468,16470,16479,16483,16491,16499,16507],{"title":16469},"docker ps — перевірка контейнерів Dokploy",[4880,16471,16473,3572,16476],{"className":16472},[3412],[3410,16474,9592],{"className":16475},[4886],[3366,16477,16478],{},"docker ps --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\"",[4880,16480,16482],{"className":16481},[3412],"NAMES                STATUS              PORTS",[4880,16484,16486,16490],{"className":16485},[3412],[3410,16487,16489],{"className":16488},[4926],"dokploy-app","          Up 3 minutes        0.0.0.0:3000->3000\u002Ftcp",[4880,16492,16494,16498],{"className":16493},[3412],[3410,16495,16497],{"className":16496},[4926],"dokploy-traefik","      Up 3 minutes        0.0.0.0:80->80\u002Ftcp, 0.0.0.0:443->443\u002Ftcp",[4880,16500,16502,16506],{"className":16501},[3412],[3410,16503,16505],{"className":16504},[4926],"dokploy-postgres","     Up 3 minutes        5432\u002Ftcp",[4880,16508,16510,16514],{"className":16509},[3412],[3410,16511,16513],{"className":16512},[4926],"dokploy-redis","        Up 3 minutes        6379\u002Ftcp",[3348,16516,16517],{},"Що робить кожен контейнер:",[3619,16519,16520,16527,16534,16541],{},[3622,16521,16522,16526],{},[3366,16523,16524],{},[3407,16525,16489],{}," — основний застосунок: веб-інтерфейс, REST API, управління деплоями",[3622,16528,16529,16533],{},[3366,16530,16531],{},[3407,16532,16497],{}," — reverse proxy: приймає HTTP\u002FHTTPS трафік, термінує TLS, маршрутизує до контейнерів застосунків",[3622,16535,16536,16540],{},[3366,16537,16538],{},[3407,16539,16505],{}," — реляційна база даних Dokploy (конфігурація, проєкти, деплої)",[3622,16542,16543,16547],{},[3366,16544,16545],{},[3407,16546,16513],{}," — кеш та черга задач (асинхронні деплої, WebSocket для логів)",[3547,16549],{},[3584,16551,16553],{"id":16552},"крок-4-перше-налаштування-у-веб-інтерфейсі","Крок 4: Перше налаштування у веб-інтерфейсі",[3348,16555,16556,16557],{},"Відкрийте у браузері: ",[3407,16558,16208],{},[3348,16560,16561,16562,16565],{},"Ви побачите сторінку ",[3366,16563,16564],{},"реєстрації першого адміністратора",". Ця форма відображається лише один раз — при першому відкритті після чистого встановлення. Якщо цю сторінку побачить сторонній — він зможе стати адміністратором. Тому важливо виконати цей крок одразу після встановлення.",[3348,16567,16568],{},[3366,16569,16570],{},"Заповніть форму реєстрації:",[3619,16572,16573,16579,16585],{},[3622,16574,16575,16578],{},[3366,16576,16577],{},"Email:"," ваша email-адреса (буде логіном для входу)",[3622,16580,16581,16584],{},[3366,16582,16583],{},"Password:"," надійний пароль (мінімум 8 символів; рекомендується 16+)",[3622,16586,16587,16590],{},[3366,16588,16589],{},"Confirm Password:"," повторіть пароль",[3348,16592,8634,16593,16596],{},[3366,16594,16595],{},"Create Account",". Ви автоматично увійдете в Dokploy і побачите порожній Dashboard.",[3348,16598,16599],{},[3366,16600,16601],{},"Огляд головних розділів інтерфейсу:",[4049,16603,16604,16613],{},[4052,16605,16606],{},[4055,16607,16608,16611],{},[4058,16609,16610],{},"Розділ",[4058,16612,5168],{},[4075,16614,16615,16625,16635,16645,16655,16665],{},[4055,16616,16617,16622],{},[4080,16618,16619],{},[3366,16620,16621],{},"Dashboard",[4080,16623,16624],{},"Загальна статистика: кількість проєктів, сервісів, стан сервера (CPU, RAM, диск)",[4055,16626,16627,16632],{},[4080,16628,16629],{},[3366,16630,16631],{},"Projects",[4080,16633,16634],{},"Список проєктів — кожен проєкт містить один або кілька сервісів",[4055,16636,16637,16642],{},[4080,16638,16639],{},[3366,16640,16641],{},"Settings → Server",[4080,16643,16644],{},"Домен Dokploy UI, Let's Encrypt email, SSH-ключі для GitHub",[4055,16646,16647,16652],{},[4080,16648,16649],{},[3366,16650,16651],{},"Settings → Certificates",[4080,16653,16654],{},"Перегляд виданих SSL-сертифікатів та їх статусу",[4055,16656,16657,16662],{},[4080,16658,16659],{},[3366,16660,16661],{},"Settings → Users",[4080,16663,16664],{},"Управління командою: додавання користувачів з різними правами",[4055,16666,16667,16672],{},[4080,16668,16669],{},[3366,16670,16671],{},"Settings → Notifications",[4080,16673,16674],{},"Налаштування сповіщень (Slack, Discord, Email, Telegram)",[3348,16676,16677],{},[3366,16678,16679],{},"Налаштування серверного домену та SSL:",[7586,16681,16682,16691,16701,16707],{},[3622,16683,16684,16685,3994,16688],{},"Перейдіть у ",[3366,16686,16687],{},"Settings",[3366,16689,16690],{},"Server",[3622,16692,16693,16694,16697,16698],{},"У полі ",[3366,16695,16696],{},"Domain"," введіть ваш домен для Dokploy UI: ",[3407,16699,16700],{},"dokploy.pp.ua",[3622,16702,16693,16703,16706],{},[3366,16704,16705],{},"Let's Encrypt Email"," введіть вашу email-адресу (на неї Let's Encrypt надсилає сповіщення про закінчення сертифікату)",[3622,16708,8634,16709],{},[3366,16710,16711],{},"Save",[3348,16713,16714,16715,16718,16719,3373],{},"Після збереження Dokploy передає налаштування Traefik, який ",[3366,16716,16717],{},"автоматично"," звертається до Let's Encrypt, проходить HTTP-01 верифікацію та отримує сертифікат. Зачекайте 1–2 хвилини — потім Dokploy UI буде доступний за адресою ",[3407,16720,16054],{},[4147,16722,16723,16724,16726,16727,16729],{},"Якщо після збереження HTTPS не запрацював — перевірте два моменти: 1) DNS-запис для ",[3407,16725,16700],{}," вже вказує на ваш Elastic IP (",[3407,16728,16068],{},"); 2) порт 80 відкритий у Security Group (Let's Encrypt потребує його для верифікації).",[3547,16731],{},[3584,16733,16735],{"id":16734},"крок-5-підготовка-net-застосунку-до-деплою-через-docker","Крок 5: Підготовка .NET застосунку до деплою через Docker",[3348,16737,16738,16739,16742,16743,16745,16746,16749,16750,3373],{},"Dokploy будує ваш застосунок з ",[3366,16740,16741],{},"Dockerfile"," у корені репозиторію. Якщо ",[3407,16744,16741],{}," відсутній — Dokploy може спробувати автовизначення стека через ",[3366,16747,16748],{},"Nixpacks",", але для .NET рекомендується явний ",[3407,16751,16741],{},[3348,16753,16754,16755,16757,16758,3373],{},"Ключовий момент при написанні ",[3407,16756,16741],{}," для Dokploy: застосунок повинен слухати на порту, який ви потім вкажете в налаштуваннях домену. Традиційно для контейнерів використовують порт ",[3366,16759,16760],{},"8080",[3400,16762,16766],{"className":16763,"code":16764,"language":16765,"meta":3405,"style":3405},"language-dockerfile shiki shiki-themes light-plus dark-plus dark-plus","# Файл: Dockerfile (у корені репозиторію)\n\n# Стадія 1: збірка\nFROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 AS build\nWORKDIR \u002Fsrc\n\n# Копіюємо файл проєкту окремо для кешування шару відновлення пакетів\nCOPY MyApi.csproj .\nRUN dotnet restore\n\n# Копіюємо решту коду та публікуємо\nCOPY . .\nRUN dotnet publish -c Release -o \u002Fapp\u002Fpublish --no-restore\n\n# Стадія 2: runtime образ (менший розмір — лише runtime, без SDK)\nFROM mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 AS runtime\nWORKDIR \u002Fapp\nCOPY --from=build \u002Fapp\u002Fpublish .\n\n# Налаштовуємо порт: 8080 — стандарт для контейнерів (не 5000\u002F5001)\nENV ASPNETCORE_URLS=http:\u002F\u002F+:8080\nENV ASPNETCORE_ENVIRONMENT=Production\nEXPOSE 8080\n\nENTRYPOINT [\"dotnet\", \"MyApi.dll\"]\n","dockerfile",[3407,16767,16768,16773,16777,16782,16796,16804,16808,16813,16821,16829,16833,16838,16845,16852,16856,16861,16873,16880,16887,16891,16896,16904,16911,16919,16923],{"__ignoreMap":3405},[3410,16769,16770],{"class":3412,"line":3413},[3410,16771,16772],{"class":4462},"# Файл: Dockerfile (у корені репозиторію)\n",[3410,16774,16775],{"class":3412,"line":3419},[3410,16776,3435],{"emptyLinePlaceholder":3434},[3410,16778,16779],{"class":3412,"line":3425},[3410,16780,16781],{"class":4462},"# Стадія 1: збірка\n",[3410,16783,16784,16787,16790,16793],{"class":3412,"line":3431},[3410,16785,16786],{"class":4416},"FROM",[3410,16788,16789],{"class":6300}," mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 ",[3410,16791,16792],{"class":4416},"AS",[3410,16794,16795],{"class":6300}," build\n",[3410,16797,16798,16801],{"class":3412,"line":3438},[3410,16799,16800],{"class":4416},"WORKDIR",[3410,16802,16803],{"class":6300}," \u002Fsrc\n",[3410,16805,16806],{"class":3412,"line":3444},[3410,16807,3435],{"emptyLinePlaceholder":3434},[3410,16809,16810],{"class":3412,"line":3450},[3410,16811,16812],{"class":4462},"# Копіюємо файл проєкту окремо для кешування шару відновлення пакетів\n",[3410,16814,16815,16818],{"class":3412,"line":3456},[3410,16816,16817],{"class":4416},"COPY",[3410,16819,16820],{"class":6300}," MyApi.csproj .\n",[3410,16822,16823,16826],{"class":3412,"line":3462},[3410,16824,16825],{"class":4416},"RUN",[3410,16827,16828],{"class":6300}," dotnet restore\n",[3410,16830,16831],{"class":3412,"line":3468},[3410,16832,3435],{"emptyLinePlaceholder":3434},[3410,16834,16835],{"class":3412,"line":3474},[3410,16836,16837],{"class":4462},"# Копіюємо решту коду та публікуємо\n",[3410,16839,16840,16842],{"class":3412,"line":3480},[3410,16841,16817],{"class":4416},[3410,16843,16844],{"class":6300}," . .\n",[3410,16846,16847,16849],{"class":3412,"line":3486},[3410,16848,16825],{"class":4416},[3410,16850,16851],{"class":6300}," dotnet publish -c Release -o \u002Fapp\u002Fpublish --no-restore\n",[3410,16853,16854],{"class":3412,"line":3491},[3410,16855,3435],{"emptyLinePlaceholder":3434},[3410,16857,16858],{"class":3412,"line":3497},[3410,16859,16860],{"class":4462},"# Стадія 2: runtime образ (менший розмір — лише runtime, без SDK)\n",[3410,16862,16863,16865,16868,16870],{"class":3412,"line":3503},[3410,16864,16786],{"class":4416},[3410,16866,16867],{"class":6300}," mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 ",[3410,16869,16792],{"class":4416},[3410,16871,16872],{"class":6300}," runtime\n",[3410,16874,16875,16877],{"class":3412,"line":3508},[3410,16876,16800],{"class":4416},[3410,16878,16879],{"class":6300}," \u002Fapp\n",[3410,16881,16882,16884],{"class":3412,"line":3513},[3410,16883,16817],{"class":4416},[3410,16885,16886],{"class":6300}," --from=build \u002Fapp\u002Fpublish .\n",[3410,16888,16889],{"class":3412,"line":3519},[3410,16890,3435],{"emptyLinePlaceholder":3434},[3410,16892,16893],{"class":3412,"line":3524},[3410,16894,16895],{"class":4462},"# Налаштовуємо порт: 8080 — стандарт для контейнерів (не 5000\u002F5001)\n",[3410,16897,16898,16901],{"class":3412,"line":3530},[3410,16899,16900],{"class":4416},"ENV",[3410,16902,16903],{"class":6300}," ASPNETCORE_URLS=http:\u002F\u002F+:8080\n",[3410,16905,16906,16908],{"class":3412,"line":3536},[3410,16907,16900],{"class":4416},[3410,16909,16910],{"class":6300}," ASPNETCORE_ENVIRONMENT=Production\n",[3410,16912,16913,16916],{"class":3412,"line":3542},[3410,16914,16915],{"class":4416},"EXPOSE",[3410,16917,16918],{"class":6300}," 8080\n",[3410,16920,16921],{"class":3412,"line":3891},[3410,16922,3435],{"emptyLinePlaceholder":3434},[3410,16924,16925,16928,16931,16934,16936,16939],{"class":3412,"line":3897},[3410,16926,16927],{"class":4416},"ENTRYPOINT",[3410,16929,16930],{"class":6300}," [",[3410,16932,16933],{"class":4403},"\"dotnet\"",[3410,16935,3599],{"class":6300},[3410,16937,16938],{"class":4403},"\"MyApi.dll\"",[3410,16940,16941],{"class":6300},"]\n",[3712,16943,16944,16945,16948,16949,16952],{},"Двостадійна збірка (",[3407,16946,16947],{},"build"," + ",[3407,16950,16951],{},"runtime",") критично важлива для зменшення розміру образу: образ SDK важить ~800 MB, образ лише runtime — ~200 MB. Продакшн-образ буде вчетверо меншим, що прискорює деплой.",[3348,16954,16955,16956,16959],{},"Переконайтесь, що репозиторій містить ",[3407,16957,16958],{},".dockerignore"," для виключення зайвих файлів:",[3400,16961,16964],{"className":16962,"code":16963,"language":8231,"meta":3405},[8229],"# .dockerignore\nbin\u002F\nobj\u002F\n*.user\n.git\u002F\n.vs\u002F\n**\u002F*.md\n",[3407,16965,16963],{"__ignoreMap":3405},[3547,16967],{},[3584,16969,16971],{"id":16970},"крок-6-деплой-net-застосунку-через-dokploy","Крок 6: Деплой .NET застосунку через Dokploy",[3348,16973,16974],{},[3366,16975,16976],{},"Крок 6a: Створення проєкту",[7586,16978,16979,16986,16993,16999],{},[3622,16980,16684,16981,3994,16983],{},[3366,16982,16631],{},[3366,16984,16985],{},"Create Project",[3622,16987,16988,3572,16990],{},[3366,16989,8621],{},[3407,16991,16992],{},"my-dotnet-api",[3622,16994,16995,16998],{},[3366,16996,16997],{},"Description:"," опціонально",[3622,17000,8634,17001],{},[3366,17002,17003],{},"Create",[3348,17005,17006],{},[3366,17007,17008],{},"Крок 6b: Додавання сервісу",[7586,17010,17011,17020,17027],{},[3622,17012,17013,17014,9479,17017],{},"Всередині проєкту натисніть ",[3366,17015,17016],{},"+ Create Service",[3366,17018,17019],{},"Application",[3622,17021,17022,3572,17024],{},[3366,17023,8621],{},[3407,17025,17026],{},"api",[3622,17028,8634,17029],{},[3366,17030,17003],{},[3348,17032,17033],{},[3366,17034,17035],{},"Крок 6c: Налаштування джерела коду",[7586,17037,17038,17043,17048,17054,17062,17070,17078],{},[3622,17039,17040,17041],{},"У налаштуваннях сервісу знайдіть секцію ",[3366,17042,5388],{},[3622,17044,7686,17045],{},[3366,17046,17047],{},"GitHub",[3622,17049,8634,17050,17053],{},[3366,17051,17052],{},"Connect with GitHub"," → авторизуйте Dokploy у вашому GitHub акаунті (Dokploy отримає право читати репозиторії)",[3622,17055,7686,17056,3673,17059],{},[3366,17057,17058],{},"Repository",[3407,17060,17061],{},"username\u002Fmy-dotnet-api",[3622,17063,7686,17064,3673,17067],{},[3366,17065,17066],{},"Branch",[3407,17068,17069],{},"main",[3622,17071,17072,17075,17076],{},[3366,17073,17074],{},"Build Type",": оберіть ",[3366,17077,16741],{},[3622,17079,8634,17080],{},[3366,17081,16711],{},[3348,17083,17084],{},[3366,17085,17086],{},"Крок 6d: Налаштування домену",[7586,17088,17089,17095,17100,17134],{},[3622,17090,11740,17091,17094],{},[3366,17092,17093],{},"Domains"," у налаштуваннях сервісу",[3622,17096,8634,17097],{},[3366,17098,17099],{},"Add Domain",[3622,17101,17102,17103],{},"Заповніть форму:\n",[3619,17104,17105,17112,17122,17128],{},[3622,17106,17107,3572,17110],{},[3366,17108,17109],{},"Host:",[3407,17111,11650],{},[3622,17113,17114,3572,17117,3572,17119],{},[3366,17115,17116],{},"Port:",[3407,17118,16760],{},[8752,17120,17121],{},"(порт, на якому слухає ваш застосунок всередині контейнера)",[3622,17123,17124,17127],{},[3366,17125,17126],{},"HTTPS:"," увімкніть — Traefik автоматично отримає сертифікат",[3622,17129,17130,17133],{},[3366,17131,17132],{},"HTTP to HTTPS Redirect:"," увімкніть",[3622,17135,8634,17136],{},[3366,17137,16711],{},[3348,17139,17140],{},[3366,17141,17142],{},"Крок 6e: Перший деплой",[7586,17144,17145,17150,17155],{},[3622,17146,11740,17147],{},[3366,17148,17149],{},"Deployments",[3622,17151,8634,17152],{},[3366,17153,17154],{},"Deploy",[3622,17156,17157],{},"З'явиться вікно з живими логами збірки",[4876,17159,17161,17169,17176,17183,17187,17191,17195,17198,17206,17210,17217,17224,17228,17235,17242,17249],{"title":17160},"Логи збірки .NET застосунку в Dokploy (вкладка Deployments)",[4880,17162,17164,17168],{"className":17163},[3412],[3410,17165,17167],{"className":17166},[4991],"[Dokploy]"," Starting deployment #1 for service: api",[4880,17170,17172,17175],{"className":17171},[3412],[3410,17173,17167],{"className":17174},[4991]," Cloning repository: github.com\u002Fusername\u002Fmy-dotnet-api (branch: main)",[4880,17177,17179,17182],{"className":17178},[3412],[3410,17180,17167],{"className":17181},[4991]," Building Docker image...",[4880,17184,17186],{"className":17185},[3412],"Step 1\u002F10 : FROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 AS build",[4880,17188,17190],{"className":17189},[3412]," ---> a1b2c3d4e5f6",[4880,17192,17194],{"className":17193},[3412],"Step 4\u002F10 : RUN dotnet restore",[4880,17196,10152],{"className":17197},[3412],[4880,17199,17201,17202],{"className":17200},[3412],"  ",[3410,17203,17205],{"className":17204},[4886],"Restored \u002Fsrc\u002FMyApi.csproj (1.4s)",[4880,17207,17209],{"className":17208},[3412],"Step 6\u002F10 : RUN dotnet publish -c Release -o \u002Fapp\u002Fpublish --no-restore",[4880,17211,17201,17213],{"className":17212},[3412],[3410,17214,17216],{"className":17215},[4886],"Build succeeded. 0 Warning(s). 0 Error(s).",[4880,17218,17201,17220],{"className":17219},[3412],[3410,17221,17223],{"className":17222},[4886],"MyApi -> \u002Fapp\u002Fpublish\u002FMyApi.dll",[4880,17225,17227],{"className":17226},[3412],"Step 10\u002F10 : ENTRYPOINT [\"dotnet\", \"MyApi.dll\"]",[4880,17229,17231],{"className":17230},[3412],[3410,17232,17234],{"className":17233},[4926],"Successfully built f7a8b9c0d1e2",[4880,17236,17238,17241],{"className":17237},[3412],[3410,17239,17167],{"className":17240},[4991]," Starting container...",[4880,17243,17245],{"className":17244},[3412],[3410,17246,17248],{"className":17247},[4926],"[Dokploy] ✓ Deployment #1 successful! Service is running.",[4880,17250,17252],{"className":17251},[3412],[3410,17253,17255],{"className":17254},[4926],"[Dokploy] Available at: https:\u002F\u002Fmyapi.pp.ua",[3348,17257,17258],{},"Після успішного деплою перевірте застосунок:",[4876,17260,17262,17271,17275,17278,17286,17289,17292],{"title":17261},"curl — перевірка доступності задеплоєного API",[4880,17263,17265,3572,17268],{"className":17264},[3412],[3410,17266,4887],{"className":17267},[4886],[3366,17269,17270],{},"curl https:\u002F\u002Fmyapi.pp.ua\u002F",[4880,17272,17274],{"className":17273},[3412],"{\"message\":\"Hello from Dokploy!\",\"environment\":\"Production\",\"version\":\"1.0.0\"}",[4880,17276],{"className":17277},[3412],[4880,17279,17281,3572,17284],{"className":17280},[3412],[3410,17282,4887],{"className":17283},[4886],[3366,17285,12689],{},[4880,17287,12696],{"className":17288},[3412],[4880,17290,12704],{"className":17291},[3412],[4880,17293,17295],{"className":17294},[3412],[3410,17296,17298],{"className":17297},[4926],"strict-transport-security: max-age=31536000",[3547,17300],{},[3584,17302,17304],{"id":17303},"крок-7-автоматичний-cicd-через-github-webhook","Крок 7: Автоматичний CI\u002FCD через GitHub Webhook",[3348,17306,17307,17308,17310,17311,17313],{},"Webhook — це HTTP-запит, який GitHub надсилає на вашу адресу при кожному ",[3407,17309,14793],{},". Dokploy приймає цей запит та автоматично запускає новий деплой. Після налаштування процес розгортання повністю автоматичний: ви пишете код, виконуєте ",[3407,17312,14793],{}," — сервер оновлюється сам.",[3348,17315,17316],{},[3366,17317,17318],{},"Отримання Webhook URL у Dokploy:",[7586,17320,17321,17327,17337],{},[3622,17322,17323,17324,7086],{},"Перейдіть у налаштування вашого сервісу (вкладка ",[3366,17325,17326],{},"General",[3622,17328,17329,17330,17333,17334],{},"Знайдіть секцію ",[3366,17331,17332],{},"Webhook"," — там відображається унікальний URL вигляду ",[3407,17335,17336],{},"https:\u002F\u002Fdokploy.pp.ua\u002Fapi\u002Fdeploy\u002Fwebhook\u002Fabc123xyz456",[3622,17338,17339],{},"Скопіюйте цей URL",[3348,17341,17342],{},[3366,17343,17344],{},"Додавання Webhook у GitHub:",[7586,17346,17347,17358,17364,17372,17380,17387],{},[3622,17348,17349,17350,3994,17352,3994,17355],{},"Відкрийте GitHub repository → ",[3366,17351,16687],{},[3366,17353,17354],{},"Webhooks",[3366,17356,17357],{},"Add webhook",[3622,17359,17360,17363],{},[3366,17361,17362],{},"Payload URL:"," вставте скопійований Webhook URL",[3622,17365,17366,3572,17369],{},[3366,17367,17368],{},"Content type:",[3407,17370,17371],{},"application\u002Fjson",[3622,17373,17374,3994,17377],{},[3366,17375,17376],{},"Which events would you like to trigger this webhook?",[3366,17378,17379],{},"Just the push event",[3622,17381,17382,17383,17386],{},"Переконайтесь, що ",[3366,17384,17385],{},"Active"," увімкнено",[3622,17388,8634,17389],{},[3366,17390,17357],{},[3348,17392,17393,17394,17397,17398,17400,17401,17403,17404,17407],{},"GitHub відразу надішле тестовий ",[3407,17395,17396],{},"ping"," запит. У Dokploy у вкладці ",[3366,17399,17149],{}," ви побачите, що запит отримано (але деплой не запустився — ",[3407,17402,17396],{}," це не ",[3407,17405,17406],{},"push",").",[4876,17409,17411,17420,17424,17428,17431,17440,17444,17448,17455,17462,17465,17472],{"title":17410},"git push — автоматичний тригер деплою через webhook",[4880,17412,17414,3572,17417],{"className":17413},[3412],[3410,17415,4887],{"className":17416},[4886],[3366,17418,17419],{},"git add . && git commit -m \"feat: додати health check endpoint\"",[4880,17421,17423],{"className":17422},[3412],"[main 3f4a5b6] feat: додати health check endpoint",[4880,17425,17427],{"className":17426},[3412]," 1 file changed, 8 insertions(+)",[4880,17429],{"className":17430},[3412],[4880,17432,17434,3572,17437],{"className":17433},[3412],[3410,17435,4887],{"className":17436},[4886],[3366,17438,17439],{},"git push origin main",[4880,17441,17443],{"className":17442},[3412],"Enumerating objects: 5, done.",[4880,17445,17447],{"className":17446},[3412],"Writing objects: 100% (3\u002F3), done.",[4880,17449,17451],{"className":17450},[3412],[3410,17452,17454],{"className":17453},[4926],"To github.com:username\u002Fmy-dotnet-api.git",[4880,17456,17458],{"className":17457},[3412],[3410,17459,17461],{"className":17460},[4926],"   abc1234..3f4a5b6  main -> main",[4880,17463],{"className":17464},[3412],[4880,17466,17468],{"className":17467},[3412],[3410,17469,17471],{"className":17470},[4886],"# Через ~15 секунд у Dokploy Deployments з'явиться новий деплой:",[4880,17473,17475],{"className":17474},[3412],[3410,17476,17478],{"className":17477},[4926],"[Dokploy] Webhook received → Deployment #2 started automatically",[4147,17480,9484,17481,17483,17484,17487],{},[3366,17482,17149],{}," зберігається повна історія деплоїв з логами кожного. Якщо новий деплой зламав щось — натисніть ",[3366,17485,17486],{},"Rollback"," поряд з будь-яким попереднім успішним деплоєм. Dokploy зупинить поточний контейнер і запустить образ попередньої версії. Rollback займає 10–30 секунд.",[3547,17489],{},[3584,17491,17493],{"id":17492},"крок-8-управління-змінними-середовища","Крок 8: Управління змінними середовища",[3348,17495,17496],{},"Environment Variables — стандартний спосіб зберігання конфігурацій, чутливих до оточення: рядки підключення до баз даних, API-ключі, секретні ключі JWT тощо. Зберігати їх у коді або у файлах конфігурації у Git-репозиторії — небезпечно.",[7586,17498,17499,17504],{},[3622,17500,17501,17502],{},"У налаштуваннях сервісу перейдіть на вкладку ",[3366,17503,9978],{},[3622,17505,8634,17506,17509],{},[3366,17507,17508],{},"Add Variable"," для кожної змінної:",[3400,17511,17514],{"className":17512,"code":17513,"language":8231},[8229],"ASPNETCORE_ENVIRONMENT=Production\nConnectionStrings__DefaultConnection=Host=...;Database=...;Username=...;Password=...\nJwtSettings__Secret=your-very-long-secret-key-here\nAllowedOrigins=https:\u002F\u002Fmyapp.pp.ua,https:\u002F\u002Fwww.myapp.pp.ua\nSENTRY_DSN=https:\u002F\u002F...@sentry.io\u002F123456\n",[3407,17515,17513],{"__ignoreMap":3405},[7586,17517,17518],{"start":3425},[3622,17519,8634,17520,17522],{},[3366,17521,16711],{}," — Dokploy автоматично перезапустить контейнер з новими змінними",[4003,17524,17525,17528,17529,17531],{},[3366,17526,17527],{},"Ніколи"," не зберігайте паролі, API-ключі та connection strings у ",[3407,17530,7433],{}," або в Git-репозиторії. Якщо такі дані потрапили у публічний репозиторій — негайно скасуйте всі ключі та змініть паролі. Для production використовуйте Environment Variables у Dokploy або AWS Secrets Manager.",[3348,17533,17534,17537,17538,17541,17542,17545],{},[3366,17535,17536],{},"Перегляд логів у реальному часі"," через вкладку ",[3366,17539,17540],{},"Logs"," вашого сервісу. Це еквівалент ",[3407,17543,17544],{},"docker logs -f"," — ви бачите все, що застосунок виводить у stdout\u002Fstderr. Логи оновлюються у реальному часі через WebSocket.",[3547,17547],{},[3584,17549,17551],{"id":17550},"крок-9-обовязково-очищення-ресурсів","Крок 9: ОБОВ'ЯЗКОВО — Очищення ресурсів",[4003,17553,17554,17556],{},[3407,17555,3607],{}," коштує ~$0.052\u002Fгод без зупинки — це ~$37\u002Fмісяць. Зупиніть або видаліть instance після завершення роботи з лабораторною роботою!",[7643,17558,17559,17590],{},[7646,17560,17561],{"label":7648},[7586,17562,17563,17573],{},[3622,17564,9476,17565,3994,17567,3994,17569,3994,17571],{},[3366,17566,8613],{},[3407,17568,15032],{},[3366,17570,14626],{},[3366,17572,14629],{},[3622,17574,9476,17575,17577,17578,3994,17580,17582],{},[3366,17576,11074],{}," → оберіть виділений IP → ",[3366,17579,11086],{},[3366,17581,14646],{},[3619,17583,17584],{},[3622,17585,17586,17587,7086],{},"Увага: спочатку instance має бути видалений (або від'єднайте IP перед видаленням через ",[3366,17588,17589],{},"Disassociate Elastic IP address",[7646,17591,17592],{"label":7694},[3400,17593,17595],{"className":4390,"code":17594,"language":4392,"meta":3405,"style":3405},"REGION=\"eu-central-1\"\n\n# Від'єднати Elastic IP від instance\nASSOC_ID=$(aws ec2 describe-addresses \\\n    --allocation-ids $ALLOC_ID \\\n    --query \"Addresses[0].AssociationId\" \\\n    --output text --region $REGION)\naws ec2 disassociate-address --association-id $ASSOC_ID --region $REGION\n\n# Звільнити Elastic IP (перестати платити за нього)\naws ec2 release-address --allocation-id $ALLOC_ID --region $REGION\n\n# Видалити instance\naws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION\n",[3407,17596,17597,17605,17609,17614,17629,17637,17646,17659,17678,17682,17687,17705,17709,17714],{"__ignoreMap":3405},[3410,17598,17599,17601,17603],{"class":3412,"line":3413},[3410,17600,14677],{"class":6538},[3410,17602,10398],{"class":6300},[3410,17604,14682],{"class":4403},[3410,17606,17607],{"class":3412,"line":3419},[3410,17608,3435],{"emptyLinePlaceholder":3434},[3410,17610,17611],{"class":3412,"line":3425},[3410,17612,17613],{"class":4462},"# Від'єднати Elastic IP від instance\n",[3410,17615,17616,17619,17621,17623,17625,17627],{"class":3412,"line":3431},[3410,17617,17618],{"class":6538},"ASSOC_ID",[3410,17620,7352],{"class":6300},[3410,17622,4400],{"class":4399},[3410,17624,4404],{"class":4403},[3410,17626,11179],{"class":4403},[3410,17628,4411],{"class":4410},[3410,17630,17631,17633,17635],{"class":3412,"line":3438},[3410,17632,11186],{"class":4416},[3410,17634,11189],{"class":6538},[3410,17636,4411],{"class":4410},[3410,17638,17639,17641,17644],{"class":3412,"line":3444},[3410,17640,4438],{"class":4416},[3410,17642,17643],{"class":4403}," \"Addresses[0].AssociationId\"",[3410,17645,4411],{"class":4410},[3410,17647,17648,17650,17652,17654,17657],{"class":3412,"line":3450},[3410,17649,4448],{"class":4416},[3410,17651,4451],{"class":4403},[3410,17653,4454],{"class":4416},[3410,17655,17656],{"class":6538}," $REGION",[3410,17658,7378],{"class":6300},[3410,17660,17661,17663,17665,17668,17671,17674,17676],{"class":3412,"line":3456},[3410,17662,4400],{"class":4399},[3410,17664,4404],{"class":4403},[3410,17666,17667],{"class":4403}," disassociate-address",[3410,17669,17670],{"class":4416}," --association-id",[3410,17672,17673],{"class":6538}," $ASSOC_ID",[3410,17675,4454],{"class":4416},[3410,17677,14715],{"class":6538},[3410,17679,17680],{"class":3412,"line":3462},[3410,17681,3435],{"emptyLinePlaceholder":3434},[3410,17683,17684],{"class":3412,"line":3468},[3410,17685,17686],{"class":4462},"# Звільнити Elastic IP (перестати платити за нього)\n",[3410,17688,17689,17691,17693,17696,17699,17701,17703],{"class":3412,"line":3474},[3410,17690,4400],{"class":4399},[3410,17692,4404],{"class":4403},[3410,17694,17695],{"class":4403}," release-address",[3410,17697,17698],{"class":4416}," --allocation-id",[3410,17700,11189],{"class":6538},[3410,17702,4454],{"class":4416},[3410,17704,14715],{"class":6538},[3410,17706,17707],{"class":3412,"line":3480},[3410,17708,3435],{"emptyLinePlaceholder":3434},[3410,17710,17711],{"class":3412,"line":3486},[3410,17712,17713],{"class":4462},"# Видалити instance\n",[3410,17715,17716,17718,17720,17722,17724,17726,17728],{"class":3412,"line":3491},[3410,17717,4400],{"class":4399},[3410,17719,4404],{"class":4403},[3410,17721,14733],{"class":4403},[3410,17723,14708],{"class":4416},[3410,17725,7891],{"class":6538},[3410,17727,4454],{"class":4416},[3410,17729,14715],{"class":6538},[4876,17731,17733,17742,17745,17749,17753,17762,17771,17775],{"title":17732},"aws ec2 terminate-instances — видалення dokploy-server",[4880,17734,17736,3572,17739],{"className":17735},[3412],[3410,17737,4887],{"className":17738},[4886],[3366,17740,17741],{},"aws ec2 terminate-instances --instance-ids $INSTANCE_ID --region eu-central-1",[4880,17743,4970],{"className":17744},[3412],[4880,17746,17748],{"className":17747},[3412],"    \"TerminatingInstances\": [{",[4880,17750,17752],{"className":17751},[3412],"        \"InstanceId\": \"i-1234567890abcdef0\",",[4880,17754,17756,17757,17761],{"className":17755},[3412],"        \"CurrentState\": { \"Name\": ",[3410,17758,17760],{"className":17759},[4991],"\"shutting-down\""," },",[4880,17763,17765,17766,17770],{"className":17764},[3412],"        \"PreviousState\": { \"Name\": ",[3410,17767,17769],{"className":17768},[4926],"\"running\""," }",[4880,17772,17774],{"className":17773},[3412],"    }]",[4880,17776,5000],{"className":17777},[3412],[3547,17779],{},[3348,17781,17782],{},[3351,17783],{"alt":17784,"className":17785,"src":17786},"EC2 summary mindmap key concepts instance types AMI pricing security EBS",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F15.png",[3358,17788,17790],{"id":17789},"резюме","Резюме",[3725,17792,17793,17815,17836,17857,17880,17899],{},[3728,17794,17796],{"icon":3738,"title":17795},"EC2 Instances",[3619,17797,17798,17803,17812],{},[3622,17799,17800,17802],{},[3366,17801,8609],{}," — віртуальні сервери у хмарі. Платите лише за час роботи.",[3622,17804,17805,17808,17809,17811],{},[3366,17806,17807],{},"Instance Types:"," T (burstable, Free Tier ",[3407,17810,3581],{},"), M (стабільний), C (CPU), R (RAM), I (Storage).",[3622,17813,17814],{},"Тип завжди можна змінити: зупинити instance → змінити тип → запустити.",[3728,17816,17818],{"icon":3754,"title":17817},"Storage",[3619,17819,17820,17826],{},[3622,17821,17822,17825],{},[3366,17823,17824],{},"AMI"," — шаблон ОС. Перевіряйте актуальний ID для регіону. Custom AMI для Auto Scaling.",[3622,17827,17828,17831,17832,17835],{},[3366,17829,17830],{},"EBS"," — мережеві диски. ",[3407,17833,17834],{},"gp3"," для більшості задач. Snapshots для резервних копій.",[3728,17837,17840],{"icon":17838,"title":17839},"i-heroicons-shield-check","Networking & Security",[3619,17841,17842,17851],{},[3622,17843,17844,17847,17848,17850],{},[3366,17845,17846],{},"Security Groups:"," stateful файрвол. SSH лише з вашого IP. Ніколи ",[3407,17849,5402],{}," для порту 22!",[3622,17852,17853,17856],{},[3366,17854,17855],{},"Elastic IP:"," стала публічна адреса. Безкоштовна при прикріпленому запущеному instance.",[3728,17858,17861],{"icon":17859,"title":17860},"i-heroicons-currency-dollar","Pricing",[3619,17862,17863,17869,17874],{},[3622,17864,17865,17868],{},[3366,17866,17867],{},"On-Demand:"," гнучко, без контракту.",[3622,17870,17871,17873],{},[3366,17872,4632],{}," знижка 30–75% на 1-3 роки.",[3622,17875,17876,17879],{},[3366,17877,17878],{},"Spot:"," 60–90% знижка, переривувані. Для batch-задач та CI\u002FCD.",[3728,17881,17883],{"icon":3730,"title":17882},"Automation",[3619,17884,17885,17891],{},[3622,17886,17887,17890],{},[3366,17888,17889],{},"User Data:"," bash\u002FPowerShell скрипт при першому запуску — автоматизація встановлення ПЗ.",[3622,17892,17893,9643,17896,17898],{},[3366,17894,17895],{},"IMDS",[3407,17897,7132],{},"): отримання метаданих та IAM credentials без Access Keys.",[3728,17900,17903],{"icon":17901,"title":17902},"i-heroicons-rocket-launch","Deployment",[3619,17904,17905,17915],{},[3622,17906,17907,17910,17911,17914],{},[3366,17908,17909],{},"Linux:"," SSH + SCP → systemd service (",[3407,17912,17913],{},"Restart=always",") → nginx reverse proxy.",[3622,17916,17917,17919,17920,17922],{},[3366,17918,13857],{}," RDP підключення → IIS + .NET 10 Hosting Bundle → ",[3407,17921,14350],{}," у PowerShell.",[3547,17924],{},[3348,17926,17927],{},[3351,17928],{"alt":17929,"className":17930,"src":17931},"EC2 practical tasks and lab exercises for .NET developers",[3355],"\u002Fimages\u002Faws\u002Fec2\u002F16.png",[3358,17933,17935],{"id":17934},"практичні-завдання","Практичні завдання",[3584,17937,17939],{"id":17938},"рівень-1-базовий","Рівень 1 (Базовий)",[3348,17941,17942,17945,17946,3706,17948,17950],{},[3366,17943,17944],{},"Завдання 1."," Поясніть різницю між ",[3407,17947,3581],{},[3407,17949,3653],{},". Коли ви б обрали кожен? Що таке CPU Credits у T-instances?",[3348,17952,17953,17956,17957,17959],{},[3366,17954,17955],{},"Завдання 2."," Чому небезпечно відкривати SSH порт (22) для ",[3407,17958,5402],{},"? Як правильно налаштувати Security Group для SSH?",[3584,17961,17963],{"id":17962},"рівень-2-практичний","Рівень 2 (Практичний)",[3348,17965,17966,17969,17970,17972,17973,17976],{},[3366,17967,17968],{},"Завдання 3."," Задеплойте ASP.NET Core API на Linux EC2. Налаштуйте systemd service з ",[3407,17971,17913],{},". Перевірте, що після ",[3407,17974,17975],{},"sudo reboot"," API автоматично запускається.",[3348,17978,17979,17982],{},[3366,17980,17981],{},"Завдання 4."," Напишіть User Data скрипт для Ubuntu EC2, який автоматично встановлює .NET 10 та копіює з S3 і запускає ваш API. Протестуйте: запустіть instance і без SSH підключення перевірте, що API відповідає.",[3584,17984,17986],{"id":17985},"рівень-3-архітектура","Рівень 3 (Архітектура)",[3348,17988,17989,17992,17993,17996],{},[3366,17990,17991],{},"Завдання 5."," Спроектуйте EC2-архітектуру для .NET API з наступними вимогами: Auto Scaling Group (мін. 2, макс. 10 instances), ALB для балансування, окремий EBS том для логів, custom AMI з встановленим .NET, Health Check через ",[3407,17994,17995],{},"\u002Fhealth"," endpoint, Spot Instances для економії. Намалюйте схему у PlantUML.",[17998,17999,18000],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}",{"title":3405,"searchDepth":3419,"depth":3419,"links":18002},[18003,18004,18010,18019,18023,18028,18033,18037,18043,18044,18049,18050,18051,18056,18057,18065,18075,18083,18094,18095],{"id":3360,"depth":3419,"text":3361},{"id":3558,"depth":3419,"text":3559,"children":18005},[18006,18007,18008,18009],{"id":3586,"depth":3425,"text":3587},{"id":3665,"depth":3425,"text":3666},{"id":3683,"depth":3425,"text":3684},{"id":3699,"depth":3425,"text":3700},{"id":3764,"depth":3419,"text":3765,"children":18011},[18012,18014,18016,18018],{"id":3926,"depth":3425,"text":18013},"Стан stopped — зупинений, але не видалений",{"id":3980,"depth":3425,"text":18015},"Стан terminated — незворотнє видалення",{"id":4012,"depth":3425,"text":18017},"Стан rebooting — перезавантаження без зміни хосту",{"id":4030,"depth":3425,"text":4031},{"id":4176,"depth":3419,"text":4177,"children":18020},[18021,18022],{"id":4305,"depth":3425,"text":4306},{"id":4365,"depth":3425,"text":4366},{"id":4572,"depth":3419,"text":4573,"children":18024},[18025,18026,18027],{"id":4583,"depth":3425,"text":4584},{"id":4608,"depth":3425,"text":4609},{"id":4641,"depth":3425,"text":4642},{"id":4801,"depth":3419,"text":4802,"children":18029},[18030,18031,18032],{"id":4825,"depth":3425,"text":4826},{"id":4853,"depth":3425,"text":4854},{"id":5003,"depth":3425,"text":5004},{"id":5284,"depth":3419,"text":5285,"children":18034},[18035,18036],{"id":5329,"depth":3425,"text":5330},{"id":5426,"depth":3425,"text":5427},{"id":5521,"depth":3419,"text":5522,"children":18038},[18039,18040,18041,18042],{"id":5697,"depth":3425,"text":5698},{"id":5731,"depth":3425,"text":5732},{"id":5770,"depth":3425,"text":5771},{"id":5808,"depth":3425,"text":5809},{"id":5832,"depth":3419,"text":5833},{"id":5991,"depth":3419,"text":5992,"children":18045},[18046,18047,18048],{"id":6128,"depth":3425,"text":6129},{"id":6244,"depth":3425,"text":6245},{"id":6468,"depth":3425,"text":6469},{"id":6838,"depth":3419,"text":6839},{"id":7115,"depth":3419,"text":7116},{"id":7415,"depth":3419,"text":7416,"children":18052},[18053,18054,18055],{"id":7583,"depth":3425,"text":7584},{"id":7640,"depth":3425,"text":7641},{"id":7912,"depth":3425,"text":7913},{"id":8091,"depth":3419,"text":8092},{"id":8172,"depth":3419,"text":8173,"children":18058},[18059,18060,18061,18062,18063,18064],{"id":8183,"depth":3425,"text":8184},{"id":8236,"depth":3425,"text":8237},{"id":8301,"depth":3425,"text":8302},{"id":8327,"depth":3425,"text":8328},{"id":8438,"depth":3425,"text":8439},{"id":8506,"depth":3425,"text":8507},{"id":8589,"depth":3419,"text":8590,"children":18066},[18067,18068,18069,18070,18071,18072,18073,18074],{"id":8596,"depth":3425,"text":8597},{"id":9453,"depth":3425,"text":9454},{"id":9664,"depth":3425,"text":9665},{"id":9821,"depth":3425,"text":9822},{"id":10176,"depth":3425,"text":10177},{"id":10354,"depth":3425,"text":10355},{"id":10540,"depth":3425,"text":10541},{"id":11027,"depth":3425,"text":11028},{"id":13098,"depth":3419,"text":13099,"children":18076},[18077,18078,18079,18080,18081,18082],{"id":13105,"depth":3425,"text":13106},{"id":13563,"depth":3425,"text":13564},{"id":13874,"depth":3425,"text":13875},{"id":14078,"depth":3425,"text":14079},{"id":14425,"depth":3425,"text":14426},{"id":14606,"depth":3425,"text":14607},{"id":14767,"depth":3419,"text":14768,"children":18084},[18085,18086,18087,18088,18089,18090,18091,18092,18093],{"id":14996,"depth":3425,"text":14997},{"id":15724,"depth":3425,"text":15725},{"id":16080,"depth":3425,"text":16081},{"id":16552,"depth":3425,"text":16553},{"id":16734,"depth":3425,"text":16735},{"id":16970,"depth":3425,"text":16971},{"id":17303,"depth":3425,"text":17304},{"id":17492,"depth":3425,"text":17493},{"id":17550,"depth":3425,"text":17551},{"id":17789,"depth":3419,"text":17790},{"id":17934,"depth":3419,"text":17935,"children":18096},[18097,18098,18099],{"id":17938,"depth":3425,"text":17939},{"id":17962,"depth":3425,"text":17963},{"id":17985,"depth":3425,"text":17986},"Повне керівництво з Amazon EC2 для .NET розробників. Instance Types, AMI, Pricing Models, Security Groups, EBS, запуск .NET 10 на Linux та ASP.NET на Windows Server з IIS від А до Я.","md",null,{},{"title":3234,"description":18100},"mWYngftAJziYstTxBCsLDpW44TDvU46NKMLzLqta9l4",[18107,18109],{"title":3230,"path":3231,"stem":3232,"description":18108,"children":-1},"Повний довідник AWS CLI команд для ECR та ECS — аутентифікація, репозиторії, кластери, сервіси, мережа, балансувальник, автомасштабування, логи. Усі важливі команди з прикладами та очікуваним виводом.",{"title":3238,"path":3239,"stem":3240,"description":18110,"children":-1},"Повний довідник AWS CLI команд для Amazon EC2 — instances, AMI, Key Pairs, Security Groups, Elastic IP, EBS, snapshots, IAM Instance Profile, tags. Усі важливі команди з прикладами та очікуваним виводом.",1782371304092]