Паста на своих: rustypaste вместо капризного CDN

Почему пришлось брать метлу в лапки

Мы хостили иллюстрации для постов на catbox.moe. В какой‑то момент их CDN (files.catbox.moe) из РФ стал отвечать “Connection reset by peer”: TLS обрывался, картинки не открывались. Наш робот‑дворник посмотрел на этот сугроб разрывов, вздохнул, махнул метлой и сказал: «Хватит, делаем своё».

Что за rustypaste и почему он

rustypaste (v0.17.0) — минималистичный paste/file‑host на одном бинарнике Rust. Базы данных нет, всё хранится в файловой системе, конфиг — один config.toml. Из коробки: – загрузка файлов и текста, в том числе из удалённого URL; – угадывает MIME и позволяет его переопределять/блокировать; – одноразовые ссылки, срок жизни, удаление по токену; – аутентификация простым Authorization токеном или списком токенов в конфиге.

Нам нужен был быстрый и автономный хост для картинок канала — без лишней магии и с контролем загрузки. Rustypaste закрыл все пункты.

Как подняли: LXC + systemd + Caddy

systemd-юнит

Создаём пользователя и юнит:

# один раз

![Обложка](https://paste.clr58.ru/post-rustypaste-cover-digclean.jpg)

useradd -r -s /usr/sbin/nologin -m -d /var/lib/rustypaste rustypaste || true
install -d -o rustypaste -g rustypaste /var/lib/rustypaste/upload /etc/rustypaste

cat >/etc/systemd/system/rustypaste.service <<'UNIT'
[Unit]
Description=Rustypaste service
After=network-online.target
Wants=network-online.target

[Service]
User=rustypaste
Group=rustypaste
WorkingDirectory=/var/lib/rustypaste
Environment=CONFIG=/etc/rustypaste/config.toml
Environment=RUST_LOG=info
ExecStart=/usr/local/bin/rustypaste
Restart=always

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable --now rustypaste

Конфиг rustypaste (/etc/rustypaste/config.toml)

Важно: ниже используются документные диапазоны (RFC 5737) и заглушки — подставьте свой поддомен/пути/токены. Для heredoc используйте литеральный режим <<'TOML' — это спасает от «съедания» бэкслешей.

cat > /etc/rustypaste/config.toml <<'TOML'
[server]
address = "198.51.100.42:8000"        # LXC во внутренней сети
url = "https://paste.example"         # внешний адрес за Caddy
upload_path = "/var/lib/rustypaste/upload"
auth_tokens = ["<PASTE_UPLOAD_TOKEN>"]
expose_version = false
hardening = true

[paste]
# Расширение по умолчанию для текстов без явного имени
default_extension = "txt"
# Переопределения MIME по regex — используйте литеральные строки (одинарные кавычки)
mime_override = [
  { mime = 'image/png',  regex = '^.*\.png$' },
  { mime = 'image/jpeg', regex = '^.*\.(jpg|jpeg)$' },
  { mime = 'image/gif',  regex = '^.*\.gif$' }
]
# Что принудительно отдавать как text/plain (для предпросмотра)
text_mime_overrides = ["text/markdown", "application/json"]
TOML

chown -R rustypaste:rustypaste /etc/rustypaste /var/lib/rustypaste
systemctl restart rustypaste

Caddy reverse_proxy

Минимальный сайт‑блок:

paste.example {
  encode zstd gzip
  reverse_proxy 198.51.100.42:8000
}

Caddy сам пройдёт HTTP‑01 и выпустит сертификат для paste.example.

Загрузка и проверка

# Без токена — 401 Unauthorized
curl -fsS -F "file=@x.png" https://paste.clr58.ru/ || echo "→ 401 as expected"

# С токеном — получаем ссылку вида https://paste.clr58.ru/<имя>.png
curl -fsS -H "Authorization: <PASTE_UPLOAD_TOKEN>" -F "file=@x.png" https://paste.clr58.ru/

Пакетная переливка картинок (пример):

for f in ./images/*; do
  curl -s -H "Authorization: <PASTE_UPLOAD_TOKEN>" -F "file=@$f" https://paste.clr58.ru/ >> uploaded_urls.txt
  echo >> uploaded_urls.txt
done

Грабли, на которые наступили

1) TOML + regex: «TOML parse error: missing escaped value». Мы сначала писали regex в двойных кавычках и заливали конфиг heredoc’ом без литерального режима — bash скромно «почистил» бэкслеши. Лечение: либо heredoc с <<'TOML', либо TOML‑строки в одинарных кавычках (литеральные), как в примере выше.

2) «config.toml is not found» и цикл рестартов. Первая передача конфига в контейнер банально не долетела — сервис честно падал и перезапускался. Проверяйте, что файл реально на месте и виден пользователю сервиса: ls -l /etc/rustypaste/config.toml и права на каталог.

Итог: картинки вернулись домой

Робот‑дворник доволен: меньше мусора из внешних зависимостей — больше чистых дорожек в контент‑плане.

Ссылки

#selfhosting #lifehacks