Размещаем HUGO сайт в интернете

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

· 12 минуты на чтение
Размещаем HUGO сайт в интернете

В прошлой статье, мы научились создавать сайт используя Hugo. Проблема в том, что наш сайт пока живет только локально в нашем ПК. Как сделать так, чтобы он стал доступен другим пользователям интернета? Давайте разбираться.

Публиковать можно двумя способами. Самый простой – это использовать специальный сервис. Способ посложнее – это арендовать сервер и настроить на нем Nginx. Мы рассмотрим оба способа.

Простой путь подойдет вам, если вы не планируете устанавливать что-то еще. Например, можно установить свои комментарии или счетчик просмотров.

Спонсор поста

GitLab

Какой бы вы путь не выбрали, вам необходимо сначала зарегистрироваться в GitLab. После регистрации создайте приватный проект.

Теперь у вас есть путь до git репозитория: https://gitlab.com/uPagge/mymeagesite.git

Путь до репозитория гитлаб

Помните, мы использовали git в нашем проекте. Давайте добавим удаленный репозиторий, который мы только что создали. Для этого зайдите в папку вашего сайта и выполните следующую команду:

git remote add origin git@gitlab.com:uPagge/mymeagesite.git

Тем самым вы связали свой локальный git-репозиторий с удаленным на GitLab.

Как сделать коммит в Git
Отвечаю на вопросы: как сделать коммит, создать новую ветку, вмержить одну ветку в другую.
Подробнее о git можно прочитать здесь ☝️

Теперь необходимо отправить ваш проект в GitLab. Для этого следом выполните команду:

git push --set-upstream origin master

Подсчет объектов: 5, готово.
Delta compression using up to 4 threads.
Сжатие объектов: 100% (4/4), готово.
Запись объектов: 100% (5/5), 969 bytes | 969.00 KiB/s, готово.
Total 5 (delta 0), reused 0 (delta 0)
To gitlab.com:uPagge/mymeagesite.git
* [new branch]      master -> master
  Ветка «master» отслеживает внешнюю ветку «master» из «origin».

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

Публикация через Netlify

Этот вариант подойдет вам, если вы не планируете самостоятельно устанавливать дополнительные сервисы для вашего блога.

Зарегистрируйтесь в Netlify, после чего нажмите кнопку “New Site from Git”.

Выбирайте GitLab.

Выбирайте ваш репозиторий в GitLab.

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

Нажимаем “Deploy to Site” и немного ждем. В результате мы получаем наш сайт в интернете. Открываем выданный нам адрес и…

Воу, что случилось. Все дело в том, что мы до этого момента не знали, какой домен будет у нашего сайта. И поэтому у нас в config.toml указан следующий параметр: baseURL = "https://example.com/".

Из-за этого у нас неправильно указаны пути к стилям CSS.

Исправим это указав в config.toml наш домен. После изменения домена необходимо отправить изменения в удаленный репозиторий. Для этого выполните команду:

git commit -m "commit_message"
git push origin master

И все, netlify сам обнаружит изменения и выполнит сборку и повторную публикацию вашего сайта.

Снова открываем наш сайт.

Успешное отображение сайта в интернете
Домен

Домен вида nostalgic-goldstine-67b600.netlify.app выглядит не очень красиво, да и запоминается сложно.

Вы можете купить свой красивый домен и привязать его в netlify.

Рандомный блок

Публикация сайта на VPS

Итак, простой путь это не про вас. Вы хотите больше контроля, тогда арендуйте VPS. Я постарался максимально облегчить вам жизнь, своей инструкцией.

Генерация сайта будет происходить на стороне GitLab, на сервер будет попадать только сгенерированный сайт, то есть папка public.

Первом делом арендуйте VPS, его также называют VDS. Вы можете выбрать любой, моя рекомендация это VDSina.

⚠️
Все примеры выполняются на сервере CentOS 8. В зависимости от дистрибутива команды могут отличаться.

Подключаемся к нашему серверу через консоль linux или Putty для windows.

