Добавить в корзинуПозвонить
Найти в Дзене
КББ

Хостинг Hugo-блога на S3 Timeweb

Долгое время мой блог жил на VDS — nginx, certbot, systemd-сервисы, бекапы, короче полноценный сервер. В какой-то момент стало лень следить за ещё одной машиной и особенно меня подтолкнули проблемы с разными хостингами и я решил переехать на статический S3-хостинг. Пост про то — как я переехал, с какими граблями столкнулся и что в итоге получилось. Почему именно Timeweb, а не Яндекс Облако или Selectel? Тут всё просто: у меня уже были там аккаунты, а S3 у них стоит копейки. Для статики — идеально. Из коробки Timeweb S3 умеет раздавать статический сайт, выдаёт URL вида `*.website.twcstorage.ru`, поддерживает кастомные заголовки и политики. Что нужно - Аккаунт в Timeweb (уже был) - Hugo - Репозиторий блога на GitHub (уже был) - Домен (уже был) 1. Заходим в панель Timeweb → S3 → Создать бакет 2. Выбираем регион, имя бакета 3. После создания открываем бакет → Настройки → Хостинг статического сайта → Включаем 4. Получаем URL: `https://<id>.website.twcstorage.ru` Шаг 2: S3-ключи В панели Tim
Оглавление

Долгое время мой блог жил на VDS — nginx, certbot, systemd-сервисы, бекапы, короче полноценный сервер. В какой-то момент стало лень следить за ещё одной машиной и особенно меня подтолкнули проблемы с разными хостингами и я решил переехать на статический S3-хостинг.

Пост про то — как я переехал, с какими граблями столкнулся и что в итоге получилось.

Почему Timeweb S3

Почему именно Timeweb, а не Яндекс Облако или Selectel? Тут всё просто: у меня уже были там аккаунты, а S3 у них стоит копейки. Для статики — идеально.

Из коробки Timeweb S3 умеет раздавать статический сайт, выдаёт URL вида `*.website.twcstorage.ru`, поддерживает кастомные заголовки и политики.

Что нужно

- Аккаунт в Timeweb (уже был)

- Hugo

- Репозиторий блога на GitHub (уже был)

- Домен (уже был)

Шаг 1: Создание бакета

1. Заходим в панель Timeweb → S3 → Создать бакет

2. Выбираем регион, имя бакета

3. После создания открываем бакет → Настройки → Хостинг статического сайта → Включаем

4. Получаем URL: `https://<id>.website.twcstorage.ru`

Шаг 2: S3-ключи

В панели Timeweb идём в сервисные аккаунты → создаём ключ с доступом к бакету (на запись и чтение). Нам понадобятся:

- `AWS_ACCESS_KEY_ID`

- `AWS_SECRET_ACCESS_KEY`

- `AWS_ENDPOINT_URL` — `https://s3.twcstorage.ru`

- И имя бакета

Шаг 3: GitHub Actions

Деплой настроил через GitHub Actions. Workflow выглядит так:

name: Deploy blog to S3

on:

push:

branches: [main]

jobs:

build-and-deploy:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: peaceiris/actions-hugo@v3

with:

extended: true

- run: hugo --gc

- uses: jakejarvis/s3-sync-action@master

with:

args: --delete

env:

AWS_S3_BUCKET: ${{ secrets.AWS_BUCKET_NAME }}

AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}

AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

AWS_ENDPOINT_URL: ${{ secrets.AWS_ENDPOINT_URL }}

Секреты (`AWS_*`) храню в настройках репозитория GitHub — Settings → Secrets and variables → Actions.

Шаг 4: Деплой

Пушим в main:

git push origin main

GitHub Actions собирает сайт и синхронизирует с бакетом. Всё, сайт на S3, никаких ssh и ручных заливок.

Шаг 5: Домены (не так всё просто)

Настраиваем CNAME в DNS:

blog.tatarinovms.ru → s3.twcstorage.ru

blog.tatarinovms.space → s3.twcstorage.ru

Ждём, пока DNS обновится, открываем браузер... и получаем `AccessDenied`.

Подводный камень: кастомные домены у TimeWeb не работают:

Как оказалось, Timeweb S3 [не поддерживает кастомные домены](https://timeweb.cloud/docs/s3-storage/supported-features/static-websites#ogranicheniya). Вообще. Только их `*.website.twcstorage.ru`. На момент написания поста ответ поддержки это подтвердил.

Есть два пути:

Вариант 1: CloudFlare

Меняем NS на CloudFlare, он проксирует запросы на S3-эндпоинт и выдаёт свой SSL. VDS не нужен. Бесплатно. Но мы знаем как в некоторых регионах работает CloudFlare, скажем мягко - с перебоями.

Вариант 2: nginx reverse proxy

Пришла простая идея, так как есть в загашнике VDS, то мы ставим nginx на VDS, он проксирует кастомные домены на S3 URL. SSL через certbot. VDS всё равно есть под другие задачи. Конфиг nginx:

server {

listen 80 default_server;

server_name blog.tatarinovms.ru blog.tatarinovms.space;

return 301 https://$host$request_uri;

}

server {

listen 443 ssl http2;

server_name blog.tatarinovms.ru blog.tatarinovms.space;

ssl_certificate /etc/letsencrypt/live/blog.tatarinovms.space/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/blog.tatarinovms.space/privkey.pem;

location / {

proxy_pass https://id.website.twcstorage.ru;

proxy_ssl_verify off;

proxy_ssl_server_name on;

proxy_set_header Host id.website.twcstorage.ru;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto $scheme;

}

}

SSL получил через certbot:

certbot --nginx -d blog.tatarinovms.ru -d blog.tatarinovms.space

Итоговая схема

Пуш в main → GitHub Actions → Hugo build → aws s3 sync → S3 бакет → DNS: blog.tatarinovms.ru / blog.tatarinovms.space → A → VDS → nginx reverse proxy → S3 (*.website.twcstorage.ru)

При пуше в main GitHub Actions сам собирает Hugo и синхронизирует с S3 — nginx просто проксирует то, что уже лежит в бакете. Редеплой занимает меньше минуты.

Timeweb S3 как хостинг статики — отличное решение. Но с кастомными доменами придётся извернуться. Надеюсь, когда-нибудь они добавят эту возможность, но пока — nginx.