HTTPS становится всё более сильным трендом современного интернета. И это хорошо, особенно, когда клиенты, взаимодействуя с серверами, обмениваются с ними конфиденциальными данными. Для того, чтобы пользоваться HTTPS, нужен SSL-сертификат, который применяется для проверки подлинности сервера. Проект Let’s Encrypt значительно упростил процесс получения SSL-сертификатов. До его появления всё было гораздо сложнее.
Let’s Encrypt использует Certbot от Electronic Frontier Foundation для автоматизации процесса получения SSL-сертификата. Поддерживаются разные типы веб-серверов (Apache, nginx, и другие), которые работают на Unix-подобных ОС. Если ваш сервер соответствует системным требованиям Let’s Encrypt, это значит, что вы сможете получить сертификат в практически полностью автоматическом режиме. К сожалению, связку Node.js/Express.js Let’s Encrypt не поддерживает. То есть, в данном случае автоматически получить сертификат от Certbot не получится. Однако, не всё потеряно. Используя Let’s Encrypt и Certbot, сертификат не так уж и сложно получить вручную.
Предварительные сведения
Мы собираемся использовать Certbot в режиме webroot, запуская его с ключом --webroot
. Если в двух словах, то в этом режиме Certbot разместит файл в некоей директории нашего сервера, которая должна быть доступна по протоколу HTTP.
С помощью Express обслуживать директории, содержащие статические файлы, можно, используя функцию express.static()
.
Если взглянуть на раздел документации Certbot, посвящённый режиму webroot, окажется, что Certbot будет искать на сервере файл по адресу http://<your_server_url>/.well-known/acme-challenge/
. Если он может успешно получить по HTTP файл, который был размещён в указанной директории, он создаст для этого сервера SSL-сертификат.
Итак, приступим.
План работ
Для получения сертификата и поддержания его актуальности нам понадобится пройти через пять этапов:
- Перенаправить соответствующие порты.
- Настроить структуру директорий для статических файлов и организовать её обслуживание с помощью Express.
- Установить и запустить Certbot.
- Настроить Express на использование HTTPS.
- Обновить сертификат Let’s Encrypt через 90 дней.
Ниже опишем эти этапы подробнее, с примерами кода и команд.
Перенаправление портов
Уверен, это ни у кого затруднений не вызовет, но, для полноты изложения, опишу этот шаг.
Для успешного прохождения процесса верификации требуется URL сервера. Certbot будет использовать этот URL для того, чтобы связаться с сервером и получить данные по HTTP. Это означает, что порт 80 на предоставленном URL должен быть доступен из интернета. Не помешает открыть и порт 443, так как это порт HTTPS по умолчанию.
Лично я предпочитаю держать мои Express-сервера на портах, номера которых выше, чем 1024, а затем, используя правила перенаправления, передавать трафик с портов 80 или 443 на сервера. Как результат, мне не нужно давать Express повышенные привилегии, что безопаснее, особенно учитывая то, что веб-сервер будет обрабатывать потенциально опасный трафик.
Для того, чтобы проверить сетевые настройки, можно воспользоваться утилитой curl
. Например, если на сервере имеется адрес для тестирования работоспособности системы (что всегда полезно), запрос на этот адрес можно выполнить с помощью curl
. Предположим, сервер настроен так:
// filename: app.js
const app = require('express')();
app.get('/health-check', (req, res) => res.sendStatus(200));
app.listen(8080);
Если обратиться к конечной точке health-check
с помощью curl
, на то, что всё в порядке, укажет ответ HTTP 200.
curl http://<your_server_url>/health-check
Когда сеть и сервер готовы к работе, можно переходить к настройке обслуживания статических файлов.
Обслуживание статических файлов
Как сказано выше, адрес, по которому обратится Certbot для проверки сервера — /.well-known/acme-challenge
. Express использует функцию express.static()
для обслуживания статических файлов по пути, указанному этой функции. Этот путь становится корнем сервера. Часто папка, которая хранит статические данные веб-сайта, называется public
или static
, и, например, если у вас есть текстовый файл, видный в файловой системе как /static/test-text/mytextfile.txt
, обратиться к нему извне можно по адресу http://<your_server_url/test-text/mytextfile.txt
. Учитывая это, создадим структуру директорий для нужд Certbot и подключим её в Express.
cd static
mkdir -p .well-known/acme-challenge
Вышеприведённая команда выполняется из корня проекта, при этом подразумевается, что директория для статических данных имеет имя static
.
// filename: app.js
const express = require('express');
const app = express();
app.use(express.static('static'));
app.listen(8080);
Теперь, после того, как Express настроен на обслуживание правильной папки, проверим работоспособность системы.
echo "this is a test" > static/.well-known/acme-challenge/9001
curl http://<your_server_url>/.well-known/acme-challenge/9001
Если в консоль будет выведен текст «this is a test», значит данный шаг успешно завершён и можно идти дальше – к созданию нового SSL-сертификата.
Certbot
Первый шаг на данном этапе – установка Certbot. Здесь можно найти инструкции по установке. А именно, чтобы их увидеть, в поле I’m using выберите None of the above, затем, в следующем поле, выберите вашу ОС. После этого будет показана команда для установки. Например, для Ubuntu 16.04 (xenial) эта команда выглядит так: sudo apt-get install letsencrypt
.
Следующий шаг заключается в том, чтобы сгенерировать сертификат. Как уже было сказано, мы собираемся запустить Certbot в режиме webroot. Для этого понадобится передать ему путь, который будет использован в качестве корня веб-сервера (используя ключ –w
), и доменное имя (с помощью ключа –d
). В данном случае команда выглядит так:
letsencrypt --webroot -w ./static -d <your_server_url>
Здесь мы исходим из предположения, что вы находитесь в директории проекта. После успешного выполнения команды, вы увидите соответствующее сообщение и сведения о расположении сгенерированных файлов. Обычно они находятся по адресу /etc/letsencrypt/live/<your_server_url>
. О том, что это за файлы, можно узнать из раздела Webroot в руководстве по Certbot. Мы собираемся использовать с нашим Express-сервером файлы fullchain.pem
и privkey.pem
.
Отлично! Вот он, наш новенький SSL-сертификат. Теперь задействуем его.
Express и HTTPS
Express, сразу после установки, работает лишь по HTTP. Мы можем настроить использование HTTPS в Express, используя модуль Node https
. Для того, чтобы это сделать, понадобится два файла – сертификат и секретный ключ. Кстати сказать, берегите от чужих глаз секретный ключ вашего сервера, а доступ к файлу секретного ключа давайте только авторизованным пользователям.
Кроме того, рекомендуется либо скопировать файлы fullchain.pem
и privkey.pem
в директорию проекта, либо создать символические ссылки на них. Создание символических ссылок упрощает процесс обновления, но что именно выбрать – дело ваше.
Нижеприведённый код основан на предположении о том, что файлы fullchain.pem
и privkey.pem
находятся в папке sslcert
в директории проекта.
// filename: app.js
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
// Настройка сервера Express
const options = {
cert: fs.readFileSync('./sslcert/fullchain.pem'),
key: fs.readFileSync('./sslcert/privkey.pem')
};
express.listen(8080);
https.createServer(options, app).listen(8443);
Кроме того, тут не помешает Helmet.js. Этот пакет помогает защищать Express-сервера, управляя HTTP-заголовками. Он, помимо прочего, добавляет HSTS, убирает заголовок X-Powered-By и устанавливает заголовок X-Frame-Options для защиты от кликджекинга.
Установить его очень просто:
npm install --save helmet
После установки Helmet, его можно задействовать в Express как промежуточный слой обработки данных.
// filename: app.js
app.use(require('helmet')());
Теперь, чтобы окончательно убедиться в том, что всё работает, можно проверить сервер с помощью чего-то вроде SSL Server Test.
Обновление сертификата
Сертификаты Let’s Encrypt действуют 90 дней. Хорошо это или плохо – спорить бессмысленно, особенно учитывая то, что процесс обновления сертификата очень прост. А именно, для обновления сертификата достаточно выполнить команду letsencrypt renew
и Certbot выпустит новый сертификат. Рекомендуется автоматизировать этот процесс, используя либо задания cron
, либо что-то вроде systemd
.
Выводы
В итоге, мы настроили сервер Express на обслуживание статических файлов по специфическому пути, использовали Certbot в режиме webroot для создания сертификата сервера и подключили HTTPS в Express, используя только что созданный сертификат. Хотя автоматический процесс взаимодействия с Certbot нам и не доступен, сделать вручную всё, что надо, не так уж и сложно.
Хочется надеяться, что Certbot, в обозримом будущем, оснастят поддержкой Node.js.
А как вы получаете SSL-сертификаты для Express-серверов? Пользуетесь ли сертификатами от Let’s Encrypt?
Автор: RUVDS.com