АгАртИ-А
Разработка АгАртИ-А.рф
- ^ X
Установка SSL-сертификата Apache
[ \ ] [ .. ]
agarty@apache22.com [/list/sslCertbot/]> ls -la

Установка SSL-сертификата Apache

Создано: 2020-04-14 12:59:19, обновлено: 2020-04-14 21:19:59

Установка SSL-сертификата Apache

В этой заметке я расскажу как подготовить сервер Apache к установке сертификата на домен, получение сертификата, его обновление и автоматическое его обновление с перезапуском сервера Apache. Сервер под управлением ОС FreeBSD, но принцип настройки везде одинаков, с небольшими отличиями.

Логика работы

Необходимо упростить будущую работу с сертификатами до максимума. На примере CertBot мы будем получать сертификат. Общая инструкция гласит, что бы получить сертификат, необходимо создать в папке домена, который получает сертификат, каталог ".well-known/acme-challenge/". Далее мы должны запустить certbot, указать при этом домены. В начале он создает в данном каталоге файл с уникальным именем. Далее certbot переходит по ссылке http://your.dmn/.well-known/acme-challenge/_тут_уникальное_имя_файла, если все ОК, то верификация пройдена. После чего генерируются ключи и сертификаты в каталог /usr/local/etc/letsencrypt/live/_имя_домена_/.

Далее переходим к виртуальным хостам Apache и настраиваем домен. Перезапускаем сервер, проверяем работу.

Если все ОК настраиваем крон на автообновление и перезагрузку сервера Apache.

Установка CertBot

В начале проверим, какие версии есть

#> pkg search certbot

Отобразится куча всего. Там много версий, выбираем ту, что нравится. На текущий момент я выбрал

py37-certbot-1.3.0,1           Let's Encrypt client

Устанавливаем

#> pkg install py37-certbot

Установка проста и не тривиальная.

Помимо этого можно установить мод для Apache, который по сути должен облегчать работу с сертификатами. В данной заметке мы проделаем все операции самостоятельно. Я люблю все контролировать, поэтому сделаем немного иначе, чем обычно.

Настройка конфига Apache 2.4

Перед настройкой и получением всех сертификатов необходимо подготовить сервер.

Открываем файл конфига, путь может различатся в зависимости от версии

#> ee /usr/local/etc/apache24/httpd.conf

Переходим к модулям и расскоментируем строку

LoadModule ssl_module libexec/apache24/mod_ssl.so

По плану, мы будем все файлы верификации складывать в одно место, и настроим общий каталог хранения. Так же установим для всех сайтов алиас, который будет вести на общий каталог. Например http://your.dmn/.well-known/ будет вести на созданный общий каталог и физически в директории домена каталог .well-known создавать не потребуется.

Создаем алиас и прописываем разрешения на директорию, дописываем в любое место конфига:

Alias /.well-known/ /path/to/dir/cert/.well-known/

<Directory "/path/to/dir/cert">
Options -Indexes
Order allow,deny
Allow from all
</Directory>

Где /path/to/dir/cert - полный пусть к директории, где будут хранится временные файлы верификации.

Почти в самом конце файла расскоментируем строку

Include etc/apache24/extra/httpd-ssl.conf

Выходим из файла и сохраняем изменения.

Настраиваем файл httpd-ssl.conf

#> ee /usr/local/etc/apache24/extra/httpd-ssl.conf

Данный файл служит для первичной настройки и работе протоколов SSL. По сути там указаны переменные по умолчанию. Но моя практика показала, что очень часто они крашат систему. По идее хорошо бы разобраться в каждом параметре, но так как нам нужно просто запустить, то упростим задачу и приведем файл к такому виду:

Listen 443
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
SSLPassPhraseDialog  builtin
SSLSessionCache        "shmcb:/var/run/ssl_scache(512000)"
SSLSessionCacheTimeout  300

Выходим сохраняемся.

Теперь создаем общий каталог. Ключ -p означает, что нужно создать все директории с поддиректориями указаные в пути

#> mkdir -p /path/to/dir/cert/.well-known/acme-challenge/

Первичная настройка сервера Apache закончена.

Первичная настройка VirtualHost

Теперь необходимо настроить VirtualHost, но пока на обычный http, или же 80 порт. Добавляем в конфиг httpd.conf секцию

<VirtualHost *:80>
ServerName your.dmn
ServerAlias www.your.dmn
DocumentRoot /path/to/domain/dir/
</VirtualHost>

DocumentRoot - место, где хранятся все файлы сайта (домена)

У меня все виртуальные хосты хранятся в отдельном каталоге в удобном месте. Поэтому я использую директиву в конфиге httpd.conf

