SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-21

Как установить Hister: персональный поисковик

Разверните Hister на VPS для поиска по истории посещений и локальным файлам. Инструкция охватывает установку Docker, настройку TLS, создание учетной записи и работу с MCP.

Что такое Hister и чем он не является

Hister — это персональная поисковая система для самостоятельного размещения. Она индексирует полный текст посещенных вами страниц и хранимых файлов, позволяя выполнять поиск по этой коллекции через веб-интерфейс, терминальный клиент, HTTP API или помощника на базе ИИ (искусственного интеллекта). Hister отвечает на один вопрос: где я это читал.

Большинство пользователей знакомы с этой концепцией благодаря SearXNG, однако это разные инструменты. SearXNG — это прокси-метапоисковик. Ваш запрос поступает в него, он отправляет запросы другим поисковым системам от вашего имени и возвращает результаты, очищенные от трекинга. Индекс при этом принадлежит этим поисковым системам. Hister же строит собственный индекс на основе контента, который вы ему предоставили: страниц, захваченных расширением браузера, импортированной истории браузера, просканированных URL и файлов в указанных вами директориях. Экземпляр SearXNG для самостоятельного размещения предоставляет приватный доступ к публичному вебу. Hister обеспечивает поиск по вашим собственным прочитанным материалам. Это разные задачи, поэтому их совместная работа на одном сервере — обычная практика.

Hister — это свободное программное обеспечение, распространяемое по лицензии AGPLv3 (GNU Affero General Public License, версия 3) или более поздней. В нем отсутствует телеметрия, и оно не требует облачных сервисов. В данном руководстве используется версия v0.17.0, которая была актуальным релизом на 2026-07-28. Перед копированием команд проверьте страницу релизов на наличие актуального тега и используйте найденную версию.

Почему стоит разместить Hister на собственном VPS

Индекс полезен только тогда, когда он полон, а полным он будет лишь в том случае, если сервер работал во время вашего чтения. Ноутбук находится в спящем режиме половину дня. Страницы, открытые на телефоне в это время, не попадут в индекс, а импорт, запланированный на ночь, не запустится. VPS (виртуальный выделенный сервер) работает постоянно, поэтому все ваши устройства отправляют данные в один и тот же индекс, а краулер продолжает работу, пока вы спите.

Вторая причина — изоляция. Настройка user_handling: true в секции app предоставляет каждой учетной записи собственные учетные данные и отдельную коллекцию документов на одном экземпляре приложения. Таким образом, один сервер может обслуживать семью или небольшую команду, при этом никто не сможет искать документы в чужой истории чтения.

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

Вариант установки один: релизный бинарный файл

Hister выпускает по одному бинарному файлу на платформу. Загрузите его вместе с файлом контрольных сумм и выполните проверку перед установкой.

cd /tmp
curl -LO https://github.com/asciimoo/hister/releases/download/v0.17.0/hister_0.17.0_linux_amd64
curl -LO https://github.com/asciimoo/hister/releases/download/v0.17.0/hister_0.17.0_checksums.txt
sha256sum --ignore-missing -c hister_0.17.0_checksums.txt

Успешным результатом является одна строка hister_0.17.0_linux_amd64: OK. Строка FAILED означает, что файл поврежден или изменен, поэтому загрузите его заново, прежде чем приступать к установке.

Установите бинарный файл, затем создайте системную учетную запись и каталоги, которые он будет использовать.

sudo install -m 755 /tmp/hister_0.17.0_linux_amd64 /usr/local/bin/hister
sudo useradd --system --home-dir /var/lib/hister --shell /usr/sbin/nologin hister
sudo install -d -o hister -g hister -m 750 /var/lib/hister
sudo install -d -m 755 /etc/hister
sudo hister create-config /etc/hister/config.yml

create-config создает файл конфигурации по умолчанию, а также подтверждает, что бинарный файл запускается на этой машине. Если загружена версия для неверной архитектуры, выполнение завершится ошибкой cannot execute binary file: Exec format error.

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

app:
  directory: /var/lib/hister
  access_token: 'paste-a-long-random-string-here'
server:
  address: 127.0.0.1:4433
  base_url: https://hister.example.com

