Hugo, Tor и Gemini

2021-12-01 · Nacht · hugo, tor, gemini, blog

Дееевоньки… вы даже не представляете, какой мне сегодня рецептик на форуме для мамочек посоветовали!

Кхем. Вернее…

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

В поисках вдохновения и референсов я прошлась по паре десятков сайтов, так или иначе указывающих на свою легковесность. Часто можно встретить одни и те же идеи: сосредоточенность на текстовых данных, минимальное количество CSS и отсутствие JavaScript, общий минимализм в оформлении и стилистике, помимо синдикации в RSS, также бывают зеркала в Tor и Gemini, элементы интерактивности с помощью IndieWeb. Рассмотрим небольшие хитрости для зеркалирования с помощью Hugo.

Референсы:

и много других. Сами найдёте, если захотите — это не такое редкое явление.

Tor

Не требует каких-либо дополнительных действий, кроме поднятия скрытого сервиса и настройки веб-сервера (например, Caddy).

Tor Browser и Brave Browser поддерживают HTTP-заголовок `Onion-Location`, отправляемый нашим веб-сервером для чистой сети, и будут автоматически предлагать пользователю перейти по Onion-адресу. Также существует фоллбек с помощью meta-тега.

Конфиг Tor:

HiddenServiceDir /etc/tor/droom.vision/
HiddenServicePort 80 127.0.0.1:8180

Конфиг Caddy:

droom.vision {
	root * /srv/http/droom.vision
	file_server

	header Onion-Location http://wjbwa5f5klig6szvtm7zsv7xk55r7yi2aaqo5vgtz7syxxdvy2m2skyd.onion{path}

	tls
	encode gzip
}

http://wjbwa5f5klig6szvtm7zsv7xk55r7yi2aaqo5vgtz7syxxdvy2m2skyd.onion:8180 {
	root * /srv/http/droom.vision
	file_server

	encode gzip
}

Meta-тег для добавления в условный шаблон Hugo `layouts/partials/head.html`:

<meta http-equiv="onion-location" content="http://wjbwa5f5klig6szvtm7zsv7xk55r7yi2aaqo5vgtz7syxxdvy2m2skyd.onion{{.RelPermalink}}" />

Не забудьте сменить Onion-адрес на свой. Возможно, этот meta-тег можно автоматически генерировать с помощью `[outputFormats]` в конфиге Hugo по аналогии с Gemini.

Gemini

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

Для удобства дебага капсулы рекомендую этот малюсенький Gemini-сервер.

Автоматика

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

Полуавтоматика

Вся магия происходит в `config.toml` Hugo. Поправив его, можно работать с `.gmi`-файлами как с обычными шаблонами.

uglyurls = true

[permalinks]
  blog = '/blog/:filename'
  notes = '/notes/:year/:month/:day/:filename'

[outputs]
  home = ['HTML', 'RSS', 'GEMTEXT']
  section = ['HTML', 'RSS', 'GEMTEXT']
  page = ['HTML', 'GEMTEXT']

[mediaTypes]
  [mediaTypes.'text/gemini']
    suffixes = ['gmi']

[outputFormats]
  [outputFormats.GEMINI]
    name = 'GEMTEXT'
    baseName = 'index'
    isPlainText = true
    isHTML = false
    mediaType = 'text/gemini'
    protocol = 'gemini://'
    permalinkable = true
    path = 'gemini/'

Что здесь происходит:

Вот, кстати, та самая настройка веб-сервера для работы с некрасивыми ссылками:

try_files {path}.html {path} {path}/ =404
uri strip_suffix /

За подробностями о каждом отдельном ключе рекомендую обратиться в справочную.

Далее, вы можете создавать такие же шаблоны в `layouts/_default/`, `layouts/sectionname/` и `layouts/pagename.gmi`, как и в случае с HTML. Вам доступны все данные из front matter ваших Markdown-файлов, параметры сайта из `config.toml` и Go-функции.

Например, `layouts/index.gmi` может быть как наполненным информацией, так и брать информацию из `_index.md`. У меня сосуществуют два разных файла индекса, то есть первый вариант, потому что я (пока что) не занимаюсь конвертацией.

`layouts/_default/list.gmi` уже требует заполнения некоторых директив:

{{ range .Pages }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title | safeHTML }}
{{.Date.Format "2006-01-02"}} · {{.Params.categories}} · {{ if eq .Kind "page" }} {{ delimit .Params.tags ", " }} {{end}}
{{ end }}

Что здесь происходит:

И самое интересное в `layots/_default/single.gmi`. До сих пор мы ничего не делали со страницами, записанными в Markdown. В принципе, если вы не злоупотребляете разметкой, можно ничего не делать: заголовки и списки в Markdown и Gemini одинаковые, остальная разметка просто не рендерится и выглядит вполне уместно. Именно это я делаю для постов, содержащих исключительно текст. Но что насчёт ссылок, альтернативных списков, Hugo-шорткодов?

# {{ .Title | safeHTML }}

{{if fileExists (replace $.File.Path ".md" ".gmi") }}
{{readFile (replace (replace $.File.Path ".md" ".gmi") ".html" ".gmi") | safeHTML}}
{{else}}
{{.RawContent | safeHTML}}
{{end}}

Что здесь происходит:

Вот, в принципе, и всё. Как генерировать исправленные `.gmi`-файлы уже решать вам: можно как я и другие — переписывать вручную; можно генерировать автоматически с помощью условного `md2gmn` и альтернатив — опять же, вручную, с помощью Git pre-commit hook или в процессе CI. Логика сего действа проста и тупа до смерти.

Отдельные герои умудряются конвертировать содержимое из Markdown в Gemtext с помощью встроенных Go-регулярок, но это некрасивое с виду решение. Настолько, что я предпочту попрактиковаться в клацаньи клавиш для достижения результата.

Для полной красоты ещё можете генерировать meta-тег в HTML, указывающий на существование Gemini-версии страницы. Что, впрочем, бесполезно, потому что URL-то всё равно неправильный, а как задать свой я пока что ещё не знаю.

{{ range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{ end -}}

Если я ничего не упустила, после выполнения `hugo` у вас внутри `public/` будут как HTML-файлы, так и `gemini/`.

Но не всё так радужно.

Баги

Hugo не был бы Hugo, не сломав мне мозг в совершенно неожиданных местах;

Итог

Смотрите исходники моего сайта и ~~не~~ делайте так же. Смотрите исходники других сайтов — там-то люди умнее постарались. Городите новые велосипеды и помогайте с починкой существующих (обратите внимание на gmnhg, например). ~~Воруй, убивай, еби гусей.~~