# Virtual hosts
Include /MyDir/vhosts/*.conf

И все файлы виртуальных хостов имеют имена, что-то вроде mysite.ru.conf

В заметке я делаю все в файле httpd.conf, Вы можете использовать мой метод хранения, или все в один файл.

Проверяем конфигурацию

#> apachectl configtest

Если выдает

Performing sanity check on apache24 configuration:
Syntax OK

Значит Вы все настроии верно, иначе - смотрим на ошибки. И я более чем уверен они будут =). Обычно это опечатки, не верно указаные пути, доступы к каталогам не верные, так же могут быть конфликты модулей. Всегда все по разному, поэтому возможно придется посидеть.

Но если все ОК, то перезапускаем сервер Apache

#> apachectl restart

Если директория пуста, создаим простой файл с не тривиальным содержимым

#> echo "true" > /path/to/domain/dir/index.html

Переходим на наш домен (http://your.dmn), и если видим "true" значит все настройки были успешны.

Получение сертификатов CertBot

О том, как работает certbot Вы прочтете в этих наших Интернетах. Ниже я описываю простейший прием получения сертификатов.

Нам необходимо получить сертификат на домен, в этот момент бот проведет верификацию поместив файлы в созданный общий каталог, если все успешно то сертификаты будут помещены в директорию сертификатов.

#> certbot certonly -w /path/to/dir/cert/ -d your.dmn -d www.your.dmn

Из этого следует

certonly - только получить сертификат
-w - указан путь к нашей общей директории
-d - доменные имена, на которые будут получен сертификат. Их можно сделать до 5 за раз. Они не разделяются пробелом, и перед каждым необходимо ставить ключ -d

В момент получения он спросит Ваш E-mail (укажите действеный, спама не будет но будут напоминалки о продлении), спросит кучу разрешений, без которых Вы не получите сертификат. Так же задаст вопрос, как получить сертификат. Указываем, что поместить в webroot, это и есть наш указанный путь в -w.

В последствии Вам придет E-mail для подтверждения электронной почты.

Далее certbot помещает в директори указанную в -w временные файлы для аутентификации. Из-вне перейдет по ссылке, которая состоит из указанных доменов (поочередно на каждый указанный) и проверит наличие временных файлов. Таким образом произойдет верификации. Если все успешно сделано, будет выдано сообщение с поздравлением и файлы сертификата будут помещены в директорию

/usr/local/etc/letsencrypt/live/

Посмотрим, какой каталог был создан в данной директории. Обычно он имеет имя тоже, что указан в -d. Однако есть нюанс: если мы перечисляем домены, то сертификат на все домены будет один, и какой каталог будет создан не всегда ясен. По логике - первый указанный. Но у меня бывало так, что тот который содержал www. Поэтому посмотрим какой каталог создан:

#> ls -lah /usr/local/etc/letsencrypt/live/
drwx------  3 root  wheel     4B Apr 14 11:07 .
drwxr-xr-x  9 root  wheel    11B Apr 14 11:48 ..
-rw-r--r--  1 root  wheel   740B Apr 14 11:07 README
drwxr-xr-x  2 root  wheel     7B Apr 14 11:07 your.dmn

Видим, что создался каталог your.dmn. Он нам и нужен. Переходим вновь к виртуальному хосту

Настройка SSL-сертификата в Apache

Открываем файл конфига. Если Вы настроили виртуальные хосты отдельно от файла конфига, то открывайте именно файл с виртуальным хостом.

#> ee /usr/local/etc/apache24/httpd.conf

Находим нашу секцию

<VirtualHost *:80>
ServerName your.dmn
ServerAlias www.your.dmn
DocumentRoot /path/to/domain/dir/
</VirtualHost>

И пока в ней ничего не меняем. Добавляем новую секцию снизу

<VirtualHost *:443>
ServerName your.dmn:443
ServerAlias www.your.dmn
DocumentRoot /path/to/domain/dir/

SSLEngine on
SSLCertificateFile "/usr/local/etc/letsencrypt/live/your.dmn/cert.pem"
SSLCertificateKeyFile "/usr/local/etc/letsencrypt/live/your.dmn/privkey.pem"
SSLCertificateChainFile "/usr/local/etc/letsencrypt/live/your.dmn/chain.pem"

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>

<Directory "/usr/local/www/apache24/cgi-bin">
SSLOptions +StdEnvVars
</Directory>

BrowserMatch "MSIE [2-5]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
</VirtualHost>

Обратите внимание на две директивы

ServerName your.dmn:443
ServerAlias www.your.dmn

ServerName - обязательно должен содержать в название номер порта :443.
ServerAlias - алиасы НЕ ДОЛЖНЫ содержать 443 порт в названии.

Я не мало часов потратил выясняя разного рода глюки, то открывается сайт, то нет, здесь работает, там нет. Методом анализа и каких-то примеров из интернета я это выяснил.

SSLCertificateFile, SSLCertificateKeyFile, SSLCertificateChainFile - содержат полный путь к сертификатам. Проверить правильность путей всегда можно так:

#> ls -lah /usr/local/etc/letsencrypt/live/your.dmn/chain.pem
lrwxr-xr-x  1 root  wheel    43B Apr 14 11:07 /usr/local/etc/letsencrypt/live/your.dmn/chain.pem -> ../../archive/your.dmn/chain1.pem

Если показало, что все найдено, то путь Вы указали верно.

Выходим, сохраняемся.

Проверяем, перезагружаем сервер Apache

#> apachectl configtest
#> apachectl restart

Переходим теперь уже по безопасному протоколу, https://your.dmn. Если отобразит "true", поздравляю, Вы успешно установили сертификат.

Переадресация с http на https

Ну, а теперь по желанию настроим переадресацию с http на https. По факту надо сделать переадресацию с 80 на 443 порт .

Открываем конфиг-файл где указан наш виртаульный хост и приводим его к следующему виду

<VirtualHost *:80>
ServerName your.dmn
ServerAlias www.your.dmn
DocumentRoot /path/to/domain/dir/
RedirectMatch 301 (.*) https://your.dmn$1
</VirtualHost>

Как обычно выходим-сохраняемся, тестируем-перезапускаем.

#> apachectl configtest
#> apachectl restart

Теперь при обращении к http://your.dmn и http://www.your.dmn будет автоматически переадресовываться на https://your.dmn

В данной конфигурации я с оба домена переадресовываю на один, который я выбрал в качестве основного. Что бы переадресовывать на домен, по которому был переход, то просто разделите на две секции

<VirtualHost *:80>
ServerName your.dmn
DocumentRoot /path/to/domain/dir/
RedirectMatch 301 (.*) https://your.dmn$1
</VirtualHost>

<VirtualHost *:80>
ServerName www.your.dmn
DocumentRoot /path/to/domain/dir/
RedirectMatch 301 (.*) https://www.your.dmn$1
</VirtualHost>

При этом виртуальный хост на 443 порте перенастраивать не нужно. НО, это при условии, что выдаваемая информация одинакова. Если же она должна быть разной, то и его так же необходимо разделить на две части

Массовое получение сертификатов

Для массового получения сертификатов я, как это и принято, использую написанный скрипт. Я использую bash, его Вы можете установить из пакетов самостоятельно. Ну или использовать обычный sh, это не принципиально.

Скрипт:

#!/usr/bin/env bash

/usr/local/bin/certbot certonly -w /path/to/dir/cert -d domain0.dmn -d www.domain0.dmn
/usr/local/bin/certbot certonly -w /path/to/dir/cert -d domain1.dmn -d www.domain1.dmn
/usr/local/bin/certbot certonly -w /path/to/dir/cert -d sub1.domain0.dmn
/usr/local/bin/certbot certonly -w /path/to/dir/cert -d sub2.domain0.dmn
/usr/local/bin/certbot certonly -w /path/to/dir/cert -d sub0.domain1.dmn -d sub1.domain1.dmn -d sub2.domain1.dmn -d sub3.domain1.dmn

Варианты скрипта можно использовать по своему усмотрению. Можно даже написать цикл, который подгружает из файла все домены. Но это уже извращение для особо продвинутых.

Вновь обратим внимание на -w - у всех он ОДИНАКОВ. Сервер настроен таким образом, что файлы аутентификации с уникальным именем складываются в одно место, и из него же отображается когда бот проводит аутентификацию.

Выходим-сохраняем, назначаем доступы и запускаем

#> chmod u+x getCertBot
#> ./getCertBot

Где getCertBot это имя файла скрипта. У Вас оно может быть любым другим.

Помните, он запросит на каждую строку (строку, не домен!) E-mail и кучу других вопросов.

Но этот скрипт необходим для получения новых сертификатов, для обновления уже имеющихся используется другая команда

Автоматическое обновление сертификатов в Apache

И-так, мы все настроили, все работает штатно. Теперь подумаем об обновлении сертификатов.

Для обновления сертификатов существует следующая команда:

#> certbot renew

Вы можете ее в любой момент запустить, если время обновления не подошло, то Вам будет выдано уведомление о том, что еще рано.

Но если сертификат обновился, то нам достаточно просто перезапустить сервер

#> apachectl restart

Вообще, у команды certbot есть параметр --post-hook, в котором можно указать, что сделать после выполнения команды

#> certbot renew --post-hook "apachectl restart"

Но я ее не очень люблю, т.к. апачи выдает что все ОК, а вот certbot думает что это ошибка. Это никак не влияет ни на что, но сообщения раздражают. Поэтому я не использую этот параметр.

С командами разобрались, с порядком запуска тоже. Давайте запустим автоматику. Обновлять будем в час ночи, в понедельник, раз в две недели, от пользователя root

В начале создаем скрипт

#!/usr/bin/env bash

/usr/local/bin/certbot renew
/usr/local/sbin/apachectl restart

Обязательно указывать полный путь к приложениям! Cron не будет отрабатывать, если пути будут не полные, и ругнется, что нет такой команды.

Узнать полный путь можно введя "which команда"

#> which certbot
/usr/local/bin/certbot

Вышли-сохранились, назначили доступы

#> chmod u+x getCertBotRenew

Где getCertBotRenew это имя файла скрипта. Вы можете назвать свой по усмотрению.

Настраиваем крон

#> crontab -e

Вписываем туда строку

5 1 1 */2 * root /path/to/script/getCertBotRenew