ssh root@188.225.43.153

The authenticity of host '188.225.43.153 (188.225.43.153)' can't be established.
ECDSA key fingerprint is SHA256:sVi8p6f+3pvWbJv/u4rzv5RtUTMcrhCTI9yzVkCXoSI.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '188.225.43.153' (ECDSA) to the list of known hosts.

root@188.225.43.153's password:

Activate the web console with: systemctl enable --now cockpit.socket

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

yum update && yum upgrade

Создаем нового пользователя

Создадим нового пользователя и все действия будем делать от его имени.

Команды для CentOS 8, для других дистрибутивов могут быть другие команды.

useradd upagge
passwd upagge

Changing password for user upagge.

New password:
Retype new password:

passwd: all authentication tokens updated successfully.

usermod -aG wheel upagge
exit

Проверьте авторизацию через нового пользователя:

ssh upagge@188.225.43.153
Гайд по защите Linux сервера от взлома
Базовая защита от взлома вашего linux сервера. Запрет входа для root пользователя, смена стандартного порта и другие способы защиты.

Создаем ключи для сервера

Как я уже говорил, мы будем генерировать сайт на стороне GitLab. Для этого нам необходимо будет настроить доставку папки public на сервер, с помощью GitLab CI.

Чтобы GitLab CI имел возможность войти на наш сервер, надо сгенерировать SSL ключи.

Команда для генерации:

ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key (/home/user_name/.ssh/id_rsa): /home/user_name/.ssh/megasite
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user_name/.ssh/megasite.
Your public key has been saved in /home/user_name/.ssh/megasite.pub.
The key fingerprint is:
SHA256:QjNqmEYk1ncTZcTQyUyM8m+Y2R2txOQCV65Xc08F0Mo user_name@localhost
The key's randomart image is:
+---[RSA 2048]----+
|..o    o&=o..o...|
|.o . o =.O..  . .|
|  . . B + +o.+ ..|
| . o o + ..=E.o..|
|  + o . S.+.o   .|
| . .   = +.o     |
|        .        |
|                 |
|                 |
+----[SHA256]-----+

Не устанавливайте пароль на ключ. Имя ключа можете оставить по умолчанию id_rsa, так как у меня уже есть главный ключ id_rsa, и я не хотел его затирать, я задал новое имя megasite.

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

ssh-copy-id -i ~/.ssh/megasite.pub upagge@188.225.43.153

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user_name/.ssh/megasite.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
upagge@188.225.43.153's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'upagge@188.225.43.153'"
and check to make sure that only the key(s) you wanted were added.

Теперь вы можете зайти на свой сервер через ssh ключ без пароля, но главное, что это сможет сделать GitLab.

ssh upagge@188.225.43.153
🧐

Настройка GitLab CI/CD

GitLab CI позволит нам генерировать сайт и отправлять его к нам на сервер.

Создайте файл в корне проекта с названием .gitlab-ci.yml:

image: upagge/hugo-builder:latest

build:
  variables:
    GIT_SUBMODULE_STRATEGY: recursive
  only:
    - master
  before_script:
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -p $PORT $HOST >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  script:
    - hugo --minify
    - tar -zcf public.tar.gz ./public
    - scp -C -P $PORT -r ./public.tar.gz $USER@$HOST:$SITE_PATH/
    - ssh $USER@$HOST -p $PORT "rm -rf $SITE_PATH/public/*"
    - ssh $USER@$HOST -p $PORT "cd $SITE_PATH && tar -xf public.tar.gz && rm public.tar.gz"

Перед коммитом и пушем в GitLab необходимо добавить переменные GitLab CI: Settings -> CI/CD -> Variables

  • SSH_PRIVATE_KEY - ваш приватный SSH ключ.

Получить его можно командой cat /path_to_private_key. Пример:

