Всем привет! Часто требуется поднять свой проект на VPS/VDS. Именно это я и покажу в данной статье.
Что нам понадобится
VPS (Ubuntu 22.04, Ubuntu 24.04 - самый доступный вариант).
Домен (для примера будет использоваться test.ru) и доступ к DNS-записям домена.
Приложение (код вашего проекта), которое мы будем деплоить.
В конце я покажу альтернативный способ, который не потребует настройки NGINX, SSL, покупки домена и других вещей, а именно использование "движка приложений" Amvera с развертыванием через простой git push, где вся настройка произойдет автоматически.
От теории к практике: что мы будем делать?
Давайте сначала зафиксируем картину, чтобы потом команды, которые я опишу ниже, не казались сложными и "магическими".
Что мы будем делать (очень кратко):
Запустим приложение "в коробке" - в Docker: приложение будет работать на сервере, но не торчать в интернет напрямую. То есть оно будет доступно только локально, например по
127.0.0.1:8000.Поставим reverse-proxy с помощью Nginx: Nginx будет единственным, кто торчит наружу на портах 80 и 443 (для ssl).
NGINX будет делать две вещи:
Принимать запросы на
test.ru;Перенаправлять их внутрь Docker-контейнера (
127.0.0.1:8000).Сделаем нормальный HTTPS (SSL-сертификат) чтобы браузер показывал замочек и не ругался.
Сертификат используем бесплатный от Let's Encrypt. Cтавится он через certbot, плюс сам обновляется автоматически (если открыт 80 порт).
Практика и настройка VPS/VDS
Ниже я покажу “минимально правильный” путь: безопасный вход на сервер, установка Docker, загрузка проекта на VPS, запуск контейнера, подключение домена через Nginx и включение HTTPS.
Шаг 0: Подключаемся к серверу и обновляем систему
ssh root@IP-сервера
# Например: ssh root@1.2.3.4
# Команда ниже обновляет все пакеты и список доступных пакетов в системе
apt update && apt -y upgrade
Шаг 1. Создаем безопасного пользователя и настраиваем доступ по SSH-ключу
Работать под root - не лучшая идея. Мы будем делать правильно:
adduser deploy
usermod -aG sudo deploy
Теперь на своем ПК создаем ключ:
ssh-keygen -t ed25519
И копируем его на сервер (чтобы сервер мог нас корректно авторизовать):
ssh-copy-id deploy@IP-сервера
Проверяем вход:
ssh deploy@IP-сервера
Дальше по пути: отключаем root-логин и вход по паролю (чтобы мы могли войти только по ключу):
sudo nano /etc/ssh/sshd_config
Установим:
PermitRootLogin no
# !!! Не устанавливай PasswordAuthentication no, если еще не проверил вход по ключу !!!
PasswordAuthentication no
И применяем:
sudo systemctl restart ssh
Шаг 2. Включаем фаервол (UFW)
Оставляем наружу только SSH/HTTP/HTTPS:
sudo apt -y install ufw
# Запрещаем все входящее
sudo ufw default deny incoming
# Разрешаем все исходящее
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
# HTTP
sudo ufw allow 80/tcp
# HTTPS
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status
Шаг 3. Устанавливаем Docker
Вы можете просто скопировать следующий скрипт для установки Docker:
sudo apt update
sudo apt install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
или установить Docker по официальной инструкции.
И добавим себя в группу Docker:
sudo usermod -aG docker $USER
newgrp docker
docker version
Шаг 4. Загружаем файлы проекта на VPS
Рассмотрим два нормальных способа.
Способ A. через Git (самый удобный)
Если проект есть в Github/Gitlab:
sudo mkdir -p /opt/myapp # <- Здесь будет лежать наше приложение
sudo chown -R $USER:$USER /opt/myapp
cd /opt/myapp
git clone <ССЫЛКА_НА_РЕПОЗИТОРИЙ> .
Способ Б: загрузка файлов с ПК на сервер (scp/rsync)
Если репозитория нет или проще загрузить файлы:
scp:
scp -r ./myapp deploy@IP_СЕРВЕРА:/opt/
или rsync (лучше, если много файлов):
rsync -av --progress ./myapp/ deploy@IP_СЕРВЕРА:/opt/myapp/
Шаг 5. Создание Dockerfile и запуск приложения
Здесь все чуть более индивидуально, но шаблон один и тот же: в Dockerfile мы описываем, как собрать и запустить контейнер.
Что вообще такое Dockerfile:
Dockerfile - это простой текстовый файл, который содержит в себе понятную для Docker инструкцию к сборке и запуску образа (image) вашего приложения.
Я покажу два самых популярных кейса: Python FastAPI и Node.js.
5.1 Dockerfile - пример для Python FastAPI
FROM python:3.12-slim
WORKDIR /app
# Предполагается, что у нас есть файл requirements.txt со всеми зависимостями проекта
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host=0.0.0.0", "--port=8000"]
5.2 Dockerfile - пример для Node.js
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
5.3 Сборка образа и запуск контейнера
После того, как Dockerfile готов, остается 2 шага:
Собрать
imageЗапустить контейнер из образа
Перейдем в папку проекта:
cd /opt/myapp
Собираем образ (пусть будет myapp:latest):
# Предполагается, что Dockerfile расположен в той же папке, где работает терминал (/opt/myapp)
docker build -t myapp:latest .
Проверяем, появился ли образ:
docker images | grep myapp
Запускаем контейнер
Для примера с Python FastAPI:
docker run -d \
--name myapp \
--restart unless-stopped \
-p 127.0.0.1:8000:8000 \
myapp:latest
Проверяем, работает ли контейнер:
docker ps
docker logs -f --tail=200 myapp
5.4 Обновление приложения
Когда меняем код и хотим обновить контейнер, логика простая:
Остановить и удалить старый контейнер.
Собрать новый образ.
Запустить новый контейнер.
cd /opt/myapp
docker stop myapp
docker rm myapp
docker build -t myapp:latest .
docker run -d \
--name myapp \
--restart unless-stopped \
-p 127.0.0.1:8000:8000 \
myapp:latest
Шаг 6. Настраиваем Nginx как reverse-proxy
Ставим nginx:
sudo apt -y install nginx
sudo systemctl enable --now nginx
Отключаем дефолтный сайт:
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Создаем конфиг сайта:
sudo nano /etc/nginx/sites-available/myapp
Заменим домен test.ru на собственный:
server {
listen 80;
server_name test.ru www.test.ru;
client_max_body_size 25m;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
}
Активируем сайт:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
sudo nginx -t
sudo systemctl reload nginx
6.1 Установка A-записи на домене
Это необходимо для того, чтобы домен понимал, к какому IP он привязан.
В значении A записи (это такая DNS-запись, обычно настраивается на сайте регистратора в настройках домена) нужно прописать IP машины (VPS/VDS).
Шаг 7. HTTPS через Let's Encrypt (certbot)
Ставим certbot (версия для nginx):
sudo apt -y install certbot python3-certbot-nginx
Выписываем сертификат и автоматически правим конфиг Nginx:
sudo certbot --nginx -d test.ru -d www.test.ru
Проверяем автообновление (необязательно):
sudo certbot renew --dry-run
Шаг 8. Проверка и правки
Если контейнер запущен, A-запись раскатилась по DNS-серверам и test.ru открывается - все готово. Однако иногда бывает, что сайт отдает ошибку 502.
502 Bad Gateway
Обычно говорит о том, что Nginx не достучался до приложения.
docker ps
docker logs --tail=200 myapp
ss -lntp | grep 8000
sudo tail -n 200 /var/log/nginx/error.log
Альтернатива: запуск на Amvera за 3 минуты без настройки инфраструктуры
С VPS-путем выше все честно: он дает полный контроль, но требует времени и внимания - обновления ОС, UFW, конфиги Nginx, SSL, перезапуски, логи.
Если задача быстро развернуть проект и не заниматься обслуживанием сервера, проще использовать специализированный движек приложений, такой как Amvera.
Что такое Amvera
Amvera - сервис, заточенный на быстрый и легкий деплой IT-приложений, предоставляющий бонусом:
Автоматизацию развертывания. Достаточно просто сделать push в привязанный git (или перетянуть файлы в интерфейсе) и сервис сам все настроит и запустит.
Бесплатный внешний домен с HTTPS;
Встроенные бэкапы, алерты, мониторинг, логирование, проксирование до нейронок и еще множество вещей, упрощающих жизнь разработчика.
Бесплатные 111 рублей на баланс для тестов;
Когда это особенно удобно:
нужно быстро показать MVP/демо приложения
нет желания админить VPS
проект не один, и хочется повторяемости деплоя
А VPS-вариант выше остается отличным способом разобраться “как оно устроено внутри” и получить полный контроль.
Практика: деплой Amvera
Шаг 0. Регистрация пользователя
Тут все просто: регистрируемся по ссылке и сразу получаем бесплатные 111 рублей для тестов.
Шаг 1. Выбор типа приложения
Amvera предлагает запуск сразу нескольких типов приложения:
Обычное приложение. Конфигурация, файлы проекта - все от вас.
Преднастроенный сервис. Это сервис, который был заранее настроен и который можно развернуть менее, чем за 5 минут (это n8n, pgadmin, wordpress и др.).
Cron-сервис. То же обычное приложение, но с возможностью запуска по расписанию.
Для нас актуален первый тип - Приложение.
Шаг 2. Создание проекта
Открываем главную страницу проектов и жмём кнопку "Создать проект"