Где

5 - минута
1 - час
1 - день недели
*/2 - раз в две недели
root - от имени пользователя, без root не получится
/path/to/script/getCertBotRenew - полный путь к скрипту

Выходим-сохраняемся.

И теперь раз в две недели будут обновлятся все сертификаты и одновременно с этим перезагружать сервер Apache.

Добавление сертификата на новый домен

И-так сервер настроен и давно работает. Необходимо добавить сертификат на другой домен или новый.

Все достаточно просто

1. Создать/отредактировать виртуальные хосты на 80й порт как описано выше но без переадресации
2. Перезапустить сервер Apache
2. Получить сертификаты
3. Настроить виртуальный хост на https
4. Перезапустить сервер Apache
5. Если все ОК, настроить переадресацию и перезапустить сервер Apache

Все. Более ничего не требуется. Все остальное будет работать автоматически.

Ошибки, с которыми я сталкивался

Как я описал выше, я подгружаю виртуальные хосты из отдельной директории. Но помимо этого, есть у Apache "баг" - если обратится к серверу с использованием домена, который не указан в настройках сервера, то автоматически подгрузится тот виртуальный хост, что был подгружен первым. Поэтому у меня есть виртуальный хост с названием файла

0.conf

В нем прописана директива

<VirtualHost *:80>
DocumentRoot /dev/null
</VirtualHost>