Сгенерируйте токен с помощью openssl rand -hex 32. Файл теперь содержит учетные данные, поэтому ограничьте права доступа к нему до запуска службы.

sudo chown root:hister /etc/hister/config.yml
sudo chmod 640 /etc/hister/config.yml

Запуск под управлением systemd

Создайте файл /etc/systemd/system/hister.service:

[Unit]
Description=Hister personal search engine
After=network-online.target
Wants=network-online.target

[Service]
User=hister
Group=hister
Environment=HISTER_CONFIG=/etc/hister/config.yml
ExecStart=/usr/local/bin/hister listen
Restart=on-failure
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/hister

[Install]
WantedBy=multi-user.target

HISTER_CONFIG — это документированная переменная окружения для пути к конфигурации, поэтому юнит не зависит от домашнего каталога учетной записи hister. ProtectSystem=strict переводит всю файловую систему в режим «только для чтения» для этого сервиса, поэтому в ReadWritePaths необходимо указать каталог с данными. ProtectHome=yes скрывает /home от сервиса, поэтому отслеживаемый каталог внутри /home будет выглядеть пустым для индексатора. Удалите эту строку, если вам нужно индексировать файлы в этом расположении.

sudo systemctl daemon-reload
sudo systemctl enable --now hister
systemctl status hister --no-pager
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4433/

Любой HTTP-код ответа, выведенный последней командой, означает, что процесс прослушивает порт. curl: (7) Failed to connect означает, что это не так, а journalctl -u hister -n 50 --no-pager укажет причину.

Вариант установки два: Docker Compose

Образ опубликован в GitHub container registry, по одному тегу на каждый релиз.

services:
  hister:
    image: ghcr.io/asciimoo/hister:v0.17.0
    container_name: hister
    user: '1000:1000'
    restart: unless-stopped
    environment:
      - HISTER__SERVER__ADDRESS=0.0.0.0:4433
      - HISTER__SERVER__BASE_URL=https://hister.example.com
      - HISTER__APP__ACCESS_TOKEN=${HISTER_ACCESS_TOKEN}
    volumes:
      - ./data:/hister/data
    ports:
      - 127.0.0.1:4433:4433

Каждый ключ конфигурации имеет переопределение через переменную окружения вида HISTER__<SECTION>__<KEY>, где два символа подчеркивания служат разделителем, поэтому для развертывания контейнера не требуется монтировать файл конфигурации. Храните HISTER_ACCESS_TOKEN в файле .env рядом с файлом compose. Если вы предпочитаете редактировать файл, команда docker run --rm ghcr.io/asciimoo/hister:v0.17.0 create-config > config.yml выведет значения по умолчанию.

Две строки выше легко настроить неверно, и обе стоит изучить.

Адрес внутри контейнера должен быть 0.0.0.0:4433. Контейнер имеет собственное сетевое пространство имен, поэтому процесс, привязанный к 127.0.0.1 внутри него, доступен только изнутри этого контейнера, и опубликованному порту нечего перенаправлять.

Опубликованный порт записывается как 127.0.0.1:4433:4433, а не 4433:4433. Docker публикует порты, вставляя собственные правила netfilter, и эти правила оцениваются до правил ufw, поэтому обычный 4433:4433 остается доступным из интернета даже на машине, где ufw status показывает, что порт закрыт. Привязка хостовой стороны к 127.0.0.1 оставляет reverse proxy единственным способом доступа. Эта же ловушка применима к каждому контейнеру на сервере, и в Docker Compose на VPS рассматриваются остальные аспекты этой темы.

Образ по умолчанию запускается от имени UID 1000 и GID 1000, поэтому ./data должен быть доступен для записи этой учетной записи, иначе контейнер остановится при запуске с ошибкой доступа. sudo chown -R 1000:1000 ./data исправляет это. Если эти числа вам незнакомы, сначала прочитайте от имени какого UID и GID контейнер записывает файлы.

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

Hister по умолчанию прослушивает 127.0.0.1:4433, и этот выбор сделан намеренно. Подумайте, что содержит индекс спустя месяц использования: страницы внутренней вики, счета, тикеты в техподдержку, открытые в авторизованном состоянии, страницы сброса паролей и полный текст всего остального, что вы читали. В документации проекта прямо сказано: "Hister передает всю вашу историю браузера, включая содержимое страниц, на сервер и обратно".