cat ~/.ssh/megasite

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1YEoaZk4EfJCS3f3uq85alhztxVDZ9nG96kOQ8eriud2pamQ
dtl+CO0UOFrytzn2miud2dLx2NUr35Qixto4yw6slGpWMU51wqm3JOYELtKXYfjv
SkY1v...
-----END RSA PRIVATE KEY-----

Скопируйте весь ответ команды.

  • USER - пользователь на сервер. В нашем случае upagge.
  • HOST - IP адрес сервера.
  • PORT - порт для подключения. Если вы его не меняли, то 22.
  • SITE_PATH - путь до папки, в которую GitLab поместит public. В моем случае /home/upagge/

Весь блок before_script отвечает за настройку SSH авторизации.

Разберем построчно блок script:

  • Строка 16 генерирует сайт.
  • Строка 17 создает архив из папки public. Таким образом сайт быстрее загрузится на сервер.
  • Строка 18 загружает архив на сервер в папку SITE_PATH.
  • Строка 19 удаляет старую папку public на сервере.
  • Строка 20 распаковывает архив и удаляет сам архив.

Если вы добавили тему для Hugo в качестве git-submodule, то GIT_SUBMODULE_STRATEGY: recursive загрузит тему за вас.

Настройка GitLab CI CD для Java приложения
На примере Java приложения рассматриваем сборку и деплой на сервер с помощью GitLab CI.

После добавления переменных выполняем команды commit и push.

git add .gitlab-ci.yml
git commit -m 'gitlab ci'
git push

Заходим в проект на GitLab в раздел Pipelines и видим, что все прошло успешно.

Успешный CI/CD

Заходим на сервер и проверяем, что папка public появилась и не пустая:

ls
public
ls public/
404.html                article  categories  en     index.html  index.xml            page        series       tags       theme.js
algolia-logo-light.svg  author   de          fonts  index.json  modernizr-simple.js  robots.txt  sitemap.xml  theme.css  theme.js.LICENSE.txt

Отлично. Теперь при каждом изменений ветки master наш сайт будет автоматически обновляться на сервере.

Установка docker и docker-compose

Файлы сайта уже у нас на сервере. Чтобы к ним был доступ из интернета, нам нужен Nginx.

Для установки Nginx будем использовать docker и docker-compose. Это необходимо, чтобы в дальнейшем бесплатно получить https для нашего сайта.

У меня есть отдельная заметка с командами для установки docker и docker-compose на CentOS 8. Можете просто копировать команды оттуда.

Настройка записей DNS

Для сайта необходимо доменное имя. Рекомендую REG.RU.

После покупки домена не забудьте добавить ресурсную запись DNS:

  • Тип записи: A
  • Subdomain: @
  • IP Address: ip адрес вашего сервера

И еще одну запись для www:

  • Тип записи: A
  • Subdomain: www
  • IP Address: ip адрес вашего сервера

После добавления записи нужно подождать, пока DNS сервер их обновит. В зависимости от DNS регистратора обновление может занимать от 15 минут до 24 часов. На REG.RU это занимает от 15 до 30 минут.

Настройка конфигурации Nginx

Создадим папку nginx в папке пользователя. Так, чтобы папка public лежала рядом.

mkdir nginx

Теперь заполняем конфигурацию. Замените название домена, если домена пока нет, можно использовать IP сервера. Все что надо заменить выделено желтым.

nano nginx/mysite.conf
server {

        listen 80;
        listen [::]:80;

        root /public;
        index index.html;

        server_name domain_name.com www.domain_name.com;

        location / {
               try_files $uri $uri/ =404;
        }

}

Обратите внимание, что nginx у нас будет работать в контейнере. Поэтому root /public это путь до папки в контейнере.

Создание файла Docker Compose

Создадим файл docker-compose.yml рядом с папкой nginx и public.

nano docker-compose.yml
version: '3'

services:
  nginx:
    image: nginx
    container_name: nginx
    hostname: nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./public:/public:ro
      - ./nginx/mysite.conf:/etc/nginx/conf.d/mysite.conf

