Развёртывание статического на VPS вручную

Развёртываем nginx и статический сайт на VPS с Debian GNU/Linux вручную с помощью bash, ssh и rsync


Допустим, что у вас уже есть:

  1. Виртуальная машина (VPS) с Debian GNU/Linux с известным IP адресом и доступом по SSH ключу
  2. Доменное имя, привязанное к IP адресу этой виртуальной машины

Разберём, как развернуть статический сайт с nginx на этой машине вручную.

Инструкция написана в предположении, что развёртывать сайт мы будем тоже из Linux.

Настройка Unix пользователей и доступов по ssh

Настройка доступа под своим пользователем по ключу с sudo

Скорее всего VPS позволяет подключится по SSH ключу из-под пользователя root, например так:

ssh root@ip-адрес-vps-сервера

Если на вашем компьютере тоже Linux, выясните имя пользователя командой: id -u -n

Допустим, мы получили имя ivan.ivanov.

Создать пользователя интерактивно (лучше указать привычный и надёжный пароль):

adduser --force-badname ivan.ivanov

Добавить пользователя в группу sudo, чтобы он мог пользоваться sudo:

usermod -aG sudo ivan.ivanov

Отредактировать файл /etc/sudoers.d/ivan_ivanov

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:

  1. В проекте создайте подкаталог — например, src/nginx-prod/
  2. Скопируйте в новый каталог конфиги nginx, используемые для локальной разработки — например, они могут быть в src/nginx/
  3. Внесите изменения в конфиги для production

В конфигах для production стоит сделать несколько изменений:

  1. Поменять user nginx; на user www-data; — в Debian веб-сервер принято запускать под пользователем www-data
  2. Пересмотреть worker_processes 2; — возможно, вместо 2 поставить иное число или просто auto, чтобы число процессов nginx соответствовало числу ядер в системе
  3. Поменять error_log, чтобы писать логи в файл /var/log/nginx/error.log вместо stderr
    • в контекстах server можно вместо error.log указать иное имя файла — например, atdd.ru.error.log
  4. Поменять access_log, чтобы писать логи в файл /var/log/nginx/access.log вместо stdout
    • в контекстах server можно вместо access.log указать иное имя файла — например, atdd.ru.access.log
  5. Явно определить ssl_protocols и ssl_ciphers, чтобы поддержка TLS не зависела от версии nginx в дистрибутиве Linux, установленном на VPS
  6. В контекстах server убрать локальные варианты server_name — например, убрать atdd.lan и localhost, но оставить atdd.ru
  7. Поменяйте каталог в директиве 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: 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:

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

Поддержка различных веб-серверов в Certbot реализована плагинами, и мы установим Certbot с плагином для nginx:

# Установка в Debian 12:
sudo apt install certbot python3-certbot-nginx

Далее запускаем Certbot:

sudo certbot --nginx

Результат

После запуска Certbot файл конфигурации nginx изменится.

Вывести конфиг можно командой 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:

Пример:

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

Допустим, что мы хотим скопировать статический сайт с такими ограничениями:

Перед первым копированием на сервере надо создать каталог и поменять его владельца на 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/