Утекшую базу паролей еще нужно взломать. Утекший персональный индекс — это открытый текст, готовый к поиску, поэтому он требует больше защиты, чем кажется на первый взгляд, учитывая, что это небольшое self-hosted приложение.

Из этого следуют два факта. Hister «из коробки» не требует аутентификации, поэтому один лишь reverse proxy делает вашу историю поиска доступной любому, кто узнает имя хоста. MCP-эндпоинт также по умолчанию доступен по адресу /mcp, и без токена любой клиент, имеющий к нему доступ, может выполнять поиск по индексу.

Настройте аутентификацию до того, как сервис впервые выйдет за пределы localhost. Одному пользователю достаточно app.access_token — общего секретного ключа, который передается расширением браузера, терминальным клиентом и любым MCP-клиентом. Для нескольких пользователей настройте user_handling: true и создайте учетные записи:

sudo -u hister hister create-user alice --admin --config /etc/hister/config.yml

Команда запросит пароль длиной не менее 8 символов. Каждая учетная запись получает собственные документы и персональный API-токен, который владелец может пересоздать на странице профиля или с помощью флага --regen-token в hister update-user. Генерация нового токена немедленно аннулирует предыдущий, поэтому после этого потребуется обновить все устройства, использующие данную учетную запись.

Не меняйте app.public, если вы не уверены в необходимости этого действия. Публичный режим разрешает неаутентифицированный поиск, просмотр превью, раздачу файлов и MCP-поиск, но при этом блокирует запись данных, доступ к истории и административные операции.

Reverse proxy, TLS и межсетевой экран

Hister не поддерживает HTTPS самостоятельно, поэтому выполняйте TLS (transport layer security) termination перед ним. Caddy — самый быстрый путь, так как он самостоятельно запрашивает и обновляет сертификаты через ACME (automatic certificate management environment).

hister.example.com {
    reverse_proxy 127.0.0.1:4433
}

Перезагрузите его с помощью sudo systemctl reload caddy. Перед выдачей сертификата должны быть соблюдены два условия: A-запись для hister.example.com должна указывать на этот сервер, а порт 80 должен быть открыт, так как через него проходит проверка HTTP-01 challenge. Если хотя бы одно из условий не выполнено, браузер выдаст ошибку TLS вместо страницы, а в логах Caddy будут повторяться сообщения о неудачной проверке.

Затем закройте все остальные порты.

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

Порт 4433 намеренно отсутствует в этом списке.

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

Наполнение индекса

Браузерное расширение является основным сборщиком данных. Установите его из Mozilla Add-ons или Chrome Web Store, откройте страницу настроек, укажите URL сервера в https://hister.example.com и вставьте токен доступа. После этого расширение будет захватывать заголовок, полный текст, HTML и favicon каждой посещаемой страницы и отправлять их на ваш сервер. Извлечение данных происходит на стороне клиента, внутри браузера. Расширение не взаимодействует с третьими лицами, а единственный внешний запрос, который оно выполняет — это запрос favicon страницы.

Извлечение данных на стороне клиента делает возможным создание приватного индекса. Расширение видит страницу точно так же, как и вы — после авторизации и рендеринга, поэтому внутренняя страница вики или платная статья будут проиндексированы корректно, а вашему серверу не потребуются учетные данные. Это также означает, что всё, что вы просматриваете, является кандидатом для индексации, поэтому правила исключения (skip rules) имеют приоритет перед добавлением контента.

Правила исключения хранятся в rules.json при однопользовательской установке или для каждого пользователя в базе данных; вкладка Rules в веб-интерфейсе — самый простой способ их редактирования. Это регулярные выражения Go, которые сопоставляются с полным URL:

^https://mail\.example\.com
^https://bank\.example\.com
.*?utm_source=

Шаблон вида ^mail.example.com никогда не сработает, так как проверяемая строка начинается с https://. Завершающий $ также не сработает для любого URL, содержащего строку запроса, поскольку параметры запроса сохраняются при сопоставлении.