Обратите внимание на строки 12 и 13. Так задаются относительные пути до папок, если рядом с файлом не будет папок public и nginx, то ничего не заработает.

Запускаем командой:

sudo docker-compose up -d
[sudo] password for upagge:

Creating network "upagge_default" with the default driver
Pulling nginx (nginx:)...
latest: Pulling from library/nginx
f7ec5a41d630: Pull complete
aa1efa14b3bf: Pull complete
b78b95af9b17: Pull complete
c7d6bca2b8dc: Pull complete
cf16cd8e71e0: Pull complete
0241c68333ef: Pull complete
Digest: sha256:75a55d33ecc73c2a242450a9f1cc858499d468f077ea942867e662c247b5e412
Status: Downloaded newer image for nginx:latest
Creating nginx ... done

Проверяем, что контейнер успешно запустился командой ps:

sudo docker-compose ps

Name               Command               State                Ports
---------------------------------------------------------------------------------
nginx   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:80->80/tcp,:::80->80/tcp

Если у вас другой вывод, то проверьте логи командой:

sudo docker-compose logs nginx

Attaching to nginx
nginx    | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx    | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx    | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx    | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx    | /docker-entrypoint.sh: Configuration complete; ready for start up

Настройка брандмауэра

По умолчанию на CentOS 8 может быть включен брандмауэр, чаще всего это firewalld.

Если nginx установлен правильно и брандмауэра нет, то по адресу http://ваш_домен должен открыться ваш сайт.

Обратите внимание, по http, а не по https. Часто браузеры втихую подставляют https.

Если страница не открывается, то необходимо открыть порт 80 для nginx. Запустите следующую команду, чтобы на постоянной основе активировать соединения HTTP для порта 80:

sudo firewall-cmd --permanent --add-service=http

Для применения изменений вам необходимо перезагрузить службу брандмауэра:

sudo firewall-cmd --reload

Теперь сайт должен открываться.

Настраиваем https

У нас статический сайт и https нам в принципе не нужен. Однако, поисковики лояльнее относятся к сайтам доступным по https, да и пользователи уже не доверяют сайтам по http.

Настройка Nginx

Теперь нам нужно изменить конфигурацию nginx. Добавьте строки 14-17. Они нужны для получения сертификата.

server {
        listen 80;
        listen [::]:80;

        root /public;
        index index.html;

        server_name test.upagge.ru www.test.upagge.ru;

        location / {
               try_files $uri $uri/ =404;
        }

	    location ~ /.well-known/acme-challenge {
                allow all;
                root /public;
        }

}

Настройка certbot

Также необходимо добавить в docker-compose.yaml сервис certbot:

version: '3'

services:
  nginx:
    image: nginx
    container_name: nginx
    hostname: nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./public:/public:ro
      - ./nginx:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - ./public:/var/www/html
    depends_on:
      - nginx
    command: certonly --webroot -w /var/www/html --email you@email.ru --agree-tos --no-eff-email --staging -d domain_name.com -d www.domain_name.com
volumes:
certbot-etc:
certbot-var:

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

sudo docker-compose up -d

Creating volume "upagge_certbot-etc" with default driver
Creating volume "upagge_certbot-var" with default driver
Pulling certbot (certbot/certbot:)...
latest: Pulling from certbot/certbot
339de151aab4: Pull complete
a860e27ad689: Pull complete
910a9a405b4b: Pull complete
bde2ad12a253: Pull complete
584dc3c8e951: Pull complete
ee0b6a5fc80b: Pull complete
3441ac9951cc: Pull complete
4665ef123f62: Pull complete
5bedd499466f: Pull complete
dec3eef9e94a: Pull complete
4f1c29d810f9: Pull complete
5eb6418594da: Pull complete
5da8c5eff620: Pull complete
Digest: sha256:c62b7ca0d8a064a9a260ee331adbe25abb1802ed104abe85a3e02062bbcf9d60
Status: Downloaded newer image for certbot/certbot:latest
Recreating nginx ... done
Creating certbot ... done

