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.
11 KiB
Общие сведения
English version: README.md
PyBitmessage — клиент P2P-протокола обмена сообщениями Bitmessage, служащий для отправки шифрованных сообщений как одному адресату, так и множеству подписчиков.
Клиент PyBitmessage, работающий демоном в docker-контейнере с включённым XML-RPC API.
Репозиторий описывает только развёртывание в docker.
Использование
Контейнер создаёт детерминированные адреса Bitmessage на основе переменной BITMESSAGE_SEED_PHRASE.
Ниже — примеры, с которых удобно начать создание контейнера.
У контейнера два порта, и они не взаимозаменяемы. 8442 — XML-RPC API: он полностью управляет демоном и не имеет TLS, поэтому задайте свои учётные данные и оставьте его на loopback. 8444 — P2P-порт Bitmessage: опубликуйте его, чтобы к узлу могли подключаться другие, или не публикуйте, и тогда узел работает только на исходящих. Внутри контейнера демон слушает оба в любом случае.
docker-compose
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
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.