Для CONNECT порт не опція 🧩
Зовнішній проксі працював. Окрема перевірка успішно проходила TLS, авторизацію, публічний HTTPS і DNS.
Але Transparent Gateway не додавав його до активного пулу.
Перед додаванням кожного проксі validator перевіряє, чи може той передавати реальні запити. Для HTTPS він просить проксі відкрити тунель до потрібного сервера за допомогою команди
Validator надсилав такий запит:
Тут указаний домен, але немає порту.
Домен
Правильний запит:
Окрема перевірка проксі додавала
Виправлення звелося до простого правила: під час створення
Після виправлення validator надіслав правильну адресу:
Зовнішній проксі пройшов перевірку й потрапив до активного пулу:
Тепер у gateway є два перевірені маршрути: локальний проксі для лабораторного echo-сервісу та зовнішній — для публічного HTTPS і DNS ✅
Наступним кроком перевірю обидва маршрути з окремої клієнтської VM.
Зовнішній проксі працював. Окрема перевірка успішно проходила TLS, авторизацію, публічний HTTPS і DNS.
Але Transparent Gateway не додавав його до активного пулу.
Перед додаванням кожного проксі validator перевіряє, чи може той передавати реальні запити. Для HTTPS він просить проксі відкрити тунель до потрібного сервера за допомогою команди
CONNECT.Validator надсилав такий запит:
CONNECT echo.devdays.net.ua HTTP/1.1
Тут указаний домен, але немає порту.
Домен
echo.devdays.net.ua визначає сервер, а порт 443 — HTTPS-сервіс на ньому. Без порту проксі отримує неповну адресу й не знає, куди саме відкривати тунель.Правильний запит:
CONNECT echo.devdays.net.ua:443 HTTP/1.1
Окрема перевірка проксі додавала
:443, тому працювала. Validator цього не робив, тому проксі правильно відхиляв його запит.Виправлення звелося до простого правила: під час створення
CONNECT завжди додавати порт, навіть якщо він стандартний для HTTPS.Після виправлення validator надіслав правильну адресу:
echo.devdays.net.ua:443
Зовнішній проксі пройшов перевірку й потрапив до активного пулу:
active: 2
validated: 2
Тепер у gateway є два перевірені маршрути: локальний проксі для лабораторного echo-сервісу та зовнішній — для публічного HTTPS і DNS ✅
Наступним кроком перевірю обидва маршрути з окремої клієнтської VM.
На кілька постів зверну в алгоритми 🧠
На кілька постів знову відійду від Transparent Gateway. Цього разу — в алгоритми та структури даних.
Зараз готуюся до олімпіади з програмування. І ця підготовка потроху змінює моє ставлення до речей, які раніше здавалися необов’язковими.
Програмую вже близько десяти років. Глибокого знання алгоритмів у мене немає, і для задач, із якими стикався в роботі, воно досі не було необхідним.
Це не історія про те, що колись усе вивчив, а потім просто не користувався. Багатьох алгоритмів я не знав і досі не знаю. Нічого страшного в цьому не бачу: до своєї мрії стати кращим програмістом іду поступово й кидати цей шлях не збираюся.
Алгоритми є майже в кожному плані навчання програмуванню, тому свого часу взявся за Кормена. Спроба була чесною, але недовгою: від книги хотілося спати значно сильніше, ніж розбирати чергове доведення 😴
Після цього прочитав «Грокаємо алгоритми». Вона виявилася набагато доступнішою і дала загальне уявлення про пошук, сортування, графи та складність обчислень.
Але тоді враження залишилося приблизно таким: алгоритми — цікава штука для людей з особливими інтересами, яким від усієї цієї теорії чомусь не хочеться спати.
Водночас саме програмування мене драйвило й продовжує драйвити. Тому особливої суперечності тут не бачив: код пишеться, проєкти працюють, а Кормен спокійно стоїть на полиці.
Підготовка до олімпіади показала інший бік програмування. Тут недостатньо знайти будь-яке правильне рішення. Потрібно побачити структуру задачі й вибрати спосіб, який не з’їсть увесь час або пам’ять.
Тому наступні кілька постів будуть про алгоритми. Трохи відпочинемо від серверів, проксі та розгортання — і подивимося, навіщо всі ці дерева взагалі вигадали 🌲
На кілька постів знову відійду від Transparent Gateway. Цього разу — в алгоритми та структури даних.
Зараз готуюся до олімпіади з програмування. І ця підготовка потроху змінює моє ставлення до речей, які раніше здавалися необов’язковими.
Програмую вже близько десяти років. Глибокого знання алгоритмів у мене немає, і для задач, із якими стикався в роботі, воно досі не було необхідним.
Це не історія про те, що колись усе вивчив, а потім просто не користувався. Багатьох алгоритмів я не знав і досі не знаю. Нічого страшного в цьому не бачу: до своєї мрії стати кращим програмістом іду поступово й кидати цей шлях не збираюся.
Алгоритми є майже в кожному плані навчання програмуванню, тому свого часу взявся за Кормена. Спроба була чесною, але недовгою: від книги хотілося спати значно сильніше, ніж розбирати чергове доведення 😴
Після цього прочитав «Грокаємо алгоритми». Вона виявилася набагато доступнішою і дала загальне уявлення про пошук, сортування, графи та складність обчислень.
Але тоді враження залишилося приблизно таким: алгоритми — цікава штука для людей з особливими інтересами, яким від усієї цієї теорії чомусь не хочеться спати.
Водночас саме програмування мене драйвило й продовжує драйвити. Тому особливої суперечності тут не бачив: код пишеться, проєкти працюють, а Кормен спокійно стоїть на полиці.
Підготовка до олімпіади показала інший бік програмування. Тут недостатньо знайти будь-яке правильне рішення. Потрібно побачити структуру задачі й вибрати спосіб, який не з’їсть увесь час або пам’ять.
Тому наступні кілька постів будуть про алгоритми. Трохи відпочинемо від серверів, проксі та розгортання — і подивимося, навіщо всі ці дерева взагалі вигадали 🌲
👀1
Правильного результату для олімпіади недостатньо ⏱️
Першим бажанням в олімпіадній задачі часто стає звичайний перебір.
Потрібно знайти пару елементів — переберу всі пари. Потрібно перевірити відрізки масиву — перевірю кожен відрізок. На прикладах з умови все працює, відповідь правильна, можна відправляти.
А потім тести повідомляють, що чекати до завтра вони не збираються 😅
Наприклад, у масиві 200 000 елементів подвійний цикл може виконати близько 40 мільярдів операцій:
Логічно код може бути бездоганним. Але за відведену секунду він просто не встигне отримати результат.
Рішення зі складністю
Відповідь та сама, але різниця у швидкості — у тисячі разів.
Те саме стосується пам’яті. Можна створити таблицю для всіх можливих пар і навіть правильно її заповнити. Але якщо вона не поміститься в доступну пам’ять, правильність уже нікого не врятує.
Тому обмеження в умові — це частина задачі. Вони підказують, чи можна використовувати перебір, чи доведеться шукати інший підхід.
Поступово звикаю перед написанням коду ставити додаткові запитання:
• скільки буде даних;
• які операції повторюються;
• що доводиться рахувати знову;
• чи можна один раз зберегти частину результату;
• чи існує структура даних саме для таких операцій.
Одне з таких запитань і привело мене до дерева Фенвіка.
Першим бажанням в олімпіадній задачі часто стає звичайний перебір.
Потрібно знайти пару елементів — переберу всі пари. Потрібно перевірити відрізки масиву — перевірю кожен відрізок. На прикладах з умови все працює, відповідь правильна, можна відправляти.
А потім тести повідомляють, що чекати до завтра вони не збираються 😅
Наприклад, у масиві 200 000 елементів подвійний цикл може виконати близько 40 мільярдів операцій:
200 000 × 200 000 = 40 000 000 000
Логічно код може бути бездоганним. Але за відведену секунду він просто не встигне отримати результат.
Рішення зі складністю
O(n log n) для того самого обсягу даних потребуватиме приблизно 3,6 мільйона кроків:200 000 × log₂(200 000) ≈ 3 600 000
Відповідь та сама, але різниця у швидкості — у тисячі разів.
Те саме стосується пам’яті. Можна створити таблицю для всіх можливих пар і навіть правильно її заповнити. Але якщо вона не поміститься в доступну пам’ять, правильність уже нікого не врятує.
Тому обмеження в умові — це частина задачі. Вони підказують, чи можна використовувати перебір, чи доведеться шукати інший підхід.
Поступово звикаю перед написанням коду ставити додаткові запитання:
• скільки буде даних;
• які операції повторюються;
• що доводиться рахувати знову;
• чи можна один раз зберегти частину результату;
• чи існує структура даних саме для таких операцій.
Одне з таких запитань і привело мене до дерева Фенвіка.
🤯1
Нуль задач і значно більше мотивації 🔥
Вчора взяв участь в олімпіаді з програмування у складі команди
Очікування були скромними, але завдання все одно виявилися значно складнішими, ніж очікував. У підсумку команда не розв’язала жодної задачі.
У таблиці команди з таким результатом опинилися в діапазоні 426–605. Окремого місця нам навіть не виділили — настільки впевнено розташувалися у хвості 😅
Для порівняння: минулого року розв’язували по три-чотири задачі в кожному турі й дійшли щонайменше до другого. Можливо, навіть до третього — точно вже не пам’ятаю, тому вигадувати не буду.
Вітаю команду
Окремий респект команді
Минулорічна олімпіада залишила змішані почуття й багато роздратування. Цього разу результат у таблиці значно гірший, але реакція зовсім інша. Замість бажання посперечатися із задачами з’явився інтерес: як вони насправді розв’язуються і яких знань мені не вистачило.
Олімпіада добре показала слабкі місця. Недостатньо знати, що графи, дерева й динамічне програмування десь існують. Потрібно за обмежений час упізнати потрібну ідею, оцінити її складність і перетворити на робочий код.
Саме над цим і будемо працювати. Розберемо задачі, підтягнемо алгоритми й наступного разу прийдемо підготовленішими.
Сьогоднішню таблицю вже не змінимо. А от те, з чим прийдемо на наступну олімпіаду, — цілком 💪
Вчора взяв участь в олімпіаді з програмування у складі команди
PDAU_RootAccess.Очікування були скромними, але завдання все одно виявилися значно складнішими, ніж очікував. У підсумку команда не розв’язала жодної задачі.
У таблиці команди з таким результатом опинилися в діапазоні 426–605. Окремого місця нам навіть не виділили — настільки впевнено розташувалися у хвості 😅
Для порівняння: минулого року розв’язували по три-чотири задачі в кожному турі й дійшли щонайменше до другого. Можливо, навіть до третього — точно вже не пам’ятаю, тому вигадувати не буду.
Вітаю команду
cViVCNUFT_ComputerWorms — Haidei, Hrom і CHEREMUKHIN — із перемогою та чудовим результатом 🏆Окремий респект команді
sPolit_vozduhbenders — Yabchenko, Sadovnikov і Khalin. Команда політеху посіла восьме місце. Дуже крутий результат 👏Минулорічна олімпіада залишила змішані почуття й багато роздратування. Цього разу результат у таблиці значно гірший, але реакція зовсім інша. Замість бажання посперечатися із задачами з’явився інтерес: як вони насправді розв’язуються і яких знань мені не вистачило.
Олімпіада добре показала слабкі місця. Недостатньо знати, що графи, дерева й динамічне програмування десь існують. Потрібно за обмежений час упізнати потрібну ідею, оцінити її складність і перетворити на робочий код.
Саме над цим і будемо працювати. Розберемо задачі, підтягнемо алгоритми й наступного разу прийдемо підготовленішими.
Сьогоднішню таблицю вже не змінимо. А от те, з чим прийдемо на наступну олімпіаду, — цілком 💪
❤2🥰1
Як дерево Фенвіка зберігає суми 🌲
Дерево Фенвіка корисне в задачах, де числа в масиві змінюються, а суми потрібно рахувати багато разів.
Візьмемо вісім чисел:
Нехай потрібно виконувати дві операції:
• додати число до одного елемента;
• знайти суму від початку масиву до вибраної позиції.
Звичайний цикл легко знайде суму. Але для сьомої позиції він прочитає сім елементів. Якщо масив містить сотні тисяч чисел і таких запитів багато, постійний перебір стає дорогим.
Можна заздалегідь порахувати всі накопичені суми:
Тоді сума перших семи чисел одразу дорівнює
Але після зміни третього числа доведеться виправити суми для третьої, четвертої, п’ятої та всіх наступних позицій. Швидке читання отримали, зате оновлення стало повільним.
Дерево Фенвіка зберігає не всі накопичені суми, а суми окремих блоків. Для восьми позицій вони виглядають так:
Щоб знайти суму перших семи чисел, не потрібно читати всі сім:
У дереві це три комірки:
Вони не перетинаються й разом точно покривають позиції від першої до сьомої.
Якщо змінюється третє число, потрібно оновити лише блоки, до яких воно належить:
Тобто комірки:
Ось і вся основна ідея: дерево Фенвіка зберігає масив як набір блоків різного розміру. Великий потрібний відрізок складається з кількох готових блоків, а одна зміна торкається лише тих блоків, які містять змінений елемент.
Залишається зрозуміти, як програма знаходить ці блоки без окремої таблиці переходів.
Для цього й використовується дивний вираз
Дерево Фенвіка корисне в задачах, де числа в масиві змінюються, а суми потрібно рахувати багато разів.
Візьмемо вісім чисел:
3 1 4 1 5 9 2 6
Нехай потрібно виконувати дві операції:
• додати число до одного елемента;
• знайти суму від початку масиву до вибраної позиції.
Звичайний цикл легко знайде суму. Але для сьомої позиції він прочитає сім елементів. Якщо масив містить сотні тисяч чисел і таких запитів багато, постійний перебір стає дорогим.
Можна заздалегідь порахувати всі накопичені суми:
3 4 8 9 14 23 25 31
Тоді сума перших семи чисел одразу дорівнює
25.Але після зміни третього числа доведеться виправити суми для третьої, четвертої, п’ятої та всіх наступних позицій. Швидке читання отримали, зате оновлення стало повільним.
Дерево Фенвіка зберігає не всі накопичені суми, а суми окремих блоків. Для восьми позицій вони виглядають так:
позиція 1 зберігає суму [1]
позиція 2 зберігає суму [1–2]
позиція 3 зберігає суму [3]
позиція 4 зберігає суму [1–4]
позиція 5 зберігає суму [5]
позиція 6 зберігає суму [5–6]
позиція 7 зберігає суму [7]
позиція 8 зберігає суму [1–8]
Щоб знайти суму перших семи чисел, не потрібно читати всі сім:
[1–4] + [5–6] + [7]
У дереві це три комірки:
tree[4] + tree[6] + tree[7]
Вони не перетинаються й разом точно покривають позиції від першої до сьомої.
Якщо змінюється третє число, потрібно оновити лише блоки, до яких воно належить:
[3]
[1–4]
[1–8]
Тобто комірки:
tree[3]
tree[4]
tree[8]
Ось і вся основна ідея: дерево Фенвіка зберігає масив як набір блоків різного розміру. Великий потрібний відрізок складається з кількох готових блоків, а одна зміна торкається лише тих блоків, які містять змінений елемент.
Залишається зрозуміти, як програма знаходить ці блоки без окремої таблиці переходів.
Для цього й використовується дивний вираз
i & -i.Навіщо дереву Фенвіка
У дереві Фенвіка кожна позиція зберігає суму блоку. Розмір цього блоку можна отримати так:
Першого разу цей вираз виглядає як чаклунство. Насправді він просто залишає наймолодший установлений біт числа — крайню праву одиницю в його двійковому записі.
Розберемо число
Щоб отримати
Тепер виконуємо побітове
Отримали
Отже:
Саме два елементи входять до блоку, який закінчується на шостій позиції:
Інший приклад — позиція
Тому четверта комірка зберігає блок із чотирьох чисел:
Для позиції
Отже, сьома комірка відповідає лише за себе:
Тепер можна знайти суму перших семи чисел.
Починаємо з позиції
Шоста позиція зберігає блок із двох чисел. Додаємо
Четверта зберігає чотири числа:
Дійшли до нуля — сума готова:
У коді це виглядає так:
Під час оновлення рухаємося в інший бік. Якщо змінилася третя позиція, потрібно оновити всі більші блоки, які її містять:
Для цього розмір блоку не віднімаємо, а додаємо:
Замість проходу по всьому масиву кожна операція відвідує лише кілька комірок. Для мільйона елементів це приблизно двадцять переходів.
Концепція справді проста: зберігаємо суми правильно підібраних блоків і пересуваємося між ними. Але щоб побачити цю простоту за двійковими числами та
На цьому короткий відступ в алгоритми завершую. Дерево Фенвіка не зробило з мене олімпіадного чемпіона, але добре показало, скільки зайвої роботи можна прибрати правильною структурою даних.
У наступному пості повернуся до Transparent Gateway. Зовнішній проксі вже потрапив до активного пулу — залишилося провести через нього запит із клієнтської VM і перевірити весь маршрут, а не лише окремі його частини.
i & -i 🧩У дереві Фенвіка кожна позиція зберігає суму блоку. Розмір цього блоку можна отримати так:
i & -i
Першого разу цей вираз виглядає як чаклунство. Насправді він просто залишає наймолодший установлений біт числа — крайню праву одиницю в його двійковому записі.
Розберемо число
6:6 = 00000110
Щоб отримати
-6, комп’ютер інвертує біти й додає одиницю:00000110
↓ інвертуємо
11111001
↓ додаємо 1
11111010
Тепер виконуємо побітове
AND:00000110
& 11111010
----------
00000010
Отримали
2.Отже:
6 & -6 = 2
Саме два елементи входять до блоку, який закінчується на шостій позиції:
[5–6]
Інший приклад — позиція
4:4 = 00000100
4 & -4 = 4
Тому четверта комірка зберігає блок із чотирьох чисел:
[1–4]
Для позиції
7 результат дорівнює одиниці:7 = 00000111
7 & -7 = 1
Отже, сьома комірка відповідає лише за себе:
[7]
Тепер можна знайти суму перших семи чисел.
Починаємо з позиції
7. Її блок має розмір 1, тому додаємо tree[7] і переходимо до позиції 6:7 - 1 = 6
Шоста позиція зберігає блок із двох чисел. Додаємо
tree[6] і переходимо до четвертої:6 - 2 = 4
Четверта зберігає чотири числа:
4 - 4 = 0
Дійшли до нуля — сума готова:
tree[7] + tree[6] + tree[4]
У коді це виглядає так:
def prefix_sum(i):
result = 0
while i > 0:
result += tree[i]
i -= i & -i
return result
Під час оновлення рухаємося в інший бік. Якщо змінилася третя позиція, потрібно оновити всі більші блоки, які її містять:
3 → 4 → 8
Для цього розмір блоку не віднімаємо, а додаємо:
def add(i, value):
while i <= n:
tree[i] += value
i += i & -i
Замість проходу по всьому масиву кожна операція відвідує лише кілька комірок. Для мільйона елементів це приблизно двадцять переходів.
Концепція справді проста: зберігаємо суми правильно підібраних блоків і пересуваємося між ними. Але щоб побачити цю простоту за двійковими числами та
i & -i, довелося добряче посидіти.На цьому короткий відступ в алгоритми завершую. Дерево Фенвіка не зробило з мене олімпіадного чемпіона, але добре показало, скільки зайвої роботи можна прибрати правильною структурою даних.
У наступному пості повернуся до Transparent Gateway. Зовнішній проксі вже потрапив до активного пулу — залишилося провести через нього запит із клієнтської VM і перевірити весь маршрут, а не лише окремі його частини.
Клієнтський трафік пройшов через обидва проксі 🧪
Алгоритмічний відступ завершено, повертаюся до Transparent Gateway.
Перед паузою зовнішній TLS-проксі нарешті пройшов validator і потрапив до активного пулу. Тепер у gateway є два маршрути:
Але перевірка проксі з самого gateway доводить лише те, що gateway може до них підключитися. Клієнтський трафік усе ще міг не перехоплюватися, піти неправильним маршрутом або взагалі обійти gateway.
Тому фінальну перевірку запускаю з окремої клієнтської VM. На ній немає адрес проксі, паролів або коду проєкту. Програми відкривають звичайні з’єднання, а єдиний маршрут за замовчуванням веде через Transparent Gateway.
Команда запускається з довіреної машини:
Параметр
Спочатку клієнт звертається до локального echo-сервісу:
Цей маршрут перевіряє перехоплення TCP-з’єднання, relay, авторизацію на проксі та повернення відповіді всередині стенда.
Потім клієнт виконує DNS-запит і встановлює HTTPS-з’єднання з публічним echo-сервісом:
Публічний сервіс повертає свіжий ідентифікатор запиту та адресу, з якої побачив з’єднання. Перевірка звіряє її з вихідною адресою зовнішнього проксі в активному пулі.
Для локального маршруту виконується така сама перевірка. Тому випадкова відповідь від іншого сервісу або пряме з’єднання клієнта за успіх не зарахуються.
Окремо клієнт надсилає три UDP-пакети не на DNS-порт. Transparent Gateway підтримує DNS через UDP, але довільний UDP-трафік через TCP-проксі передати не може. Такий трафік повинен блокуватися, а не тихо виходити в обхід проксі.
Після тесту лічильник правила
Скорочений результат:
Тепер перевірені не лише окремі контейнери та проксі. Звичайний клієнт без власних налаштувань проксі пройшов через gateway до локального й публічного echo-сервісів, а непідтримуваний трафік не зміг обійти маршрут ✅
Наступна перевірка — перезавантажити gateway і переконатися, що обидва маршрути повернуться без ручного запуску.
Алгоритмічний відступ завершено, повертаюся до Transparent Gateway.
Перед паузою зовнішній TLS-проксі нарешті пройшов validator і потрапив до активного пулу. Тепер у gateway є два маршрути:
локальний проксі
→ локальний echo-сервіс
зовнішній TLS-проксі
→ публічний echo-сервіс
Але перевірка проксі з самого gateway доводить лише те, що gateway може до них підключитися. Клієнтський трафік усе ще міг не перехоплюватися, піти неправильним маршрутом або взагалі обійти gateway.
Тому фінальну перевірку запускаю з окремої клієнтської VM. На ній немає адрес проксі, паролів або коду проєкту. Програми відкривають звичайні з’єднання, а єдиний маршрут за замовчуванням веде через Transparent Gateway.
Команда запускається з довіреної машини:
python3 deploy/verify-readiness.py \
--public \
--gateway tgadmin@<gateway> \
--client tgadmin@<client>
Параметр
--public додає до локальної перевірки справжній вихід в інтернет.Спочатку клієнт звертається до локального echo-сервісу:
клієнт
→ Transparent Gateway
→ локальний проксі
→ локальний echo
Цей маршрут перевіряє перехоплення TCP-з’єднання, relay, авторизацію на проксі та повернення відповіді всередині стенда.
Потім клієнт виконує DNS-запит і встановлює HTTPS-з’єднання з публічним echo-сервісом:
клієнт
→ Transparent Gateway
→ зовнішній TLS-проксі
→ Cloudflare
→ публічний echo
Публічний сервіс повертає свіжий ідентифікатор запиту та адресу, з якої побачив з’єднання. Перевірка звіряє її з вихідною адресою зовнішнього проксі в активному пулі.
Для локального маршруту виконується така сама перевірка. Тому випадкова відповідь від іншого сервісу або пряме з’єднання клієнта за успіх не зарахуються.
Окремо клієнт надсилає три UDP-пакети не на DNS-порт. Transparent Gateway підтримує DNS через UDP, але довільний UDP-трафік через TCP-проксі передати не може. Такий трафік повинен блокуватися, а не тихо виходити в обхід проксі.
Після тесту лічильник правила
DROP збільшився на три. Отже, усі контрольні пакети gateway справді зупинив.Скорочений результат:
PASS validator cycle and lineage; two usable active upstreams
PASS fresh client UDP DNS via gateway
PASS TCP and verified public HTTPS
PASS public echo matches active exit [IP hidden]
PASS local transparent echo
PASS direct non-DNS UDP blocked
FULL_CLIENT_READINESS PASS
Тепер перевірені не лише окремі контейнери та проксі. Звичайний клієнт без власних налаштувань проксі пройшов через gateway до локального й публічного echo-сервісів, а непідтримуваний трафік не зміг обійти маршрут ✅
Наступна перевірка — перезавантажити gateway і переконатися, що обидва маршрути повернуться без ручного запуску.
❤1
Після перезавантаження повернувся весь маршрут 🔄
Раніше вже перевіряв автоматичний запуск Transparent Gateway після перезавантаження. Тоді у стенді був лише локальний проксі, тому перевірка закінчувалася на внутрішньому echo-сервісі.
Відтоді з’явився зовнішній TLS-проксі, його сертифікат, дані авторизації та публічний echo-сервіс. Старої перевірки вже недостатньо: systemd може успішно запустити контейнери, але це ще не означає, що клієнт знову вийде через них в інтернет.
Перед перезавантаженням зберігаю контрольний стан:
Сценарій запам’ятовує ідентифікатор поточного завантаження, контейнери, стан захищених файлів і тестове значення в Redis.
Після повернення машини запускаю з довіреного комп’ютера повну перевірку:
Спочатку вона перевіряє сам gateway:
- машина справді перезавантажилася;
- systemd сам запустив Transparent Gateway;
- конфігурація, секрети й сертифікат проксі не змінилися;
- дані Redis пережили перезавантаження;
- validator провів новий цикл і зібрав свіжий активний пул.
Потім окрема клієнтська VM повторює обидва маршрути:
Також перевіряються DNS, HTTPS-сертифікат, вихідна адреса проксі та блокування UDP-трафіку, який gateway не підтримує.
Скорочений результат:
Після перезавантаження нічого не запускав руками. Gateway сам підняв сервіси, дочекався нового пулу проксі й знову провів клієнтський трафік через локальний та публічний маршрути ✅
Але машина все ще існувала до початку перевірки. Наступний тест цікавіший: видалити gateway повністю й відтворити його з чистого шаблону.
Раніше вже перевіряв автоматичний запуск Transparent Gateway після перезавантаження. Тоді у стенді був лише локальний проксі, тому перевірка закінчувалася на внутрішньому echo-сервісі.
Відтоді з’явився зовнішній TLS-проксі, його сертифікат, дані авторизації та публічний echo-сервіс. Старої перевірки вже недостатньо: systemd може успішно запустити контейнери, але це ще не означає, що клієнт знову вийде через них в інтернет.
Перед перезавантаженням зберігаю контрольний стан:
sudo python3 deploy/verify-boot.py --prepare
sudo systemctl reboot
Сценарій запам’ятовує ідентифікатор поточного завантаження, контейнери, стан захищених файлів і тестове значення в Redis.
Після повернення машини запускаю з довіреного комп’ютера повну перевірку:
python3 deploy/verify-full-boot.py \
--gateway tgadmin@<gateway> \
--client tgadmin@<client>
Спочатку вона перевіряє сам gateway:
- машина справді перезавантажилася;
- systemd сам запустив Transparent Gateway;
- конфігурація, секрети й сертифікат проксі не змінилися;
- дані Redis пережили перезавантаження;
- validator провів новий цикл і зібрав свіжий активний пул.
Потім окрема клієнтська VM повторює обидва маршрути:
клієнт
→ gateway
→ локальний проксі
→ локальний echo
клієнт
→ gateway
→ зовнішній TLS-проксі
→ публічний echo
Також перевіряються DNS, HTTPS-сертифікат, вихідна адреса проксі та блокування UDP-трафіку, який gateway не підтримує.
Скорочений результат:
PASS reboot: boot ID changed
PASS systemd automatic startup
PASS Redis and protected files preserved
PASS fresh proxy pools after reboot
FULL_CLIENT_READINESS PASS
FULL_REBOOT_CHECK PASS
Після перезавантаження нічого не запускав руками. Gateway сам підняв сервіси, дочекався нового пулу проксі й знову провів клієнтський трафік через локальний та публічний маршрути ✅
Але машина все ще існувала до початку перевірки. Наступний тест цікавіший: видалити gateway повністю й відтворити його з чистого шаблону.
❤2
Чиста VM стала готовим gateway за шість хвилин ♻️
Перезавантаження пройшло успішно. Але воно перевірило машину, на якій уже були код, конфігурація, секрети й дані Redis.
Якщо втратити її диск, systemd уже нічим не допоможе. Тому для фінальної перевірки зупинив робочий gateway і створив нову VM із чистого шаблону Debian.
Старий диск не копіював. Нова машина на початку не мала коду Transparent Gateway, конфігурації, контейнерів, образів Docker або томів із даними.
Щоб не виконувати весь процес руками, додав до репозиторію сценарій
Каталог
Далі він послідовно:
Перед розгортанням окремо переконався, що на новій VM немає каталогу застосунку, контейнерів, образів і томів Docker. Так тест не міг випадково використати залишки попереднього gateway.
Потім машина отримала код і шість захищених файлів конфігурації. Cloud-init підготував Debian і Docker, сценарій розгорнув застосунок, а systemd узяв на себе подальший запуск.
Перша повна готовність настала приблизно через три хвилини після початку створення VM:
Після цього новий gateway перезавантажився й повторно провів клієнтський трафік через локальний та зовнішній проксі.
Фінальний результат:
Уся перевірка разом із перезавантаженням тривала трохи більше шести хвилин. Ручних виправлень — нуль.
Тепер Transparent Gateway існує не лише у вигляді вдало налаштованої VM. Його вдалося відтворити з чистого шаблону, провести через повну перевірку й перезавантажити без жодного «зараз швиденько зайду через SSH» 😌
У наступному пості зберу результат цілком, залишу посилання на статтю та репозиторій і чесно відмічу, чого цей стенд усе ще не перевіряє.
Перезавантаження пройшло успішно. Але воно перевірило машину, на якій уже були код, конфігурація, секрети й дані Redis.
Якщо втратити її диск, systemd уже нічим не допоможе. Тому для фінальної перевірки зупинив робочий gateway і створив нову VM із чистого шаблону Debian.
Старий диск не копіював. Нова машина на початку не мала коду Transparent Gateway, конфігурації, контейнерів, образів Docker або томів із даними.
Щоб не виконувати весь процес руками, додав до репозиторію сценарій
deploy/proxmox/recreate-lab.py. Він запускає повне відтворення стенда:sudo python3 deploy/proxmox/recreate-lab.py \
--evidence /root/tg-recreate-evidence
Каталог
--evidence потрібен для результатів перевірки. Сценарій створює його сам і відмовляється перезаписувати попередній запуск.Далі він послідовно:
зупиняє старий gateway
↓
створює нову VM із чистого шаблону
↓
чекає завершення cloud-init
↓
перевіряє порожній стан машини
↓
доставляє код і секрети
↓
розгортає Transparent Gateway
↓
перевіряє клієнтський трафік
↓
перезавантажує VM
↓
повторює повну перевірку
Перед розгортанням окремо переконався, що на новій VM немає каталогу застосунку, контейнерів, образів і томів Docker. Так тест не міг випадково використати залишки попереднього gateway.
Потім машина отримала код і шість захищених файлів конфігурації. Cloud-init підготував Debian і Docker, сценарій розгорнув застосунок, а systemd узяв на себе подальший запуск.
Перша повна готовність настала приблизно через три хвилини після початку створення VM:
clone: 20.81s
cloud-init: 97.63s
deployment: 78.27s
first ready: 189.44s
Після цього новий gateway перезавантажився й повторно провів клієнтський трафік через локальний та зовнішній проксі.
Фінальний результат:
PASS fresh machine identity
PASS clean application state before deployment
PASS cloud-init, secrets, deployment and systemd
FULL_CLIENT_READINESS PASS
FULL_REBOOT_CHECK PASS
RECREATE_CHECK PASS
Уся перевірка разом із перезавантаженням тривала трохи більше шести хвилин. Ручних виправлень — нуль.
Тепер Transparent Gateway існує не лише у вигляді вдало налаштованої VM. Його вдалося відтворити з чистого шаблону, провести через повну перевірку й перезавантажити без жодного «зараз швиденько зайду через SSH» 😌
У наступному пості зберу результат цілком, залишу посилання на статтю та репозиторій і чесно відмічу, чого цей стенд усе ще не перевіряє.
❤1
Transparent Gateway нарешті відтворюється з чистої VM ⚙️
Починав із gateway, який добре працював, але жив на одній вручну підготовленій VM. Поки її диск цілий — усе чудово. Якщо ні, залишається археологія в історії команд і спроби згадати, чому цей маршрут колись запрацював 😅
Тепер увесь шлях виглядає так:
Фінальний тест почався з чистої VM без коду, контейнерів, образів Docker, Redis і старих SSH-ключів.
Приблизно через три хвилини клієнт уже проходив через Transparent Gateway до локального та публічного echo-сервісів. Потім VM перезавантажилася й повторила весь маршрут без ручного втручання.
Повний цикл разом із перезавантаженням зайняв трохи більше шести хвилин:
Але називати це повним відновленням після втрати хоста ще рано.
Шість файлів із конфігурацією та секретами для тесту забрав зі старої VM. Окрему резервну копію цього набору та процедуру її відновлення ще потрібно підготувати.
Також за межами перевірки залишилися:
- IPv6;
- оновлення токенів і сертифікатів проксі;
- робота з API справжнього провайдера;
- повне закріплення версій пакетів і базових Docker-образів;
- моніторинг і повний аудит безпеки.
Тобто gateway уже можна відтворити з чистого шаблону, але один зелений
У статті зібрав увесь шлях: шаблон Proxmox, cloud-init, доставку секретів, systemd, локальний і публічний echo, помилку з
https://devdays.net.ua/articles/rozghortannia-transparent-gateway-proxmox-cloud-init-systemd/
Код, сценарії розгортання та перевірки:
https://github.com/Va1b0rt/TransparentGateway
Починав із gateway, який добре працював, але жив на одній вручну підготовленій VM. Поки її диск цілий — усе чудово. Якщо ні, залишається археологія в історії команд і спроби згадати, чому цей маршрут колись запрацював 😅
Тепер увесь шлях виглядає так:
чистий шаблон Debian
→ нова VM у Proxmox
→ cloud-init готує систему
→ окремо надходять код і секрети
→ сценарій розгортає gateway
→ systemd керує запуском
→ клієнт перевіряє локальний та публічний маршрути
Фінальний тест почався з чистої VM без коду, контейнерів, образів Docker, Redis і старих SSH-ключів.
Приблизно через три хвилини клієнт уже проходив через Transparent Gateway до локального та публічного echo-сервісів. Потім VM перезавантажилася й повторила весь маршрут без ручного втручання.
Повний цикл разом із перезавантаженням зайняв трохи більше шести хвилин:
FULL_CLIENT_READINESS PASS
FULL_REBOOT_CHECK PASS
RECREATE_CHECK PASS
manual repairs: 0
Але називати це повним відновленням після втрати хоста ще рано.
Шість файлів із конфігурацією та секретами для тесту забрав зі старої VM. Окрему резервну копію цього набору та процедуру її відновлення ще потрібно підготувати.
Також за межами перевірки залишилися:
- IPv6;
- оновлення токенів і сертифікатів проксі;
- робота з API справжнього провайдера;
- повне закріплення версій пакетів і базових Docker-образів;
- моніторинг і повний аудит безпеки.
Тобто gateway уже можна відтворити з чистого шаблону, але один зелений
PASS усе ще не перетворює лабораторний стенд на безсмертний production 😌У статті зібрав увесь шлях: шаблон Proxmox, cloud-init, доставку секретів, systemd, локальний і публічний echo, помилку з
CONNECT, перезавантаження та повне відтворення VM:https://devdays.net.ua/articles/rozghortannia-transparent-gateway-proxmox-cloud-init-systemd/
Код, сценарії розгортання та перевірки:
https://github.com/Va1b0rt/TransparentGateway
❤1💅1
24 години на AI-агента — і захист перед AI-суддею 🎃
Зареєструвався на HackerRank Orchestrate October 2026. Бейдж учасника вже прилетів, тепер чекаю умову задачі.
Формат такий: на старті отримую практичну проблему, для якої потрібно спроєктувати й реалізувати AI-агента. На роботу — 24 години ⏱
Яку саме проблему доведеться вирішувати цього разу, поки не розкривають. Завдання надішлють 24 жовтня.
Користуватися AI-інструментами дозволено: Claude Code, Cursor, Codex або інші на власний вибір. Разом із кодом потрібно здати результати роботи агента та історію спілкування з AI під час розробки.
А після здачі — 30-хвилинна голосова співбесіда з AI-суддею. Потрібно пояснити архітектуру, свої рішення та компроміси.
Оцей момент мене й зацікавив. Згенерований код ще доведеться розібрати настільки, щоб відповісти, чому система влаштована саме так. «Воно якось запрацювало» — слабенький план для захисту 😅
Після участі розберу конкретну задачу, своє рішення і те, що вдалося перевірити за відведений час.
HackerRank Orchestrate — October 2026
https://www.hackerrank.com/hackerrank-orchestrate-october26
Зареєструвався на HackerRank Orchestrate October 2026. Бейдж учасника вже прилетів, тепер чекаю умову задачі.
Формат такий: на старті отримую практичну проблему, для якої потрібно спроєктувати й реалізувати AI-агента. На роботу — 24 години ⏱
Яку саме проблему доведеться вирішувати цього разу, поки не розкривають. Завдання надішлють 24 жовтня.
Користуватися AI-інструментами дозволено: Claude Code, Cursor, Codex або інші на власний вибір. Разом із кодом потрібно здати результати роботи агента та історію спілкування з AI під час розробки.
А після здачі — 30-хвилинна голосова співбесіда з AI-суддею. Потрібно пояснити архітектуру, свої рішення та компроміси.
Оцей момент мене й зацікавив. Згенерований код ще доведеться розібрати настільки, щоб відповісти, чому система влаштована саме так. «Воно якось запрацювало» — слабенький план для захисту 😅
Після участі розберу конкретну задачу, своє рішення і те, що вдалося перевірити за відведений час.
HackerRank Orchestrate — October 2026
https://www.hackerrank.com/hackerrank-orchestrate-october26
❤1
Встановив власний проєкт за власною інструкцією 😅
Transparent Gateway уже працював на домашньому стенді. Після попередніх пригод навіть навчився розгортатися на новій машині.
Але захотілося перевірити простішу й значно кориснішу ситуацію: людина відкрила GitHub, завантажила код і вирішила ним скористатися. Без моїх готових віртуалок і підказок через плече 🤔
Для тих, хто не застав початок: Transparent Gateway — це шлюз між клієнтськими машинами та інтернетом. Програми звертаються до сайтів звичайним способом, а шлюз спрямовує їхні з’єднання через налаштований проксі. Вписувати проксі окремо в браузер чи кожну програму не потрібно.
Маршрут виходить такий:
Тому підготував чистий Debian і почав із цілком буденної команди:
Далі потрібно було ввести параметри мережі, додати проксі й запустити сервіси.
Саме цей шлях і захотів зробити нормальним: щоб для першого запуску не доводилося спочатку вивчати внутрішню будову всього проєкту ⚙️
Почав із налаштувань. Бо адреса проксі одна, а файлів, яким щось від неї потрібно, уже декілька.
Transparent Gateway уже працював на домашньому стенді. Після попередніх пригод навіть навчився розгортатися на новій машині.
Але захотілося перевірити простішу й значно кориснішу ситуацію: людина відкрила GitHub, завантажила код і вирішила ним скористатися. Без моїх готових віртуалок і підказок через плече 🤔
Для тих, хто не застав початок: Transparent Gateway — це шлюз між клієнтськими машинами та інтернетом. Програми звертаються до сайтів звичайним способом, а шлюз спрямовує їхні з’єднання через налаштований проксі. Вписувати проксі окремо в браузер чи кожну програму не потрібно.
Маршрут виходить такий:
клієнт → gateway → проксі → сайт
Тому підготував чистий Debian і почав із цілком буденної команди:
git clone https://github.com/Va1b0rt/TransparentGateway.git
Далі потрібно було ввести параметри мережі, додати проксі й запустити сервіси.
Саме цей шлях і захотів зробити нормальним: щоб для першого запуску не доводилося спочатку вивчати внутрішню будову всього проєкту ⚙️
Почав із налаштувань. Бо адреса проксі одна, а файлів, яким щось від неї потрібно, уже декілька.
❤1👏1
Налаштування без екскурсії по конфігах ⚙️
Для першого запуску gateway потрібні досить прості речі: клієнтська мережа, адреса проксі, його порт і, за потреби, логін із паролем.
Але всередині проєкту вони розкладаються по різних файлах. Частина належить мережевим налаштуванням, частина — списку проксі, ще частина — даним доступу.
Вручну це зробити можна. Але змушувати людину розбирати всі ці файли ще до першого запуску якось негостинно 😅
Тому додав до репозиторію
На підготовленій машині, з каталогу проєкту, запускаю:
Він послідовно запитує потрібні значення. Наприклад:
Тут
Якщо потрібна авторизація, скрипт запитає логін і пароль. Пароль під час введення не відображається 🔑
Відповіді потрапляють у робочі файли з потрібними правами. Після цього окремою командою перевіряю конфігурацію:
У результаті перше знайомство з проєктом уже не починається з ручного редагування JSON-файлів ✅
А от чому пароль узагалі лежить окремо від адреси проксі — там є своя причина.
Для першого запуску gateway потрібні досить прості речі: клієнтська мережа, адреса проксі, його порт і, за потреби, логін із паролем.
Але всередині проєкту вони розкладаються по різних файлах. Частина належить мережевим налаштуванням, частина — списку проксі, ще частина — даним доступу.
Вручну це зробити можна. Але змушувати людину розбирати всі ці файли ще до першого запуску якось негостинно 😅
Тому додав до репозиторію
scripts/tgctl.py — скрипт для налаштування й керування gateway.На підготовленій машині, з каталогу проєкту, запускаю:
sudo python3 scripts/tgctl.py configure
Він послідовно запитує потрібні значення. Наприклад:
Protocol ... [http]: socks5
Authorised upstream proxy host or IP: proxy.example.com
Proxy port [3128]: 1080
Тут
proxy.example.com — вигаданий приклад. Для роботи вводжу дані свого реального проксі.Якщо потрібна авторизація, скрипт запитає логін і пароль. Пароль під час введення не відображається 🔑
Відповіді потрапляють у робочі файли з потрібними правами. Після цього окремою командою перевіряю конфігурацію:
sudo python3 scripts/tgctl.py check
У результаті перше знайомство з проєктом уже не починається з ручного редагування JSON-файлів ✅
А от чому пароль узагалі лежить окремо від адреси проксі — там є своя причина.
Мільйон доларів і трохи математики 💸
Прочитав у пості розбір про шанси стати доларовим мільйонером. Для України автор отримав приблизно 0,05%.
Спочатку взяв частку мільйонерів у населенні, потім додав власні припущення про стартові умови та вплив війни. Вийшла цифра, після якої хочеться закрити калькулятор ізастрелитись піти зробити чай 😅
У коментарях зачепилися за питання: а чи можна цей відсоток вважати моїм особистим шансом?
Автор пояснив свою думку через можливості. Там, де більший платоспроможний ринок, легше знайти справу, на якій можна заробити великий капітал. Самого бажання багато працювати недостатньо, якщо покупцям нічим платити.
Із цим погоджуюся. Але між «скільки людей уже мають мільйон» і «чи зможу заробити його за життя» є різниця.
Частка мільйонерів показує, скільки людей уже мають такі статки. Але не показує, скільки людей, які сьогодні починають з нуля, дійдуть до мільйона за наступні двадцять років. Це різні питання, хоча відповідь на обидва хочеться отримати одним діленням.
Щоб порахувати саме шанс, потрібно знати, скільки людей починали зі схожих умов, що робили й до чого прийшли за певний час. Самого ділення кількості мільйонерів на населення для цього замало. Звіт Credit Suisse, на який послався автор, описує розподіл статків, а не ймовірність конкретної людини розбагатіти.
Моя перша думка була простішою: «Але ж за ці гроші змагаються не всі».
Не кожен хоче будувати бізнес, продавати свій продукт чи ризикувати заради більшого доходу. Комусь достатньо стабільної роботи — і це нормальний вибір.
Тільки тут теж легко намалювати собі красиву математику. Прибрати зі знаменника всіх, хто «не грає», поділити ще раз — і порадіти новому відсотку. Але скільки насправді людей пробували, скільки не вийшло й за який період це рахувати? Цих даних у мене немає. Тому власні «тепер уже точно 5%» вигадувати не буду 🙂
Натомість є інша важлива деталь: жити в Україні й продавати лише в Україні — не одне й те саме.
Наприклад, можу робити гру або сервіс тут, а продавати людям з інших країн. Тоді можливості мого продукту залежать уже не тільки від того, скільки готові витратити покупці вдома.
Легкою задачу це не робить. За кордоном на мій продукт теж ніхто спеціально не чекає: доведеться знайти покупця й переконати його заплатити.
Тому думку автора про нерівні можливості приймаю. Місце, де живеш і працюєш, справді має значення. Але свої особисті шанси з цього відсотка все одно не вирахую.
Не знаю, наскільки вони вищі за 0,05%. І підміняти неприємну цифру приємнішою тільки заради настрою теж не хочу.
Але між «у цій країні мало мільйонерів» і «у мене майже немає шансів» — висновок, якого ця математика не доводить.
Мільйона поки немає. Але й статистично довести, що варто кидати спроби за нього конкурувати, теж не вдалося. Продовжую працювати 😅
Прочитав у пості розбір про шанси стати доларовим мільйонером. Для України автор отримав приблизно 0,05%.
Спочатку взяв частку мільйонерів у населенні, потім додав власні припущення про стартові умови та вплив війни. Вийшла цифра, після якої хочеться закрити калькулятор і
У коментарях зачепилися за питання: а чи можна цей відсоток вважати моїм особистим шансом?
Автор пояснив свою думку через можливості. Там, де більший платоспроможний ринок, легше знайти справу, на якій можна заробити великий капітал. Самого бажання багато працювати недостатньо, якщо покупцям нічим платити.
Із цим погоджуюся. Але між «скільки людей уже мають мільйон» і «чи зможу заробити його за життя» є різниця.
Частка мільйонерів показує, скільки людей уже мають такі статки. Але не показує, скільки людей, які сьогодні починають з нуля, дійдуть до мільйона за наступні двадцять років. Це різні питання, хоча відповідь на обидва хочеться отримати одним діленням.
Щоб порахувати саме шанс, потрібно знати, скільки людей починали зі схожих умов, що робили й до чого прийшли за певний час. Самого ділення кількості мільйонерів на населення для цього замало. Звіт Credit Suisse, на який послався автор, описує розподіл статків, а не ймовірність конкретної людини розбагатіти.
Моя перша думка була простішою: «Але ж за ці гроші змагаються не всі».
Не кожен хоче будувати бізнес, продавати свій продукт чи ризикувати заради більшого доходу. Комусь достатньо стабільної роботи — і це нормальний вибір.
Тільки тут теж легко намалювати собі красиву математику. Прибрати зі знаменника всіх, хто «не грає», поділити ще раз — і порадіти новому відсотку. Але скільки насправді людей пробували, скільки не вийшло й за який період це рахувати? Цих даних у мене немає. Тому власні «тепер уже точно 5%» вигадувати не буду 🙂
Натомість є інша важлива деталь: жити в Україні й продавати лише в Україні — не одне й те саме.
Наприклад, можу робити гру або сервіс тут, а продавати людям з інших країн. Тоді можливості мого продукту залежать уже не тільки від того, скільки готові витратити покупці вдома.
Легкою задачу це не робить. За кордоном на мій продукт теж ніхто спеціально не чекає: доведеться знайти покупця й переконати його заплатити.
Тому думку автора про нерівні можливості приймаю. Місце, де живеш і працюєш, справді має значення. Але свої особисті шанси з цього відсотка все одно не вирахую.
Не знаю, наскільки вони вищі за 0,05%. І підміняти неприємну цифру приємнішою тільки заради настрою теж не хочу.
Але між «у цій країні мало мільйонерів» і «у мене майже немає шансів» — висновок, якого ця математика не доводить.
Мільйона поки немає. Але й статистично довести, що варто кидати спроби за нього конкурувати, теж не вдалося. Продовжую працювати 😅
🔥3🤝1
Пароль теж хотів подорожувати 🔑
Під час налаштування ввів адресу проксі та пароль до нього. Здавалося б, записати поруч — і готово.
Але список проксі проходить через кілька сервісів: один збирає адреси, другий перевіряє, третій вибирає придатні для роботи. Результати передаються через Redis.
Якщо покласти пароль поруч з адресою, він поїде тією самою дорогою. Хоча більшості цих сервісів пароль узагалі не потрібен 🫣
Тому в записі про проксі залишив лише мітку:
За нею два сервіси знаходять потрібні дані доступу в окремому файлі.
Validator бере пароль, коли перевіряє проксі. Gateway — коли передає через нього клієнтський трафік. Інші компоненти працюють із міткою й самого пароля не отримують ⚙️
Магічного сейфа тут поки немає: пароль лежить у звичайному JSON-файлі, а користувач root може його прочитати.
Зате він уже не мандрує всім конвеєром. І пізніше зможу підключити сховище секретів, змінивши місце, звідки ці два сервіси отримують пароль.
Так вдалося розділити адресу проксі й доступ до нього без зайвої складності. Що не може не радувати 🙂
Налаштування готові, контейнери запустилися. А потім зникло світло.
Під час налаштування ввів адресу проксі та пароль до нього. Здавалося б, записати поруч — і готово.
Але список проксі проходить через кілька сервісів: один збирає адреси, другий перевіряє, третій вибирає придатні для роботи. Результати передаються через Redis.
Якщо покласти пароль поруч з адресою, він поїде тією самою дорогою. Хоча більшості цих сервісів пароль узагалі не потрібен 🫣
Тому в записі про проксі залишив лише мітку:
"credential_ref": "quickstart-proxy"
За нею два сервіси знаходять потрібні дані доступу в окремому файлі.
Validator бере пароль, коли перевіряє проксі. Gateway — коли передає через нього клієнтський трафік. Інші компоненти працюють із міткою й самого пароля не отримують ⚙️
Магічного сейфа тут поки немає: пароль лежить у звичайному JSON-файлі, а користувач root може його прочитати.
Зате він уже не мандрує всім конвеєром. І пізніше зможу підключити сховище секретів, змінивши місце, звідки ці два сервіси отримують пароль.
Так вдалося розділити адресу проксі й доступ до нього без зайвої складності. Що не може не радувати 🙂
Налаштування готові, контейнери запустилися. А потім зникло світло.
Світло знайшло забуту службу 💡
Поки готував перевірку gateway, згасло світло. Машина перезавантажилася.
Після її повернення Docker працював. А шість контейнерів мого проєкту — ні 😬
У налаштуваннях контейнерів стояло:
І це було навмисно. Запуском мала керувати служба systemd — системний механізм, який запускає програми під час завантаження Linux.
От тільки встановлення самої служби в команду запуску забув додати. Контейнери запустив, автоматичний запуск подумки теж установив. Дуже зручно 😅
Поки машина не перезавантажувалася, помилка себе не показувала.
Виправив
Після виправлень уже навмисно перезавантажив машину. Цього разу gateway піднявся без ручної допомоги ✅
Безкоштовне тестування від електромережі виявилося корисним. Але до списку залежностей проєкту його все-таки не додавав. 😜
На цьому проблему запуску закрив. А клієнт тим часом знайшов наступну: адресу сайту він усе ще визначити не міг.
Поки готував перевірку gateway, згасло світло. Машина перезавантажилася.
Після її повернення Docker працював. А шість контейнерів мого проєкту — ні 😬
У налаштуваннях контейнерів стояло:
restart: "no"
І це було навмисно. Запуском мала керувати служба systemd — системний механізм, який запускає програми під час завантаження Linux.
От тільки встановлення самої служби в команду запуску забув додати. Контейнери запустив, автоматичний запуск подумки теж установив. Дуже зручно 😅
Поки машина не перезавантажувалася, помилка себе не показувала.
Виправив
tgctl.py up: тепер після успішного першого запуску він установлює та вмикає службу. Під час наступного завантаження вона чекає на Docker, запускає контейнери й перевіряє появу робочого проксі.Після виправлень уже навмисно перезавантажив машину. Цього разу gateway піднявся без ручної допомоги ✅
Безкоштовне тестування від електромережі виявилося корисним. Але до списку залежностей проєкту його все-таки не додавав. 😜
На цьому проблему запуску закрив. А клієнт тим часом знайшов наступну: адресу сайту він усе ще визначити не міг.
😁1
UGEN пише у своєму пості про проблему, яка висить над новачками (і не тільки) в IT вже роками. 📉
Відкриваєш вакансії — і легко знаходиш junior-позиції з вимогами до вже досвідченого спеціаліста. У їхньому прикладі Junior Recruiter має три роки досвіду в технічному рекрутингу. 🤯
Історія не нова. Вимоги встигнути попрацювати ще до першої роботи зустрічалися задовго до нинішньої конкуренції. Питання, чи справді шукають джуна, чи просто хочуть платити як джуну, теж нікуди не поділося. 💸
UGEN пропонує уточнити робочі моменти: що означає Middle у цій компанії, чи буде ментор, які умови стажування та оплати. 📝
Але UGEN не уточнює, що шанс поставити ці питання буде далеко не у кожного.
За даними Ashby, для технічних позицій до співбесіди доходять близько 3,6% відгуків. Серед тих, хто дістався співбесіди, до оферу доходять 7,3%. 📲
На умовну тисячу відгуків це приблизно 36 запрошень на співбесіду й 2–3 офери. Це не окрема статистика українських джунів і не рекрутерської вакансії з допису UGEN — це масштаб відбору на технічні позиції у вибірці Ashby. 🎯
І вся ця боротьба та відбір на рівні спецназу — за позиції на $500–800.
Для справедливості: далеко не кожен роботодавець виставляє джуну неадекватні вимоги. За моїми спостереженнями, на профільних DOU та Djinni вакансії зазвичай притомніші, ніж на загальних сайтах пошуку роботи.
Але головна конкуренція для джуна — з іншими кандидатами. І вона є всюди, незалежно від сайту. Айтівців стало багато. Із нас тепер можна обирати.
Умовно, на позицію прийдуть десятеро із шаленим бажанням учитися й один, який уже вміє виконувати потрібні задачі. І роботодавець цілком може вибрати його, а не вкладатися в навчання решти.
От про цей шлях і хочеться читати в каналі для пошуку першої роботи. Реальні кейси: що кандидат умів, які проєкти показав, як отримав запрошення на співбесіду й що допомогло отримати офер.
Бо список питань до роботодавця — це добре. Але до кінця посту так і не зрозумів: як кандидату наблизитися до першої роботи? Питань у нього й до цього вистачало. 🤷♂️
Відкриваєш вакансії — і легко знаходиш junior-позиції з вимогами до вже досвідченого спеціаліста. У їхньому прикладі Junior Recruiter має три роки досвіду в технічному рекрутингу. 🤯
Історія не нова. Вимоги встигнути попрацювати ще до першої роботи зустрічалися задовго до нинішньої конкуренції. Питання, чи справді шукають джуна, чи просто хочуть платити як джуну, теж нікуди не поділося. 💸
UGEN пропонує уточнити робочі моменти: що означає Middle у цій компанії, чи буде ментор, які умови стажування та оплати. 📝
Але UGEN не уточнює, що шанс поставити ці питання буде далеко не у кожного.
За даними Ashby, для технічних позицій до співбесіди доходять близько 3,6% відгуків. Серед тих, хто дістався співбесіди, до оферу доходять 7,3%. 📲
На умовну тисячу відгуків це приблизно 36 запрошень на співбесіду й 2–3 офери. Це не окрема статистика українських джунів і не рекрутерської вакансії з допису UGEN — це масштаб відбору на технічні позиції у вибірці Ashby. 🎯
І вся ця боротьба та відбір на рівні спецназу — за позиції на $500–800.
Для справедливості: далеко не кожен роботодавець виставляє джуну неадекватні вимоги. За моїми спостереженнями, на профільних DOU та Djinni вакансії зазвичай притомніші, ніж на загальних сайтах пошуку роботи.
Але головна конкуренція для джуна — з іншими кандидатами. І вона є всюди, незалежно від сайту. Айтівців стало багато. Із нас тепер можна обирати.
Умовно, на позицію прийдуть десятеро із шаленим бажанням учитися й один, який уже вміє виконувати потрібні задачі. І роботодавець цілком може вибрати його, а не вкладатися в навчання решти.
От про цей шлях і хочеться читати в каналі для пошуку першої роботи. Реальні кейси: що кандидат умів, які проєкти показав, як отримав запрошення на співбесіду й що допомогло отримати офер.
Бо список питань до роботодавця — це добре. Але до кінця посту так і не зрозумів: як кандидату наблизитися до першої роботи? Питань у нього й до цього вистачало. 🤷♂️
❤1
Забув, що gateway теж може бути DNS-сервером 🧩
Після виправлення запуску контейнери працювали, проксі був готовий, а клієнтська перевірка завершувалася так:
Перший рядок показував правильний маршрут через gateway. Другий — що клієнт не зміг знайти адресу потрібного сервісу через DNS.
DNS перетворює ім’я на кшталт
У правилах gateway врахував звернення до
А клієнт запитував адресу в самого gateway —
Оцей варіант і пропустив 😅
Додав правило, яке спрямовує DNS-запити до власної адреси gateway в той самий обробник. Тепер клієнт міг використовувати шлюз як DNS-сервер, а той уже знаходив відповідь через зовнішній сервіс.
Після виправлення перевірка пройшла далі й отримала HTTPS-відповідь ✅
Але отримати відповідь — ще половина справи. Залишилося порівняти, з якої адреси публічний сервіс побачив цей запит.
Після виправлення запуску контейнери працювали, проксі був готовий, а клієнтська перевірка завершувалася так:
CLIENT_ROUTE PASS gateway=192.168.91.1 dev=eth1
CLIENT_CHECK FAIL: [Errno -2] Name or service not known
Перший рядок показував правильний маршрут через gateway. Другий — що клієнт не зміг знайти адресу потрібного сервісу через DNS.
DNS перетворює ім’я на кшталт
echo.devdays.net.ua на IP-адресу, до якої вже можна підключитися. Без цього HTTPS-запит навіть не почався 🤷♂️У правилах gateway врахував звернення до
1.1.1.1 і 1.0.0.1: такі DNS-запити передавалися через захищене HTTPS-з’єднання.А клієнт запитував адресу в самого gateway —
192.168.91.1.Оцей варіант і пропустив 😅
Додав правило, яке спрямовує DNS-запити до власної адреси gateway в той самий обробник. Тепер клієнт міг використовувати шлюз як DNS-сервер, а той уже знаходив відповідь через зовнішній сервіс.
Після виправлення перевірка пройшла далі й отримала HTTPS-відповідь ✅
Але отримати відповідь — ще половина справи. Залишилося порівняти, з якої адреси публічний сервіс побачив цей запит.
❤1
Перевіряю запит із клієнтської машини 🔎
Gateway запустився, DNS запрацював. Тепер потрібно було пройти весь маршрут звичайним клієнтським запитом.
Для цього використав окрему машину, єдиний вихід якої в інтернет веде через gateway.
Передав їй
Скрипт перевіряє маршрут, знаходить адресу публічного echo-сервісу через DNS і звертається до нього через HTTPS.
Echo повертає адресу, з якої побачив запит. Саме вона й дозволяє порівняти результат із проксі, який вибрав gateway.
Щоб не показувати зовнішні адреси у виводі, обидві перевірки обчислюють для них однакові короткі відбитки. Отримав:
Значення збіглися ✅
Тобто публічний сервіс побачив клієнтський запит з адреси активного проксі. Сам клієнт при цьому знав лише адресу gateway.
Оце вже той результат, заради якого все й затіяв: програма просто відкриває сайт, а потрібний маршрут забезпечує шлюз ⚙️
Gateway запустився, DNS запрацював. Тепер потрібно було пройти весь маршрут звичайним клієнтським запитом.
Для цього використав окрему машину, єдиний вихід якої в інтернет веде через gateway.
Передав їй
scripts/client-check.py із репозиторію та запустив перевірку вже на клієнті:python3 /tmp/tg-client-check.py --gateway 192.168.91.1
Скрипт перевіряє маршрут, знаходить адресу публічного echo-сервісу через DNS і звертається до нього через HTTPS.
Echo повертає адресу, з якої побачив запит. Саме вона й дозволяє порівняти результат із проксі, який вибрав gateway.
Щоб не показувати зовнішні адреси у виводі, обидві перевірки обчислюють для них однакові короткі відбитки. Отримав:
На gateway:
active_exit_ids=0649753926f0
На клієнті:
PUBLIC_EXIT id=0649753926f0
Значення збіглися ✅
Тобто публічний сервіс побачив клієнтський запит з адреси активного проксі. Сам клієнт при цьому знав лише адресу gateway.
Оце вже той результат, заради якого все й затіяв: програма просто відкриває сайт, а потрібний маршрут забезпечує шлюз ⚙️
❤1
Transparent Gateway вже можна встановлювати 🛠️
Нарешті пройшов шлях від репозиторію на GitHub до робочого gateway на чистій Debian-машині 🚀
Поки розгортав, знайшов забуте встановлення служби systemd і пропущений випадок у DNS. Обидві проблеми виправив. Після повторного перезавантаження сервіси запустилися самі, а клієнтський запит пройшов через проксі.
Тепер на підготовленому Debian основні дії виглядають так:
Перша команда збирає налаштування, друга їх перевіряє, третя запускає gateway й чекає на робочий проксі.
Сам проксі та клієнтську мережу потрібно підготувати заздалегідь — їх скрипт із повітря ще не дістає 😅
Найприємніше тут те, що проєктом уже можна скористатися, не повторюючи всі мої попередні експерименти.
Оновлення теж уже спростив: нова версія встановлюється однією командою, налаштування залишаються на місці, а якщо запуск не вдався — повертається попередня версія. Цю роботу описав окремо:
Оновлення Transparent Gateway без повторного налаштування
Далі — діагностика, щоб при помилці одразу було видно, де саме зупинився запит.
Повний шлях із командами, скрінами та пригодами зі світлом зібрав у статті:
Від GitHub до робочого Transparent Gateway
Код проєкту на GitHub
Нарешті пройшов шлях від репозиторію на GitHub до робочого gateway на чистій Debian-машині 🚀
Поки розгортав, знайшов забуте встановлення служби systemd і пропущений випадок у DNS. Обидві проблеми виправив. Після повторного перезавантаження сервіси запустилися самі, а клієнтський запит пройшов через проксі.
Тепер на підготовленому Debian основні дії виглядають так:
sudo python3 scripts/tgctl.py configure
sudo python3 scripts/tgctl.py check
sudo python3 scripts/tgctl.py up --timeout 300
Перша команда збирає налаштування, друга їх перевіряє, третя запускає gateway й чекає на робочий проксі.
Сам проксі та клієнтську мережу потрібно підготувати заздалегідь — їх скрипт із повітря ще не дістає 😅
Найприємніше тут те, що проєктом уже можна скористатися, не повторюючи всі мої попередні експерименти.
Оновлення теж уже спростив: нова версія встановлюється однією командою, налаштування залишаються на місці, а якщо запуск не вдався — повертається попередня версія. Цю роботу описав окремо:
Оновлення Transparent Gateway без повторного налаштування
Далі — діагностика, щоб при помилці одразу було видно, де саме зупинився запит.
Повний шлях із командами, скрінами та пригодами зі світлом зібрав у статті:
Від GitHub до робочого Transparent Gateway
Код проєкту на GitHub