В открывшемся окне выбираем тип сервиса: "Приложение". Жмем далее.
Далее выбираем произвольное название проекта и тариф.
Обязательно жмем "Далее". После этого, дальнейшие этапы настройки приложения можно пропустить.
Если вы все сделали правильно, во вкладке "Приложения" главной страницы должен появиться ваш проект со статусом "Проект не развертывался".
Открываем его.
Шаг 3. Базовая навигация и загрузка файлов
Тут нам важны все вкладки, но кратко я расскажу только про некоторые:
Репозиторий: тут собраны все файлы проекта:
Code: Git-репозиторий, содержащий все файлы для сборки запускаемого образа. Именно туда мы загрузим файлы.
Data: постоянное хранилище /data. Именно сюда ОБЯЗАТЕЛЬНО нужно сохранять все изменяемые в процессе работы приложения файлы. Это может быть как SQLite-БД, так и простой изменяемый JSON.
Конфигурация: встроенный конфигуратор и генератор amvera.yml (так называется файл конфигурации). К нему мы обратимся чуть позже.
-
Логи: наверное, самая важная вкладка для уже собранного приложения. В ней собраны:
Логи сборки проекта,
Логи приложения проекта,
Логи системы,
Переменные: вкладка, в которой вы можете создавать переменные окружения или секреты, доступные как во время сборки приложения, так и во время работы собранного образа.
Домены: здесь вы можете подключить как собственный домен с HTTP/HTTPS, так и бесплатный домен от Amvera (ничего доплачивать не нужно).
Итак, загрузим файлы проекта.
Для этого переходим во вкладку Репозиторий -> Code и грузим файлы либо через интерфейс перетягиваем, либо подключаем GitLab, GitHub или BitBukket репозиторий, либо грузим вручную через git.
Шаг 4. Настройка конфигурации
Тут все как с Dockerfile - все индивидуально под каждый проект. Мы можем лишь показать примеры некоторых конфигураций.
Если у вас возникнут трудности с созданием конфигурации, обращайтесь к документации: https://docs.amvera.ru/applications/supported-env.html.
Пример для Python (запускаем main.py):

Шаг 5. Сборка и запуск приложения
Когда ваша конфигурация готова, вы можете попробовать собрать проект. Делается это во вкладке "Конфигурация" кнопкой "Собрать".
Во время сборки рекомендуется следить за логами и статусом проекта. Не всегда получается запустить проект с первого раза - это нормально.
Если у вас возникают трудности с деплоем приложения - не стесняйтесь задавать вопросы поддержке, мы будем рады помочь.
Итог настройки VDS для деплоя
Мы развернули код на VDS, используя такие технологии как Docker, настроили Nginx и HTTPS (Let’s Encrypt). Открыли только нужные порты для безопасности и активировали наш код на удаленном сервере.
Если нужен тот же результат быстрее и без обслуживания сервера, можно задеплоить на Amvera за 3 минуты, сделав push в привязанный git и заполнив пару полей конфигурации.
Dok_DD
еще один 100600 хауту, написанный под копирку.
и root можно смело оставлять, если включить мозг и почитать man sshd_config на предмет Match хотя бы.
и от туда же узнать что without-password давно уже deprecated