Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 1m50s
A private Bitmessage contour cannot be assembled by letting the nodes find each other. The sybil check in connectionpool refuses a candidate whose /16 is already among the outbound connections, and every container of a compose project shares one /16 -- so each node keeps a single outbound connection to a randomly chosen peer, and the contour splits into components on some runs and not on others. Three variables make the topology explicit instead: BITMESSAGE_TRUSTED_PEER trustedpeer = host:port BITMESSAGE_SEND_OUTGOING sendoutgoingconnections = True/False BITMESSAGE_KNOWN_NODES host:port,... -> knownnodes.dat With them a star is one line of config per node: the hub takes SEND_OUTGOING=False and only accepts, the spokes take TRUSTED_PEER=<hub>:8444. Details worth knowing: - trustedpeer is absent from the stock keys.dat, so a substitution alone would be a silent no-op. The key is added the same way maxtotalconnections is, and it is added even when the value is empty -- that is how a node that was pinned before can be unpinned. Its anchors stop at "=" rather than "= ", because an empty value leaves no trailing space to match. - knownnodes.dat is rewritten on every start, not only when missing. "Only when missing" would never have fired: the image ships one, built by the `pybitmessage -t` run in the Dockerfile, and a named volume inherits it. Seeding it is also what stops the DNS bootstrap -- deserialising any peer that is neither a DEFAULT_NODE nor "self" raises knownNodesActual, and startBootstrappers only runs while that flag is down. - Both peer variables are validated here. PyBitmessage does check trustedpeer, but with a sys.exit() from a constructor in the network thread, which reads as a container that died for no stated reason.
134 lines
11 KiB
Markdown
134 lines
11 KiB
Markdown
# Общие сведения
|
||
|
||
> English version: [README.md](README.md)
|
||
|
||
[PyBitmessage](https://bitmessage.org/) — клиент P2P-протокола обмена сообщениями Bitmessage, служащий для отправки шифрованных сообщений как одному адресату, так и множеству подписчиков.
|
||
|
||
Клиент PyBitmessage, работающий демоном в docker-контейнере с включённым XML-RPC API.
|
||
|
||
Репозиторий описывает только развёртывание в docker.
|
||
|
||
# Использование
|
||
|
||
Контейнер создаёт детерминированные адреса Bitmessage на основе переменной `BITMESSAGE_SEED_PHRASE`.
|
||
|
||
Ниже — примеры, с которых удобно начать создание контейнера.
|
||
|
||
У контейнера два порта, и они не взаимозаменяемы. **8442** — XML-RPC API: он
|
||
полностью управляет демоном и не имеет TLS, поэтому задайте свои учётные данные
|
||
и оставьте его на loopback. **8444** — P2P-порт Bitmessage: опубликуйте его,
|
||
чтобы к узлу могли подключаться другие, или не публикуйте, и тогда узел работает
|
||
только на исходящих. Внутри контейнера демон слушает оба в любом случае.
|
||
|
||
## docker-compose
|
||
|
||
```yaml
|
||
services:
|
||
pybitmessage:
|
||
build:
|
||
context: https://git.bitdeals.org/private/bitmessage.git
|
||
dockerfile: ./docker/Dockerfile
|
||
image: registry.bitdeals.org/bitmessage
|
||
environment:
|
||
- BITMESSAGE_API_USER=CHANGE_ME
|
||
- BITMESSAGE_API_PASSWORD=CHANGE_ME
|
||
- BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase
|
||
- BITMESSAGE_SEED_ADDRESSES=1
|
||
- BITMESSAGE_TTL=172800
|
||
- BITMESSAGE_STOPRESENDINGAFTERXDAYS=60
|
||
- BITMESSAGE_MAXTOTALCONNECTIONS=40
|
||
ports:
|
||
- 127.0.0.1:8442:8442 # API — только loopback
|
||
- 8444:8444 # P2P — уберите строку, чтобы остаться на исходящих
|
||
volumes:
|
||
- bitmessage:/home/bitmessage
|
||
|
||
volumes:
|
||
bitmessage:
|
||
```
|
||
|
||
## docker cli
|
||
|
||
```sh
|
||
docker run -d \
|
||
-e BITMESSAGE_API_USER=CHANGE_ME \
|
||
-e BITMESSAGE_API_PASSWORD=CHANGE_ME \
|
||
-e BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase \
|
||
-e BITMESSAGE_SEED_ADDRESSES=1 \
|
||
-e BITMESSAGE_TTL=172800 \
|
||
-e BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 \
|
||
-e BITMESSAGE_MAXTOTALCONNECTIONS=40 \
|
||
-p 127.0.0.1:8442:8442 \
|
||
-p 8444:8444 \
|
||
-v bitmessage:/home/bitmessage \
|
||
registry.bitdeals.org/bitmessage
|
||
```
|
||
|
||
# Параметры
|
||
|
||
Образы контейнера настраиваются параметрами, передаваемыми при запуске.
|
||
|
||
|Параметр|Назначение|
|
||
|:--------|:-------|
|
||
|-p 127.0.0.1:8442|Порт API. Внутри контейнера демон всегда слушает `0.0.0.0`, поэтому доступность определяет то, что опубликовано|
|
||
|-p 8444|P2P-порт Bitmessage. Необязательный: без него узел всё равно подключается к пирам сам, просто к нему подключиться нельзя. Публиковать только как `8444:8444` — см. «Замечания»|
|
||
|-v /home/bitmessage|Каталог данных: `keys.dat` (личность, настройки) и `messages.dat`. Без него после каждого обновления это новый узел|
|
||
|-e BITMESSAGE_API_USER|Пользователь XML-RPC API. По умолчанию: `bitmessage_api_user` — измените|
|
||
|-e BITMESSAGE_API_PASSWORD|Пароль XML-RPC API. По умолчанию: `bitmessage_api_password` — измените, см. «Замечания»|
|
||
|-e BITMESSAGE_SEED_PHRASE|Парольная фраза для создания детерминированных адресов. По умолчанию: генерируется заново при каждом старте, то есть адреса каждый раз другие. Используется только при `BITMESSAGE_SEED_ADDRESSES` больше `0`|
|
||
|-e BITMESSAGE_SEED_ADDRESSES|Количество создаваемых детерминированных адресов. По умолчанию: `0`|
|
||
|-e BITMESSAGE_TTL|Срок жизни вновь отправляемых сообщений, в секундах. По умолчанию: `172800`|
|
||
|-e BITMESSAGE_STOPRESENDINGAFTERXDAYS|Прекратить повторную отправку недоставленного сообщения через X дней. По умолчанию: `30`|
|
||
|-e BITMESSAGE_APIVARIANT|Предоставляемый API: xml или json-RPC. По умолчанию: `legacy`|
|
||
|-e BITMESSAGE_MAXTOTALCONNECTIONS|Предел одновременных соединений, входящих и исходящих вместе (`maxoutboundconnections` равен 8, то есть это значение минус 8 — запас на входящие). По умолчанию: `200`, штатное значение PyBitmessage — снижайте, если P2P-порт опубликован|
|
||
|-e BITMESSAGE_TRUSTED_PEER|`host:port` единственного пира, к которому узел подключается наружу; больше ни к кому. По умолчанию: пусто — узел выбирает пиров сам. См. «Замечания»|
|
||
|-e BITMESSAGE_SEND_OUTGOING|Подключается ли узел наружу вообще: `True` или `False`. По умолчанию: `True`. При `False` получается узел, который только принимает входящие, — центр приватного контура|
|
||
|-e BITMESSAGE_KNOWN_NODES|Список `host:port` через запятую; записывается в `knownnodes.dat` при каждом старте вместо того, что там было. По умолчанию: пусто — файл не трогается. Заодно выключает бутстрап по DNS, см. «Замечания»|
|
||
|
||
# Замечания
|
||
|
||
- `%` в пароле API использовать нельзя: он ломает собственный чтец конфигурации
|
||
PyBitmessage, и любой вызов API отвечает `500`, притом что `keys.dat`
|
||
выглядит правильным. Остальные символы допустимы, контейнер их экранирует.
|
||
- Клиенты обязаны кодировать учётные данные — они попадают в
|
||
`http://user:password@host:port/`, где `@`, `#`, `/` и `:` меняют разбор URL.
|
||
Скрипты этого образа кодируют, ваш клиент должен тоже.
|
||
- Контейнер становится здоровым, когда у демона появилось сетевое соединение,
|
||
— на новом узле это несколько минут. Начальный период ожидания заодно
|
||
покрывает стартовый `VACUUM` файла `messages.dat`.
|
||
- **P2P-порт публикуется только как `8444:8444`.** Пирам демон сообщает порт из
|
||
собственной конфигурации (`port` в `keys.dat`), а не тот, в который вы его
|
||
отобразили, поэтому `8555:8444` объявляет сети порт, где никого нет. Для
|
||
другого порта на хосте нужен `extport` в `keys.dat`, а его этот контейнер не
|
||
подставляет.
|
||
- **Свой адрес нигде не указывается.** В version-сообщении демон шлёт
|
||
захардкоженный `127.0.0.1`, который каждый пир отбрасывает и берёт вместо него
|
||
IP, увиденный на сокете, а порт — из того же сообщения. Поэтому узел с
|
||
опубликованным 8444 сеть находит сама, как только он подключится наружу:
|
||
ни IP, ни DNS-имя хоста задавать негде. Единственное исключение — скрытый
|
||
сервис Tor, которому нужен явный `onionhostname`.
|
||
- **Приватному контуру нужны назначенные пиры и звезда, в которую их назначать.**
|
||
PyBitmessage отвергает кандидата, чья сетевая группа (для IPv4 — /16) уже
|
||
представлена среди его исходящих соединений. Все контейнеры одного
|
||
compose-проекта живут в одной /16, поэтому каждый узел удерживает ровно одно
|
||
исходящее соединение — со случайно выбранным пиром, и контур чаще всего
|
||
распадается на компоненты. Задайте одному узлу
|
||
`BITMESSAGE_SEND_OUTGOING=False`, и он станет хабом, который только принимает
|
||
(проверка смотрит лишь на исходящие, входящие она не ограничивает), остальные
|
||
направьте на него через `BITMESSAGE_TRUSTED_PEER=<ip-хаба>:8444` — объекты
|
||
пойдут спица → хаб → спицы. Адреса задавайте IP, а не именами сервисов:
|
||
проверка разбирает хост как IP, да и обмен `addr` между узлами оперирует IP.
|
||
- **`BITMESSAGE_KNOWN_NODES` — то, что делает приватный контур приватным.** Узел,
|
||
у которого в `knownnodes.dat` есть пир не из встроенного списка PyBitmessage,
|
||
перестаёт спрашивать адреса у `bootstrap8080.bitmessage.org`; без этого даже
|
||
узел с назначенным пиром при каждом старте резолвит публичный бутстрап-хост.
|
||
Файл переписывается на каждом старте, поэтому во что узел верит при загрузке,
|
||
определяет переменная, а не история контейнера.
|
||
- **Публикация 8444 — осознанный компромисс по безопасности.** Демон работает на
|
||
Python 2 и уже разбирает недоверенные данные от своих исходящих пиров, так что
|
||
открытый порт эту поверхность не создаёт — он меняет то, *кто* может
|
||
подключиться, *когда* и *сколько их*. Разбор до рукопожатия становится доступен
|
||
кому угодно, а реальный риск — исчерпание ресурсов, а не выполнение кода.
|
||
Держите `BITMESSAGE_MAXTOTALCONNECTIONS` низким и ограничьте контейнер по
|
||
памяти и CPU.
|