Развёртывание статического на VPS вручную
Развёртываем nginx и статический сайт на VPS с Debian GNU/Linux вручную с помощью bash, ssh и rsync
Допустим, что у вас уже есть:
- Виртуальная машина (VPS) с Debian GNU/Linux с известным IP адресом и доступом по SSH ключу
- Доменное имя, привязанное к IP адресу этой виртуальной машины
Разберём, как развернуть статический сайт с nginx на этой машине вручную.
Инструкция написана в предположении, что развёртывать сайт мы будем тоже из Linux.
Настройка Unix пользователей и доступов по ssh
Настройка доступа под своим пользователем по ключу с sudo
Скорее всего VPS позволяет подключится по SSH ключу из-под пользователя root, например так:
ssh root@ip-адрес-vps-сервера
- Работать из-под root в Linux чревато проблемами — например, можно необдуманно выполнить опасную команду.
- Мы настроим подключение под обычным пользователем, и будем использовать
sudo
для запуска отдельных команд, требующих привилегий root.
Если на вашем компьютере тоже Linux, выясните имя пользователя командой: id -u -n
Допустим, мы получили имя ivan.ivanov
.
Создать пользователя интерактивно (лучше указать привычный и надёжный пароль):
adduser --force-badname ivan.ivanov
Добавить пользователя в группу sudo, чтобы он мог пользоваться sudo:
usermod -aG sudo ivan.ivanov
Отредактировать файл /etc/sudoers.d/ivan_ivanov
- Мы позволим этому Unix пользователю использовать sudo без пароля
- Пустая строка в конце файла обязательна, иначе запуск sudo сломается для всех пользователей!
ivan.ivanov ALL=(ALL:ALL) NOPASSWD: ALL
Запустить сессию bash с новым пользователем и создать каталог ~/.ssh
:
sudo -uivan.ivanov bash -l
mkdir -p ~/.ssh
Отредактировать файл ~/.ssh/authorized_keys
, вставив туда свой публичный ключ (~/.ssh/id_rsa.pub
или ~/.ssh/id_ed25519.pub
).
Пример:
ssh-rsa AAAA...BHK ivan.ivanov@home
Всё! Теперь можно входить в систему по ключу и использовать sudo:
ssh ip-адрес-vps-сервера
sudo whoami
Подготовка конфигов nginx
На своём компьютере создадим в проекте отдельную версию конфигов nginx для production:
- В проекте создайте подкаталог — например,
src/nginx-prod/
- Скопируйте в новый каталог конфиги nginx, используемые для локальной разработки — например, они могут быть в
src/nginx/
- Внесите изменения в конфиги для production
В конфигах для production стоит сделать несколько изменений:
- Поменять
user nginx;
наuser www-data;
— в Debian веб-сервер принято запускать под пользователем www-data - Пересмотреть
worker_processes 2;
— возможно, вместо 2 поставить иное число или простоauto
, чтобы число процессов nginx соответствовало числу ядер в системе - Поменять
error_log
, чтобы писать логи в файл/var/log/nginx/error.log
вместо stderr- в контекстах server можно вместо error.log указать иное имя файла — например,
atdd.ru.error.log
- в контекстах server можно вместо error.log указать иное имя файла — например,
- Поменять
access_log
, чтобы писать логи в файл/var/log/nginx/access.log
вместо stdout- в контекстах server можно вместо access.log указать иное имя файла — например,
atdd.ru.access.log
- в контекстах server можно вместо access.log указать иное имя файла — например,
- Явно определить
ssl_protocols
иssl_ciphers
, чтобы поддержка TLS не зависела от версии nginx в дистрибутиве Linux, установленном на VPS - В контекстах
server
убрать локальные вариантыserver_name
— например, убрать atdd.lan и localhost, но оставить atdd.ru - Поменяйте каталог в директиве
root
на/var/www/html/
,/usr/local/www/atdd.ru/
или любой иной каталог, куда вы планируете скопировать данные статического сайта
Пример изменений в nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
# ... другие директивы ...
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/access.log;
}
Пример изменений в конфиге хоста (контекст server):
server {
server_name atdd.ru;
access_log /var/log/nginx/atdd.ru.access.log;
error_log /var/log/nginx/atdd.ru.error.log warn;
root /usr/local/www/atdd.ru/;
# ... другие директивы ...
}
Установка и настройка nginx на сервере
Сначала зайдите на сервер: ssh ip-адрес-vps-сервера
Затем установите nginx:
sudo apt-get update
sudo apt-get install nginx
# Проверка версии nginx
sudo nginx -v
# Альтернативный способ - проверка версии пакета nginx
apt-cache policy nginx
Теперь поменяйте основной конфиг nginx:
# Редактируем /etc/nginx/nginx.conf - скопируйте туда свою версию
sudo nano /etc/nginx/nginx.conf
# Проверяем корректность конфига nginx
sudo nginx -t
Установка последней версии nginx
В дистрибутиве может быть устаревшая версия nginx, что помешает автоматизации работы с Let's Encrypt.
- Например, в версиях nginx ниже 1.25.1 проявится проблема HTTP2 support in Nginx plugin
- Решение — установить последние версии nginx из официального репозитория nginx
Подробнее см. nginx: Linux packages, краткая версия ниже:
# Установка других необходимых пакетов
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
# Получение и проверка GPG-ключа репозитория
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
# Добавления репозитория APT
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
# Установка приоритета для пакетов из нового репозитория
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
# Установка новой версии nginx
sudo apt update
sudo apt install nginx
# Проверка версии nginx
sudo nginx -v
Получение сертификата Let's Encrypt
Временный конфиг nginx
Добавим временный файл конфигурации на время получения сертификата Let's Encrypt:
- Создайте конфиг своего сайта в каталоге
/etc/nginx/conf.d
— например, используя редактор nano:sudo nano /etc/nginx/conf.d/atdd_ru.conf
- Скопируйте конфигурацию ниже, поменяв atdd.ru на свой домен
- Обработка URL, начинающихся с
/.well-known
, нужна для получения сертификата Let's Encrypt
server {
listen 80;
listen [::]:80;
server_name atdd.ru;
root /usr/share/nginx/html;
location ~ /.well-known {
allow all;
}
location / {
index index.html;
}
}
Установка и запуск Certbot
Certbot — инструмент для автоматизации получения сертификатов Let's Encrypt
- Сертификаты Let's Encrypt выдаются на конкретный домен автоматизированно на 90 дней любому, кто докажет владение данным доменом
- Для выдачи сертификатов предусмотрен определённый протокол (ACME) и два способа доказательства владения доменом
- Мы применим один из способов доказательства владения доменом, реализованный в Certbot — отдача определённого файла с сервера, обслуживающего домен
Поддержка различных веб-серверов в Certbot реализована плагинами, и мы установим Certbot с плагином для nginx:
# Установка в Debian 12:
sudo apt install certbot python3-certbot-nginx
Далее запускаем Certbot:
sudo certbot --nginx
Результат
После запуска Certbot файл конфигурации nginx изменится.
- Обратите внимание на строки с суффиксом "# managed by Certbot"
- Эти строки не следует редактировать, т.к. их редактирует сам Certbot
- Однако их можно скопировать в локальную версию production конфигов в каталоге
src/nginx-prod/conf.d/
Вывести конфиг можно командой cat /etc/nginx/conf.d/<ваш-сайт>.conf
. В моём случае он выглядит так:
server {
server_name atdd.ru;
root /usr/share/nginx/html;
location ~ /.well-known {
allow all;
}
location / {
index index.html;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/atdd.ru/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/atdd.ru/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = atdd.ru) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name atdd.ru;
return 404; # managed by Certbot
}
Применяем финальный конфиг
В собственный конфиг nginx не забудьте внести правки от Let's Encrypt:
- Скопировать все строки "# managed by Certbot"
- Добавить
обработку /.well-known
Пример:
server {
listen 80;
listen [::]:80;
server_name atdd.ru;
location ~ /.well-known {
root /usr/share/nginx/html;
allow all;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name atdd.ru;
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/atdd.ru/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/atdd.ru/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location ~ /.well-known {
allow all;
}
# ... другие параметры конфигурации
}
Сохраним финальную версию и перезагрузим конфигурацию nginx
# Редактируем конфиг своего сайта - например, atdd.ru
sudo nano /etc/nginx/conf.d/atdd_ru.conf
# Проверяем корректность конфига nginx,
# затем выполняем чтение конфига сервисом nginx
sudo nginx -t && sudo systemctl reload nginx
Развёртываем статический сайт через rsync
Утилита rsync предназначена для копирования файлов на сервер или между серверами при наличии SSH доступов. Для облачных платформ есть похожая утилита rclone, способная работать с S3-совместимыми хранилищами и с десятками других API облачных хранилищ.
Перед первым использованием нужно установить rsync как локально, так и на сервере:
sudo apt-get install rsync
Допустим, что мы хотим скопировать статический сайт с такими ограничениями:
- Локально статика находится в каталоге
public/
проекта - На сервере nginx настроен на раздачу статики с каталога
/usr/local/www/atdd.ru/
- Пусть удалённый сервер доступен по домену
atdd.ru
или по какому-то IP адресу - Мы не хотим копировать определённые файлы, например файл
.gitignore
- Вход по SSH на сервере будет из-под root, но владельцем скопированных файлов будет www-data
Перед первым копированием на сервере надо создать каталог и поменять его владельца на www-data:
sudo mkdir -p /usr/local/www/atdd.ru
sudo chown www-data:www-data /usr/local/www/atdd.ru
Затем для каждого развёртывания можно использовать rsync:
# Проверка
rsync --dry-run --archive --progress --delete --exclude=.gitignore \
--chown=www-data:www-data \
public/ atdd.ru:/usr/local/www/atdd.ru/
# Выполнение
rsync --archive --progress --delete --exclude=.gitignore \
--chown=www-data:www-data \
public/ root@atdd.ru:/usr/local/www/atdd.ru/
Объяснение флагов rsync:
Флаг | Зачем он нужен |
---|---|
--archive | Архивный режим: копировать рекурсивно с сохранением владельца, группы, прав на файлы и времени изменения |
--progress | Выводить прогресс |
--delete | Удалять файлы в целевом каталоге, если их нет в источнике |
--exclude=.gitignore | Исключить файлы по указанному шаблону |
--chown=www-data:www-data | Поменять владельца и группу файлов на указанного |
Можно добавить в проект bash скрипт bin/deploy
для копирования на сервер:
#!/usr/bin/env bash
set -o errexit
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
PROJECT_DIR=$(dirname "$SCRIPT_DIR")
rsync --archive --stats --delete --exclude=.gitignore \
--chown=www-data:www-data \
"$PROJECT_DIR/public/" \
root@atdd.ru:/usr/local/www/atdd.ru/