И при открытии таких доменов, автоматически выдается не существующая страница (ошибка).

Точно так же я решил прописать и для 443 порта, дописав ниже

<VirtualHost *:443>
DocumentRoot /dev/null
</VirtualHost>

И обращение по 443 порту сразу перестало работать.

После удаления секции 443 сервер успешно заработал.

Поэтому если Вам выдает не понятную ошибку, которая ни к селу ни к городу, как говориться, то сразу проверяйте какие секции используют 443 порт.

Так же, самая частая проблема, это момент генерации.

Перед получением убедитесь, что пути прописаны верно. Так же самостоятельно через ссылку на сайт откройте каталоги, например создайте 1.txt в директории временных файлов, и откройте по ссылке

http://your.dmn/.well-known/acme-challenge/1.txt

Если все верно, то отобразит содержимое файла (или пустоту), но без ошибок. Таким образом проверяется настройка Apache на домен.

Так же сразу проверяем наличие пути к директории или файлу в системе

#> ls -lah /path/to/dir/cert/.well-known/acme-challenge/1.txt

Если выдает информацию по файлу, то все ОК.

Ну и конечно доступы к файлам в настройках конфигов. Или какие-то уникальные доступы через chmod.

Помните, у certbot есть ограничение запросов в час при не удачной аутентификации. Поэтому если Вы исчерпали лимит, то попробуйте позднее или с другими доменами. Ограничение вводится на конкретные домены указанные в строке.

Есть у меня и скрытые домены, которые защищены на уровне Apache паролем. Естественно внешний бот не сможет обратиться к папке с файлами аутентификации при создании или обновлении сертификатов. Поэтому я частенько забываю на время обновления снять защиту. И естественно бот ругается, что не может получить доступ.

Ну и еще раз - опечатки, опечатки и кривые руки. Проверяйте, сравнивайте, исправляйте.

Настройка сертификатов для доменнов расположенных внутри сети

