Пошук уроків, статей та іншого контенту
Підготуєте VPS, захистите SSH і firewall та розгорнете Docker-застосунок із доменом і HTTPS.
У цьому сценарії VPS працює як окремий сервер із публічною IP-адресою:
SSH використовується для адміністративного доступу.
UFW дозволяє лише SSH, HTTP і HTTPS.
Docker запускає застосунок та reverse proxy.
Caddy приймає запити на 80 і 443 портах.
Caddy пересилає HTTP-запити до контейнера застосунку через внутрішню Docker-мережу.
HTTPS-сертифікат отримується та оновлюється автоматично.
Схема запиту:
Користувач
|
| HTTPS :443
v
Caddy у Docker
|
| HTTP у внутрішній мережі Docker
v
Контейнер застосункуДля прикладів використовується Ubuntu 24.04 LTS на VPS і домен example.com. Замініть його на власний домен.
Перед налаштуванням HTTPS домен має вказувати на VPS.
Створіть DNS-записи:
A для example.com із публічною IPv4-адресою VPS;
за потреби AAAA для IPv6-адреси VPS.
Перевірити результат можна з локального комп’ютера:
dig +short example.comКоманда має повернути IP-адресу VPS.
Для автоматичного отримання сертифіката Caddy домен повинен:
Публічно резолвитися на цей VPS.
Бути доступним із мережі Інтернет.
Пропускати вхідні з’єднання на порти 80 і 443.
Якщо AAAA-запис існує, але IPv6 на VPS не налаштований, клієнти можуть звертатися за неправильною адресою. У такому разі видаліть некоректний AAAA-запис або повністю налаштуйте IPv6.
Спочатку підключіться до сервера під користувачем, якого створив провайдер:
ssh root@203.0.113.10Замість 203.0.113.10 використовуйте реальну IP-адресу VPS.
Оновіть індекс пакетів та встановлені пакети:
apt update
apt upgrade -yВстановіть базові утиліти:
apt install -y ca-certificates curl gnupg ufwНе варто постійно працювати через root. Створіть окремого користувача з можливістю виконувати адміністративні команди через sudo:
adduser deploy
usermod -aG sudo deployСистема попросить встановити пароль. Він знадобиться як резервний спосіб локальної автентифікації, але надалі вхід через пароль для SSH буде вимкнено.
На локальному комп’ютері створіть ключ, якщо його ще немає:
ssh-keygen -t ed25519 -C "deploy@vps"Публічний ключ зазвичай буде збережено у файлі:
~/.ssh/id_ed25519.pubСкопіюйте його на VPS:
ssh-copy-id deploy@203.0.113.10Якщо ssh-copy-id недоступна, виконайте на VPS такі команди під root:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.sshДалі додайте вміст локального файлу ~/.ssh/id_ed25519.pub до:
/home/deploy/.ssh/authorized_keysПісля цього встановіть правильні права:
chown -R deploy:deploy /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keysПеревірте вхід у новій сесії, не закриваючи поточну root-сесію:
ssh deploy@203.0.113.10Переконайтеся, що sudo працює:
sudo whoamiОчікуваний результат:
rootНе вимикайте парольну автентифікацію та root-доступ, доки не перевірите вхід через SSH-ключ у новій сесії.
Відкрийте конфігурацію SSH-сервера:
sudo nano /etc/ssh/sshd_configПереконайтеся, що в ній є такі параметри:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
AllowUsers deployЗначення AllowUsers deploy обмежує SSH-доступ лише користувачем deploy.
Перевірте конфігурацію перед перезапуском:
sudo sshd -tЯкщо команда не вивела помилок, перезапустіть SSH:
sudo systemctl restart sshПеревірте нове підключення в іншому вікні термінала:
ssh deploy@203.0.113.10Для Ubuntu використаємо UFW. Спочатку встановіть політики за замовчуванням:
sudo ufw default deny incoming
sudo ufw default allow outgoingДозвольте SSH до активації firewall:
sudo ufw allow 22/tcpДозвольте HTTP та HTTPS:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcpУвімкніть firewall:
sudo ufw enableПеревірте стан:
sudo ufw status verboseОчікувана логіка правил:
22/tcp ALLOW
80/tcp ALLOW
443/tcp ALLOWЯкщо провайдер VPS має власний мережевий firewall або security groups, ці самі порти потрібно дозволити і там. Правила на VPS та в панелі провайдера працюють незалежно.
Додайте офіційний GPG-ключ Docker:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.ascДодайте репозиторій Docker:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullОновіть індекс пакетів і встановіть Docker Engine та Compose plugin:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-pluginПеревірте встановлення:
sudo docker run --rm hello-worldПеревірте версії:
docker --version
docker compose versionДодайте користувача deploy до групи docker:
sudo usermod -aG docker deployГрупа docker фактично надає права, близькі до root. Тому додавати до неї слід лише довірених користувачів.
Щоб нова група стала доступною, вийдіть із SSH і підключіться знову:
exit
ssh deploy@203.0.113.10Перевірте:
docker run --rm hello-worldУвімкніть автоматичний запуск Docker під час завантаження сервера:
sudo systemctl enable --now dockerСтворіть каталог проєкту:
mkdir -p ~/web-app/site
cd ~/web-appСтворіть тестову сторінку застосунку:
cat > site/index.html <<'EOF'
<!doctype html>
<html lang="uk">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker VPS</title>
</head>
<body>
<h1>Застосунок працює</h1>
<p>Сторінка доставлена через Docker і Caddy.</p>
</body>
</html>
EOFСтворіть файл compose.yaml:
services:
app:
image: nginx:1.27-alpine
restart: unless-stopped
volumes:
- ./site:/usr/share/nginx/html:ro
caddy:
image: caddy:2.8-alpine
restart: unless-stopped
depends_on:
- app
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:У цьому файлі:
app запускає Nginx із тестовою HTML-сторінкою;
caddy є єдиним контейнером із опублікованими портами;
app не має прямого доступу з Інтернету;
restart: unless-stopped запускає контейнери після перезавантаження VPS;
том caddy_data зберігає сертифікати HTTPS;
том caddy_config зберігає службову конфігурацію Caddy.
Створіть файл Caddyfile:
cat > Caddyfile <<'EOF'
example.com {
encode gzip
reverse_proxy app:80
}
EOFЗамініть example.com на власний домен.
Ім’я app у директиві reverse_proxy — це ім’я сервісу в Compose. Docker Compose автоматично створює внутрішню мережу та DNS-запис для цього імені.
Caddy автоматично:
приймає HTTP-запити;
отримує сертифікат для домену;
перенаправляє HTTP на HTTPS;
обслуговує HTTPS;
оновлює сертифікат до завершення його дії.
Для цього Caddy має мати доступ до портів 80 і 443, а DNS домену має вже вказувати на VPS.
Перевірте підсумкову конфігурацію Compose:
docker compose configЗапустіть контейнери у фоновому режимі:
docker compose up -dПеревірте їхній стан:
docker compose psОбидва сервіси мають бути у стані running.
Перегляньте журнали Caddy:
docker compose logs -f caddyУ журналах має з’явитися інформація про отримання або завантаження сертифіката. Для завершення перегляду натисніть Ctrl+C. Це не зупиняє контейнер.
Перевірте застосунок локально на сервері:
curl -I https://example.comОчікуваний результат міститиме статус:
HTTP/2 200Також перевірте перенаправлення з HTTP:
curl -I http://example.comОчікуваний результат:
HTTP/1.1 308 Permanent RedirectПісля цього відкрийте https://example.com у браузері.
На VPS перевірте, які порти слухаються:
sudo ss -tulpnЗзовні мають бути доступні лише потрібні сервіси:
SSH на 22/tcp;
HTTP на 80/tcp;
HTTPS на 443/tcp.
Контейнер app не публікує порт через секцію ports, тому він доступний лише іншим контейнерам у Docker-мережі.
Docker може змінювати правила iptables для опублікованих портів. Тому не публікуйте зайві порти контейнерів на VPS. Для цього застосунку назовні відкриті лише порти Caddy.
Перед оновленням перегляньте поточний стан:
cd ~/web-app
docker compose psЯкщо змінюється образ або конфігурація, завантажте нові образи:
docker compose pullПерезапустіть застосунок:
docker compose up -dПереконайтеся, що контейнери знову запущені:
docker compose ps
docker compose logs --tail=100Для простої зміни HTML достатньо змінити файл у каталозі site. Оскільки він змонтований у контейнер як volume, зміни з’являться без перескладання образу.
Команда нижче зупиняє та видаляє контейнери, але не видаляє іменовані volumes:
docker compose downЦе важливо для Caddy: сертифікати зберігаються у caddy_data. Не видаляйте цей volume без потреби.
Команда з видаленням volumes має такий вигляд:
docker compose down -vВикористовуйте її обережно, оскільки вона видалить дані, які зберігаються в іменованих томах.
Перевірте стан і журнали:
docker compose ps
docker compose logs app
docker compose logs caddyПеревірте синтаксис конфігурації:
docker compose configПеревірте DNS:
dig +short example.comПеревірте firewall:
sudo ufw statusПеревірте доступність портів із локального комп’ютера:
nc -vz example.com 80
nc -vz example.com 443Якщо порт недоступний, перевірте також firewall у панелі VPS-провайдера.
Найчастіші причини:
домен указує не на цей VPS;
порт 80 закритий;
порт 443 закритий;
існує некоректний AAAA-запис;
Caddy не може записати дані у volume;
DNS-зміни ще не поширилися.
Перегляньте журнали:
docker compose logs caddyНе закривайте останню робочу SSH-сесію, доки не перевірите нову.
Якщо доступ втрачено:
Використайте web-консоль або rescue-консоль провайдера.
Перевірте /etc/ssh/sshd_config.
Перевірте права на /home/deploy/.ssh.
Перевірте, що правило SSH дозволяє потрібний порт.
Перевірте конфігурацію командою sshd -t.
Якщо ключ не скопійовано або має неправильні права, після встановлення PasswordAuthentication no можна втратити доступ.
Правильний порядок:
Створити користувача.
Додати SSH-ключ.
Перевірити вхід у новій сесії.
Вимкнути парольну автентифікацію.
Ще раз перевірити нове підключення.
Команда ufw enable може одразу заблокувати поточне підключення. Спочатку виконайте:
sudo ufw allow 22/tcpі лише потім активуйте UFW.
Такий фрагмент робить застосунок доступним напряму з Інтернету:
ports:
- "8080:80"Для reverse proxy він не потрібен. У наведеній конфігурації порт опублікований лише для Caddy, а застосунок доступний через app:80.
Якщо не зберігати /data, Caddy може втратити отримані сертифікати після видалення контейнера. Використовуйте іменований volume:
volumes:
- caddy_data:/dataCaddy не зможе отримати сертифікат, якщо домен ще не вказує на VPS. Спочатку налаштуйте DNS і перевірте його через dig.
Для адміністрування використовуйте користувача deploy і sudo, а не постійний root-сеанс. Це зменшує ризик випадкових небезпечних операцій.
Для розгортання Docker-застосунку на VPS потрібно:
Налаштувати DNS домену на IP-адресу VPS.
Створити окремого адміністративного користувача.
Налаштувати вхід через SSH-ключ.
Вимкнути root-вхід і парольну SSH-автентифікацію після перевірки ключа.
Дозволити через firewall лише SSH, HTTP і HTTPS.
Встановити Docker Engine та Docker Compose plugin.
Запустити застосунок через compose.yaml.
Використати Caddy як reverse proxy.
Зберігати дані Caddy у persistent volumes.
Перевірити DNS, журнали контейнерів, firewall і HTTPS.