Существующая история импортируется путем чтения собственной базы данных браузера, поэтому эта команда запускается на машине, где находится профиль браузера — то есть на вашем ноутбуке, а не на VPS. Установите тот же бинарный файл локально и укажите адрес сервера:

export HISTER_TOKEN='your-access-token'
hister import browser firefox -u https://hister.example.com -t "$HISTER_TOKEN"

Импорт выполняется как возобновляемая задача с именем browser-import-YYYY-MM-DD, поэтому вы можете прервать её и запустить снова позже. Сервисы закладок импортируются аналогичным образом, включая Linkwarden, Karakeep, Wallabag, Linkding, Readeck и Shaarli; повторный импорт забирает только те данные, которые новее предыдущего.

Файлы на сервере индексируются путем указания директорий в конфигурации:

indexer:
  directories:
    - path: '/var/lib/hister/documents'
      label: 'documents'
      filetypes: ['pdf', 'docx', 'md', 'txt']

PDF, DOCX, Markdown, Org mode и текстовые файлы в кодировке UTF-8 считываются как полнотекстовые. Фотографии и видео в этот список не входят, поэтому для библиотеки изображений нужен сервер, который индексирует лица, места и даты, а не текст; PhotoPrism и Immich — два решения, которые обычно сравнивают для этой задачи. Отдельная страница добавляется с помощью hister index https://example.com. Преобразование целых сайтов в чистый текст для других инструментов — это отдельная задача, решаемая с помощью self-hosted crawlers, которые преобразуют страницы в чистый текст.

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

"connection reset" domain:github.com added:<30d
title:(wireguard|nftables) -tutorial sort:-visits

Настройка агента для работы с вашим собственным индексом через MCP

MCP (model context protocol) — это интерфейс, который ассистент использует для вызова инструментов на сервере. Hister предоставляет его по адресу POST /mcp с тем же базовым URL, используя потоковый транспорт HTTP, и открывает search, get_preview и get_history. Аутентификация выполняется с помощью того же bearer-токена, что и для остальной части API.

{
  "mcpServers": {
    "hister": {
      "url": "https://hister.example.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_ACCESS_TOKEN"
      }
    }
  }
}

Заголовок X-Access-Token работает как альтернатива Authorization.

Ценность этого подхода заключается в том, что именно ищет агент. Поиск в открытом вебе возвращает то, что имеет высокий рейтинг сегодня, а для быстро развивающегося ПО это часто документация к версии, которую вы не используете. Ваш собственный индекс возвращает страницу, которую вы уже прочитали и решили сохранить, а get_preview предоставляет сохраненную копию, поэтому ответ останется доступным, даже если исходная страница исчезнет из сети. Предоставьте агенту оба источника, если вам нужны и публичные результаты: инструмент поиска в браузере на базе SearXNG добавляет открытый веб в качестве отдельного инструмента. Как только вы начнете использовать более одного из этих эндпоинтов, стоит ознакомиться с размещением MCP-серверов на VPS, так как каждый из них сталкивается с этой проблемой доступности.

Диск, резервное копирование и обслуживание

Документация оценивает размер одной индексированной страницы примерно в 100 KB, включая сжатый превью, поэтому сто тысяч страниц занимают около 10 GB. Система квот отсутствует. Две настройки часто путают между собой: indexer.max_file_size_mb (по умолчанию 1 MiB) ограничивает размер одного отслеживаемого файла, а server.max_batch_body_size (по умолчанию 40 MiB) ограничивает размер одного API-запроса.

В директории, указанной в app.directory, хранятся index.db с индексными файлами для каждого языка, db.sqlite3 для учетных записей и заданий, data/html/ для превью и rules.json. Резервная копия создается путем остановки сервиса и копирования всей этой директории вместе с файлом конфигурации. hister export backup.json экспортирует документы в формате JSON для миграции, это не является резервной копией сервера.

Следует знать две команды для обслуживания. hister reindex перестраивает поисковые индексы, что необходимо после изменения настроек индексатора. Если при большом импорте потребление памяти растет, установите detect_languages: false в секции indexer и выполните переиндексацию. hister cleanup удаляет осиротевшие файлы превью и иконок (favicon), оставшиеся после удаления страниц.