Сразу оговорюсь, если домен не прописан во вне, то ничего не получится. Бот не сможет зайти на сайт mySite.local, т.к. он бьет из внешней сети, и о Вас естественно даже не в курсе. Но если основной домен существует, то можно проделать маленькую хитрость.

Имеем myDomain.dmn, который доступен из любой точки мира. По сути, конкретно он не так важен, об этом позднее.

Внутри сети есть поддомены, которые ведут на внутренние IP адреса, и которые не прописаны в настройках myDomain.dmn, однако поддомены прописаны во внутренних DNS.

buh.myDomain.dmn 192.168.1.100
gen.myDomain.dmn 192.168.1.101
admins.myDomain.dmn 192.168.1.102
portal.myDomain.dmn 192.168.1.103

Как видно из примера, войти на сайте извне невозможно. Докучи еще и сетка сама по себе закрытая. Но способ есть, и достаточно безопасный.

Во первых создаем поддомены на самом домене myDomain.dmn в месте, где он расположен во внешней сети. Условимся, что все они ведут на один хостинг. Условимся, что хостинг UNIX с SSH.

Настраиваем сервер UNIX по примеру выше:

1. Создаем директорию, где будут хранится все файлы аутентификации
2. Настраиваем доступ к директории
3. Настраиваем алиас на директорию (.well-known)
4. Проверяем доступ к данным директориям по всем доменам

Теперь у нас есть все домены, которые во внешке. Можно поместить туда пустой index.html, что бы при обращению к ним выдавало пустую страницу. Бот certbot будет обращаться к данным доменным именам и бить в указанные выше директории, тем самым получать файл аутентификации не касаясь внутренней сети.

Теперь настраиваем внутренний сервер. Шаги теже самые, один к одному, с небольшим уточнением. Мы должны присоединить внешний созданный каталог к нашему внутреннему, где хранятся все файлы аутентификации.

#> sshfs -o allow_other,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 user@myDomain.dmn:/path/to/fileDirOuter/ /path/to/fileDirInner/

Команда sshfs позволяет примонтировать удаленный каталог в указанный. И все файлы, которые вы скопируете в этот каталог автоматически будут загружены на сервер. Тоже самое случится, если файл появится на сервере, он автоматически отобразится в каталоге.

user@myDomain.dmn:/path/to/fileDirOuter/ - сервер и путь к указанному каталогу, куда будут помещены файлы аутентификации
/path/to/fileDirInner/ - локальный каталог, куда certbot сложит файлы аутентификации в момент генерации сертификаты. В данном случае certbot это приложение на Вашем внутреннем сервере.

После чего можете на внутреннем сервере запускать certbot. Получится следующее

1. Внутренний certbot сгенерирует файлы аутентификации на внутреннем сервере
2. Разместит их в директории /path/to/fileDirInner/
3. sshfs отправит эти файлы в user@myDomain.dmn:/path/to/fileDirOuter/
4. Внешний бот certbot будет заходить на домены указаные в директивах -d
5. Внешний сервер будет отдавать их из директории /path/to/fileDirOuter/
6. После чего произойдет верификация
7. Внутренний certbot получит от внешнего файлы сертификации. Внутренний сам создает соединение с внешним, а не наоборот.
8. Поместит на внутреннем сервере файлы в нужные директории

После чего остается перезапустить сервер Apache на внутреннем сервере.

Во внешку сертификаты не попадают, т.к. внешние домены нужны только для аутентификации и настраивать их на https нет необходимости.

Внутренние домены полностью становятся защищенными. Они самостоятельно проверяют сертификат, а елси быть точнее браузер пользователя проверяет сертификат.

Тем самым все сертификаты получены и хранятся во внутренней сети. Доступ к внутренним доменам извне нет. Внешние домены работают со своим сервером, где не расположены данные из внутренней (кроме файлов аутентификации).

Если у Вас нет возможности использовать SSH, тогда, конечно, сложнее. Придется вместо общей папки использовать уникальные и монтировать их через FTP. Но это не проблема. Необходимо будет создать под каждый домен свой каталог для файлов аутентификации.

И при использовании такой схемы, на внутреннем сервере нет необходимости настраивать Apache на доступ к директории где хранятся файлы аутентификации. Просто потому, что это необходимо делать на внешнем сервере. Файлы будут помещены внутренним certbot'ом без обращения к внутреннему серверу Apache.

И по сути, сам домен myDomain.dmn. Поддомены могут вполне работать и без основного домена, т.к. в настройках DNS все домены и поддомены прописываются отдельно. И домен myDomain.dmn можно таким образом просто отключить. Поддомены будут работать в штатном режиме.

Ну вот собственно и все. Надеюсь информация поможет Вам настроить HTTPS и облегичт работу с ним.