Аргус: простой движок для блога v0.1.0

Что это такое?
Движок: Python, FastAPI
Ведение записей: Obsidian11
База данных: SQLite
Комментарии: не предусмотрены
Откуда скачать: Argus Blog Engine
Лицензия: MIT
Как работает блог: владелец блога создает записи в Obsidian, затем командой из командной строки публикует сайт.
Зачем мне еще один движок?
Именно этот вопрос, я задал сам себе, когда начал реализовывать данный движок.
На самом деле все просто.
Я начал с отличного движка WordPress. Превосходная вещь, заточена под любые нужды, но есть проблема. Wordpress — это универсальная платформа. Для того чтобы универсальная платформа удовлетворяла нужды всех пользователей, в ней должно быть много настроек, много кастомизации. И здесь оказалась первая проблема. Мне нужно было не добавлять какие-то функции а наоборот выключать уже готовые.
Вторая вещь: темы. Их очень много, под любые нужды, но универсальность ведет к тому, что я не нашел ту, которая понравится мне. Сделать свою необходимо изучить движок. Я не захотел. Так и родился очень простой движок на FAST API.
Третья вещь: ведение контента. Мне очень нравится Obsidian, превосходная вещь для записей для того, чтобы делать ссылки из одного файла на другой и формировать связанный граф знаний. И мне приходилось периодически копировать текст из Obsidian, вставлять его в WordPress, менять стили, разбивать дополнительно на абзацы. Все это занимало время.
Почему Аргус?
Аргус — имя пса из Одиссеи Гомера. История об Аргусе — это, пожалуй, самое первое в западной литературе упоминание о верности собак. Гомер запечатлел здесь архетипический образ преданного пса, который ждёт хозяина и умирает, дождавшись его возвращения. Этот мотив потом будет повторяться бесчисленное количество раз — от средневековых легенд до современных фильмов и книг, но исток его именно в «Одиссее».
Что реализовано по визуалу и темизации
В стандарте тема реализована приблизительно такая, которая вы видите на сайте.

Чтобы добавить новую тему либо кастомизировать текущую, достаточно просто скопировать её из папки default в другую папку и назначить новую переменную в env-файле.