Удаление выполняется через запрос, поэтому сначала запустите его в тестовом режиме (dry mode):

hister delete 'domain:example.com' --dry --verbose

Удаленная страница вернется, если сборщик продолжит её отправлять, поэтому добавьте правило пропуска (skip rule) перед удалением.

Лицензия AGPLv3 имеет значение только в том случае, если вы вносите изменения в код. Использование неизмененной копии для личных нужд не накладывает никаких обязательств. Если вы модифицируете Hister и предоставляете другим людям доступ к своей версии по сети, лицензия требует предоставить им исходный код ваших изменений.

Типичные ошибки и сообщения о них

Сервер не запускается. Либо порт 4433 уже занят, либо в файле конфигурации допущена синтаксическая ошибка YAML. Команда sudo ss -lntp | grep 4433 покажет, какой процесс занимает порт, а journalctl -u hister -n 50 --no-pager выведет ошибку парсинга.

Интерфейс загружается, но отображается некорректно. Искаженный текст и отсутствие изображений означают, что server.base_url не совпадает с URL в адресной строке. Завершающий слэш также считается несовпадением.

Расширение не подключается. URL сервера в настройках расширения должен в точности соответствовать base_url, сервер должен быть запущен и обновлен, а сетевой экран между ними может блокировать соединение без вывода сообщений на странице. Firefox не выводит логи расширений в обычную консоль: откройте about:debugging#/runtime/this-firefox и изучите логи расширения Hister.

Контейнер завершает работу при запуске. Ошибка прав доступа к ./data означает, что владельцем директории является UID, отличный от 1000, который используется учетной записью внутри стандартного образа.

Ошибка 403 Forbidden при обращении к административному маршруту. POST /api/reindex и POST /api/cleanup доступны только администраторам, если включена обработка пользователей, поэтому обычным учетным записям доступ к ним запрещен.

Потребление памяти растет во время импорта. Обычно это вызвано определением языка в большой истории. Установите detect_languages: false и после этого выполните hister reindex.

FAQ

Чем Hister отличается от SearXNG?

SearXNG — это метапоисковый прокси: он перенаправляет ваш запрос к публичным поисковым системам и возвращает их результаты, удаляя из них трекеры, поэтому индекс принадлежит этим системам. Hister хранит собственный полнотекстовый индекс страниц, которые вы посещали, и файлов, которые вы сохранили. Таким образом, Hister отвечает на вопрос «где я это читал», тогда как SearXNG отвечает на вопрос «что об этом говорит интернет». Они решают разные задачи, и многие пользователи запускают оба сервиса на одном сервере.

Безопасно ли хранить всю историю браузера на VPS?

Только при условии предварительной настройки доступа. Hister привязывается к 127.0.0.1:4433 и по умолчанию не требует аутентификации. Установите app.access_token или user_handling: true, настройте перед ним reverse proxy с TLS и закройте порт 4433 на межсетевом экране. Полнотекстовый индекс вашей истории — это обычный текст, поэтому любой, кто получит доступ к порту, сможет прочитать всё без необходимости взлома.

Нужно ли мне расширение для браузера или я могу просто импортировать историю?

Импорт — это разовая операция для заполнения данных. Он считывает собственную базу данных истории браузера, поэтому выполняется на компьютере, где находится профиль браузера, а не на сервере. Расширение поддерживает индекс в актуальном состоянии после импорта и захватывает страницы, требующие авторизации, так как извлекает контент непосредственно в браузере после отрисовки страницы. Стандартная схема работы: один импорт, затем использование расширения.

Может ли агент для написания кода искать по моему индексу Hister?

Да. Hister является MCP-сервером (model context protocol) по адресу POST /mcp относительно вашего базового URL, предоставляя методы search, get_preview и get_history. Укажите клиенту адрес https://your-host/mcp с заголовком Authorization: Bearer, содержащим ваш токен доступа. После этого агент сможет искать по документации, которую вы действительно читали, именно в той версии, которую вы изучали, вместо того чтобы полагаться на текущую выдачу публичных поисковых систем.