Проверяем, что все прошло успешно

sudo docker-compose ps

 Name                Command               State                 Ports
------------------------------------------------------------------------------------
certbot   certbot certonly --webroot ...   Exit 0
nginx     /docker-entrypoint.sh ngin ...   Up       0.0.0.0:80->80/tcp,:::80->80/tcp

Если ваш вывод отличается, проверьте логи. Как проверять nginx вы уже знаете, для certbot аналогичная команда:

sudo docker-compose logs nginx

Успешный запуск выглядит примерно так.

certbot    | Cleaning up challenges
certbot    | IMPORTANT NOTES:
certbot    |  - Congratulations! Your certificate and chain have been saved at:
certbot    |    /etc/letsencrypt/live/test.upagge.ru/fullchain.pem
certbot    |    Your key file has been saved at:
certbot    |    /etc/letsencrypt/live/test.upagge.ru/privkey.pem
certbot    |    Your certificate will expire on 2021-08-07. To obtain a new or
certbot    |    tweaked version of this certificate in the future, simply run
certbot    |    certbot again. To non-interactively renew *all* of your
certbot    |    certificates, run "certbot renew"
certbot exited with code 0

LetEncrypt имеет ограничения на количество запросов, поэтому мы запускали его в тестовом режиме. Теперь, когда вы убедились, что ваш запрос будет выполнен успешно, вы можете изменить определение службы certbot для удаления флага --staging.

Найдите раздел файла с определением службы certbot и замените флаг --staging в параметрах command на флаг --force-renewal, который будет указывать Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и в уже существующем сертификате. Определение службы certbot должно выглядеть следующим образом:

...

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - ./public:/var/www/html
    depends_on:
      - nginx
    command: certonly --webroot -w /var/www/html --email you@email.ru --agree-tos --no-eff-email --force-renewal -d domain_name.com -d www.domain_name.com

...

Снова запускаем docker-compose, чтобы получить рабочие сертификаты:

sudo docker-compose up -d

После получения сертификатов вы можете перейти к изменению конфигурации Nginx для использования SSL.

Активация SSL в нашей конфигурации Nginx будет подразумевать добавление перенаправления HTTP на HTTPS и указание расположения сертификата и ключей SSL. Также нам нужно будет указать нашу группу Diffie-Hellman, которую мы будем использовать для Совершенной прямой секретности.

Поскольку вы будете воссоздавать службу nginx для включения этих нововведений, сейчас вы можете остановить ее работу:

sudo docker-compose stop nginx

Создание ключа Diffie-Hellman

Далее создадим ключ Diffie-Hellman:

sudo openssl dhparam -out ./nginx/dhparam-2048.pem 2048

Процесс генерации ключа может занять несколько минут.

Изменяем Nginx

Чтобы добавить данные о Diffie-Hellman и SSL в конфигурацию Nginx, первым делом удалите ранее созданный файл конфигурации Nginx:

rm nginx/mysite.conf

Создадим новую версию файла. Обязательно замените test.upagge.ru на ваше доменное имя:

nano nginx/mysite.conf
server {
    listen 80;
    listen [::]:80;
    server_name test.upagge.ru www.test.upagge.ru;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /public;
    }

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }

}

server {

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name test.upagge.ru www.test.upagge.ru;

    root /public;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/test.upagge.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.upagge.ru/privkey.pem;

    ssl_dhparam /etc/nginx/ssl/dhparam-2048.pem;

    ssl_buffer_size 8k;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;

    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl_ecdh_curve secp384r1;
    ssl_session_tickets off;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;

    location / {
        try_files $uri $uri/ =404;
    }

}

Резюмирую

Мы разобрались, какими способами можно опубликовать свой Hugo сайт в интернете. Публикация через Netfly подойдет, если вы не планируете разворачивать какие-нибудь дополнительные сервисы для вашего сайта, в этом случае лучше выбрать VPS.

Struchkov Mark
Struchkov Mark
Задавайте вопросы, если что-то осталось не понятным👇