# Тема оформления — папка app/themes/<THEME>/ с шаблонами и статикой.
THEME=datacycle
Всего 10 HTML-файлов с Jinja-templates внутри.
CSS взят базовый, без каких-либо библиотек, но ничего не мешает подключить новую библиотеку.
Как публиковать заметку
Главное условие publish: true. И это единственное обязательное поле.
---
title: Как я настроил блог
date: 2026-08-03
tags:
- obsidian - pythondescription: Текст, который Google покажет под ссылкой в выдаче.
publish: true
---
| Поле | Если не задано |
|---|---|
publish |
заметка игнорируется |
title |
первый # в тексте, иначе имя файла |
date |
дата создания файла |
tags |
пост без тегов |
description |
первый абзац, обрезанный до ~160 символов |
slug |
генерируется и дописывается в файл |
updated |
дата, когда содержание менялось в последний раз |
cover |
первая картинка в посте (путь — как к вложению в тексте) |
aliases |
используется только для разрешения [[ссылок]] |
В Obsidian всё это удобно заполнять через панель свойств (Ctrl+;),
а publish завести как свойство-галочку.
Теги берутся только из frontmatter и записываются списком —
по строке на тег, как их пишет панель свойств Obsidian. Запись в строку
(tags: [obsidian, python]) тоже читается, переписывать старые заметки
не нужно. Инлайновые #теги в тексте не обрабатываются — так предсказуемее.
Порядок тегов значим. Первый в списке считается основным: он попадает
в хлебные крошки поста (Главная → obsidian → Заголовок) и стоит первым
в плашках под заголовком. Хотите другую рубрику — переставьте теги местами.
Дата обновления хранится в самой заметке. Заметив, что вы поправили текст,
синхронизация впишет в свойства updated: 2026-08-09 — так же, как вписывает
slug. Дальше эта дата и уходит на сайт, в sitemap и в RSS.
Время изменения файла для этого не годится: Obsidian переписывает заметку при
закрытии, синхронизация и git трогают её при выгрузке — дата ползла бы вверх
без единой правки. Поэтому она меняется, только если изменились текст,
заголовок, описание, теги или обложка. Перестановка свойств в панели, новый
алиас или служебное поле плагина её не трогают.
Раз дата лежит в заметке, пересборка базы (--rebuild) и даже её потеря
ничего не теряют. Обратная сторона: правку, сделанную в отсутствие базы,
синхронизация не заметит — дата обновится при следующей.
У новых заметок поля нет, и это не забывчивость: пока правок не было, датой
обновления считается дата публикации. Проставите updated руками — будет
ваше значение, пока вы снова не измените текст.
Что понимается из синтаксиса Obsidian
[[Заметка]],[[Заметка|подпись]],[[Заметка#Раздел]],[[папка/Заметка]], алиасы![[картинка.png]]— вложения копируются вmedia/> [!warning] Заголовок— коллауты- `` — вырезаются
```python— подсветка кода с номерами строк и кнопкой копирования- одиночный перенос строки — виден на сайте, как в режиме чтения Obsidian
Mermaid-диаграммы не поддерживаются: блок ```mermaid отрисуется как код.
Правило приватности
Всё, что не помечено publish: true, не существует. Ссылка на такую
заметку превращается в обычный текст, эмбед выбрасывается. Наружу не уходит
ни адрес, ни название. Синхронизация отчитывается о каждом таком случае:
Ссылки:
! Как я настроил блог: [[Личные финансы]] не опубликована — оставлена текстом
Про slug
Slug генерируется из заголовка один раз и записывается в файл. Дальше
переименование заголовка не меняет URL. Если поправить слаг руками,
синхронизация запишет 301 со старого адреса на новый и схлопнёт цепочки
предыдущих редиректов.
Запись в vault — единственное, что скрипт делает с вашими заметками, и только
с помеченными к публикации. Полей всего два: slug и updated. Меняется одна
строка в существующем frontmatter, YAML не пересобирается: порядок полей,
кавычки и комментарии остаются как были.
Если один и тот же слаг прописан руками сразу в двух заметках, синхронизация
остановится и покажет, в каких именно файлах, ничего не изменив. Адрес поста
должен быть один, а решить, за какой заметкой он остаётся, можете только вы.
SEO
- уникальные
titleиdescription,canonical,og:*, Twitter Cards - JSON-LD:
WebSite,BlogPosting,BreadcrumbList sitemap.xmlсlastmod,robots.txt, RSS сcontent:encoded- ЧПУ с транслитерацией кириллицы, 301 при смене слага
- ровно один
<h1>на странице,<article>,<time datetime> noindexна поиске, честный 404 вместо страниц-пустышек с кодом 200
Скорость (Core Web Vitals — фактор ранжирования):
- всё рендерится на сервере, готовый HTML лежит в базе
- шрифты самохостятся, запросов к сторонним доменам нет вообще
- у каждой картинки проставлены
widthиheight— страница не прыгает - единственный скрипт ~300 байт инлайном
Развёртывание на VPS
- VPS — 1 vCPU и 1 ГБ памяти хватает с запасом: два воркера uvicorn едят
порядка 120 МБ, остальное берёт на себя Caddy. - Домен с доступом к DNS-записям.
- SSH-ключ. Деплой-скрипт делает три подключения подряд и один раз
запускаетsudoбез терминала — с парольным входом это не работает. - Локально — свой скрипт на каждую систему. В Linux и macOS выкладывает
deploy/deploy.sh, ему нужныrsyncиssh. В Windows выкладывает
deploy/deploy.ps1из PowerShell: rsync там нет ни в системе, ни в Git Bash,
поэтому скрипт обходитсяssh,scpиtar— они входят в Windows 10/11.
Ни WSL, ни Git Bash для деплоя не нужны.
Подробная инструкция в файле DEPLOY.md