bitcoin-knots: convert to a role, de-Uptime-Kuma the health check

892-line playbook becomes 40 lines plus a role with install/build/configure/
service/healthcheck phases, five templates and one handler. bitcoin_knots_vars.yml
is deleted; its content is the role's defaults.

Verified after a real run: bitcoind still active since 2026-08-19 (NO restart),
chain at 966844 blocks / 875 GB, DATUM config intact, dbcache still 200, health
check timer firing again. changed=3, all health-check. vipy changed=0.

⚠ THE BIG ONE: the playbook would have deleted the mining integration.

bitcoin.conf on the node carries a section that was hand-added and was missing
from the template entirely:

    blockmaxsize=3985000
    blockmaxweight=3985000
    blocknotify=killall -USR1 datum_gateway
    maxmempool=1000
    blockreconstructionextratxn=1000000

blocknotify is how datum_gateway learns a new block landed. Running the old
playbook would have stripped all of it and solo mining would have carried on
against a stale template - a silent failure that costs money rather than raising
an error. Also dbcache 200 -> 3528 (hand-tuned down; the calculation wants 90% of
RAM) and logging moved off the file. All now reconciled, dbcache behind
bitcoin_dbcache_mb_override.

bitcoin-knots and datum-gateway are ONE SYSTEM. Noted in the README.

AND MY OWN FIX MADE IT MORE DANGEROUS. The `Restart bitcoind` handler was guarded
by uptime_kuma_enabled, so it had been inert: bitcoin.conf and the systemd unit
both notify it and neither could restart anything - a config change applied to
disk, reported success, and never took effect. Ungating that is right, but it
converts "wrong config sitting inertly on disk" into "node restarted onto a
config that breaks mining". The ungating had to land WITH the template
reconciliation, not before it.

It also raises the bar permanently: any residual template/live difference now
restarts a Bitcoin node on every run. Four rounds of --check --diff to reach
changed=0 - the DATUM section, an explanatory comment that was rendering into the
deployed config (now a {# #} Jinja comment), a "# Pruning (optional)" comment the
live file had, and one trailing blank line.

The build path is 32 tasks all guarded by `not bitcoind_binary_exists.stat.exists`,
so a converged host skips the 30-60 minute compile and both `state: absent`
deletions. Those target /opt/bitcoin-knots/{source,bitcoin-<version>}; the chain
is in /mnt/knots_data and is never touched. Signature-verification tasks copied
verbatim.

The health check timer had last fired 2026-08-09 while reporting active/enabled -
same OnBootSec + OnUnitActiveSec dead chain as fulcrum. The role runs the check
once after enabling to supply the reference the timer schedules from.

Ownership parity checked mechanically against `git show HEAD:`, keyed by TASK
NAME rather than path - keying by path gave a false positive, because
bitcoin_knots_source_dir is created with ownership and later removed with
state: absent, so whichever task comes last wins and that differs between one
file and five. 13/13 match.

bitcoin_p2p_port and the tailscale hostname moved to services_config.yml for the
socket-proxy play on the edge host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
counterweight 2026-09-13 18:13:40 +02:00
parent e83191c029
commit d26dc78b3c
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
19 changed files with 1163 additions and 1250 deletions

View file

@ -1,174 +1,178 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
38656563383931366464306463373265623631353331376532333134313463303635656162373437 35333539613236336636383331373761643732663835346539653531336662636432346132636539
3735623062343764316262613966353338326535313161360a323831623936373966633535396632 3738343939626363303936646239613531306461646431630a656362666266356534303466323962
63303961636566646338373464336637323830663932653039306362653832306163313938396135 64626235663062393436356165323364333735396530343435373730613765346466386336653030
3633663532373362390a333233366636666437626365373732633361653833363264623138386661 6234333131383036330a663039613363656536353164323265383130333463646638396437356332
35636665666230326164343339633834616134666531343839623134343163333864333834303862 65653330383235386563623231646535343461613833333765333336366338376264666139303635
37313864303335326133343666333733363333663336356234633332323262616530356661316363 65666139643363356264353234343736623731656534636662616466313764633763303035343432
62306338303966306632303531613161386135346439333137393062343938303134656436656539 32623965326532353733656533356566393834343338303833356334346533383531393435363461
64326134363664353165616436353635633265643161383335393633383563656231336139346138 64306561663434353935386165393361613330643163323564383835386438346664323663663564
38366238653236623664313662626566373631633136613864373032316539646332363035343865 35623032646362346262366333626461343364356136373231313635353665643838666336313766
32666664363737373962396162313438303030613264366232373030316335366534666531646239 62663730653030326534393838343139313239656530316662323638396230323436396431306135
62306630316432346131383738373764313263363039376435653062313136356531383534343831 64386263616633323061373331376536343261313330653061333662373034353564623934376235
37336536313564323336613639386138303562666437376238376630623665373230653232396261 65363432316630636132613935663466366365613265326163383832613631303631616464633161
34333433343361643065643032366433643137396231343331326362626434643365356131613766 64373661313034653338646537343164623630643039353533376537636264653261393464633765
34613039306130653535653330623333333631653538643536616530373538386332346132363739 38376436366262373663303137343861383932356330356239326464666233303064666634623135
65653135306663336163336263376332326230616238666365653663663462306238366466663366 66373430383061643463386265646666333962366366336534646635633365356334343238303930
31633833333465653534613863643465323631336661393366356363386462623434636631623738 65316432386134353838333033386164643165366662393365623839616265646538333235343237
30376265663739333336393664626539353531653637303464316562613436373739353039653430 63373236623963393937613333623630363032643365613561653638323030373435353639366433
36353034643839323131353033643866303333306435653532656239653061656235393536306463 34326334643330336564323439656630313331623762373038343133613763643838643039656338
31626162393462356238323737313933633465623566646161363964393164393762626531326138 61323933643764306339383733623939346466303636616339396534643434633936393563373934
61343336373065313232343064646463346638613661393263326265366539623861623537643164 66646632336133386163613135363963363338373338323732333563643164313662633639633130
32663365313161316464333137383337656662323137356635636637326163343562323965666166 32383263396666333639626366316630346333643039666431323164356364346566343237316166
30396531326364656461613232653361313061623835663663643861306334386539626530386666 62343464373564303533653864653164626239383737303235353638346636356538383661643931
63306331313466623163366332326564353639383961656362633435363065313830613764306237 38646538323431383638653532303163313032396164353139333461363066393566303237386239
37303530643266646464653263306432313766633835343739636261623464366536346665636135 37613236376636316136346266613530363732353232313037383830313461393136306233363931
31333638306237623535623439613636363937333430633831306162333466323137323932663432 35663963613630616530383865633330636434626230333563313362623265633637333261653632
35616135363134306231323933303635336332376163303131656131376131393465353434353330 63303130323737633365646265393736613136383536383133663538663466643631626139663865
38623339313964313730663263373963306337373938393863323062366534613131623764386638 34333938363430393763653937653561376362353633303962643637666162666538316366343132
65616463376633663864653363643135623663316439346336376366346166303962633366636565 31646163626465643463326333303365313138626366363861663530343362366663323161656362
65373335623962613131336364396133623738613364383639356533316138383333353464616639 31623361323033353238623462333031356265343239613834353864333365626636316531313238
62316161656633666431356462313634383239363464613031313232393131643936333237616364 66343633393865316535316262376338346234633737366132313938356438383066356465303239
36646530646239626662386231313239396238323139383037653337376134316535373464613235 64326261333935343337363331373366636438623966373439653432663030376236643664643865
35346439646234623462623262336461326434346632373966626464313633343266616463643764 34393738343865336263666133613765353162353839393633346439356665613936643863323464
37633830653230666631383134313738326265343738386631346261343439356163353262626161 64633462366565373532333336376666336263396362303639393061346438363035613534356334
37343134663764396439633535616537386638633731643164383064333266643830356563383066 37376166363030393237373464356139343336333939346662336332336639396432346665373137
34356161623361623366363435653739383438396363643338353736323139313661373031396132 63306539383830656363383539303366643335356133353738373266646463346265333733613030
61373834303439663939376339633832313639643332383239313337666433623435613161306139 63383036343663623366653763636135326561663739303631333936313161396335373962643662
62633162346338663335663661643938316539316139356165346461326433646366306134356338 31386331623466666262396132636265323831646333353038386131303033626435316634666662
35613934623666386463356536303362626466663062643236346163323337616232323535396265 36353539383961623535333730653537633932613366653563323339333738643131393338313931
36636165656366396136666533626433363562353537343430333361643635313335336435626265 33373964366638323239386130306666316333613233666337623966303830323637306534653430
36663233383265636530313332336562623833373930626136316265393634653466333732666563 62383634303736636166376563626537346161663432616265336364336264373638306364336331
36383037336566373566313661363062346431343534396533656135326534646161346639383336 35373862653133333637636164343030623664333536656433366563376330356431343962656162
35306633303836346365383533316661613630326533393836353036636132636663653530656336 31646536626631666636383033336130373565376430386639313135373765383437336538313266
35656364613130633761666632333633333137656637353362353337626266616238336266306636 65383038616139663436323833613232626531326531303937613931373566646263643634343461
61393932343736306465666338626365613531386362376565383738366230333465663137343363 63393365333839663231623532373634643136383333373166356635356666353837383331383334
64336661343563643136626362303937653632316230356531323231653063306538616633616265 36636465316536313765326562336539663539613036373638616633353936383866663231356262
64306332396639323461653136356662376236363861643466633466666265646538653833373138 65313965643263666163313638626335363333623833656439633464343864333465313231326164
38623130633037333666623862636165666333366335643765613834383533343436626638356536 30646530363161633834306633643132306562363065323032383066316533373963383763333466
32333939326532396339666637386237303730363332643861316236613634353230353565316239 33613230643633346566396165376665366361633733366261306637303964376231303365333165
30356135323237633963343461376233656333633636303662333365333735383930656538356238 37366633643331393537633563626164613630396663326233383263343930333232656265326633
31373862613534386464333865653361363663373664663234346636316262356137613037353135 62373539306331623332386637646333326435393933323632313166386365656561356536663738
37656534383164363131613834633062656437373066646336666533313033643130636361383038 35363362663937363661636437336532646437623864643463346238636331643935333264663365
61336366343230303036336563663537623230643061383732623865383134366535353365346363 35353063643662363939396638386531386265336566373835646435353736386666646531373361
33373331323831396462633031353665363033346536306334366237646363636633353732626166 30646136386138323530306135666333386437356430643262363234616366376335633638303133
66363938663861616461613562646530656366333166303264363030306139343161313938613361 62316562323463346263323934363937336631656666306237626438626133346566613662363831
66376263326131626132646530643439633634303539613863623965373432363863326130616536 65623561373231663262313763623965663036376631663662616634353664663762386666353539
64626336633238613034353166353664363230393732366465346363303537336161623834333265 63323237303362393762343832396463343534633432626532363534396261613132323633353938
61346365393964393365656565323331303265616630613766656239656438316539636632373038 64613333316436313063313561656561326139623736373439363363393632353564343361396666
62313139386233633732643765383039646534326236333134613531313437346161343638376432 32623938383737623836393536393838346131343762353463386339336361346266623663353262
66336432363739633231303138383338313164313930373866366431316638353761323531333930 63316362363736376639333638326433383662663866303638376662616335653764663631616666
31353136326630363038626135383939393639306466383832373630623565383766663736363937 66663738636162353262373034373334303562363236373232306364393335346139396663626634
38656132303738333863623262656131396366313663666461666231626364646433613137333062 64373735643537383230616661323238333239386330313231333833663062393832396366373337
32336661373236666235306534616535323061663634383763386339353732646636306563323632 66313966356261383039623630376138643261393062393030346131663839346437363766333732
34313433653137613930363631373666613330363761333639373630306537343633643561366231 63303136303037643931663431363435353261343133386332666531383835663361376165383632
38363833363139666631333431646262656239316138373339326533623437383336353139646431 38333963653732613462323435633936353637336538396531616437393131333631663335613931
31313833363733653534333133633636616636343635393039666233383661666363373263313631 34343236386135316336353661636266396434386563656433633935336330366162363563313738
34363064353135383261633666316462356231616163373634383730386536613462346535383331 39303561323739306362383765303131623265626332613265323264393333356165326238633031
61336632643363306435323866346665626464366163343735616130613335663235376132396663 33366464626537313662333166343532373735303135306563393737663536363862336232613435
35363635663664626638663331366131646333623533613065323731643366656562353138363335 32613031396562333939303566343834323164396165373165363932323065623839643035373539
34653863323337653331306232306133323666356464323932323562376632333439303537306534 33363362316162643264623937353066303536623962373433333430373436643862616636613537
66346462363535353961383061323762343237393535626638633365396566616636616236396462 66653864646463653435366531373039373663333964636163633965613438366339613437613731
38353433393631393338646338383830663331663538336465366161653333373736623063666437 34353330616337313037353633626633633666346363663764316163653635363335343237616666
34633365383736653230316631636666386664643731323434613761613139666432636236653137 34663461616539376463613635346536366334613536326564626363663661313038636562303031
30393666663261616332323466353161636632643534386131306632313236653063633531356564 36653837393233333234613131633735313739333263663532623563623231323239343936333831
66353964393634336530396162393862653837376436623738663135303632383166613333336165 64313661376164323738316136623261353538323565383865376339366466393033373065613835
62333434613432626264653865353035643563663435316233376465383961303534646339373632 34393339323839653430653335623664373534356232386262666437393234616362353438386361
31343530353636343238623565653566663936633763323861383231366533303164316339653637 65383362346239626438346135663064643031386335633533646433326631386439353731653663
36393364616365666335386539653439653735323162396131643931333866613862633437333438 33326633653363313232356233373531633737383530396439643139316164626566326164333439
34663233356461383537343738343134626532323361653666633733353939333065363131316133 33393163376162623938383264653337633361643633306666646163633337366264353939353236
63616632336130653962636236336264363565303839653531326264386331316264623038326266 39383035653036613463643633633234623439626365633761643038656339373362333238373033
62336233303332333638613461366231343935323036366536383639373837616638616362643331 36626563373563363139386336653764623661633766343965346634653135306137393361386539
35663331653133343661346635613036643065303637613964666237353166386666313439383936 33656261333137656632353739346462326364386330333536636634666538643461373766316165
31663730356636333061326535316638366531656430353633383663336535663830323063356666 31383238353730356339353934663037373865363238373339346238623364383631313537386231
62333762393865333132653161346361313832643163356265616133373663363836303662613935 66643937316361333262643230343965616663393430303661623161323361643835623862313564
63623662313830623434303530303833663063336164363836643531323239653966366233373266 30646631396564383932633437303464666166636434303330303934613038393130666561343837
35373037323132653833646432356435333834346138636133633339613165303362336265303065 34376164323633336432333664366631326239383463303366363763383062643565643464633634
31343931386136323362376431336164343931343934643031336435303738393764613332393561 66313264666562626339326133623630366131333232383333333961323234366633313231376134
31363333623165643363646638336435633539626635656536323030646130323734643134336562 62653962303630366330303537383639306263316630313862646334393531363439346233313462
62353233366533363131313462656239366337343532336332323563343931376237306231656532 34353937303230373931616339393861323138333237633861326165346631323931633234346630
63326439303930326563323238613538386435393735356438316536373064643465306362346135 35656666623261616564343733343764383032373733306466383763376564663665663731303539
63646532343334323538343838653764303332386139313239376332656664316361343536663766 37373863613135326634333039333932633461613165623938623338623565313332376136343436
61363065343862373165366563366363376362303862633037373763663132663631346562313161 36303037653935383630376362326335653466343233613833666361633661626437663563303331
62636635303738393763373232643862386135386537333637636631626638363232323036316366 32363331663334616338643239356133396662633231396436636630343934306333343539646132
38383235366333363264653163313937333566633066356663383466393535333535313939326266 65366263646563386563643562316337343130643661633730663664663564316535613531353165
30626531386333626334366533613366353433396438313838346339396433666436663961643438 32666436326530323961663736306162306633393366306532613266323633373330383634656535
62633336633066616163626232326334633265356532663535323264373166316133386466653131 38626138633335393266656638613765666665313561363231636261643936333033383533373366
66623261333964623235386433346236353338363961323230356633613864303735386530303165 61626365636635653834306539303530383330346630363766383734346332326638316561303763
30646265346566626562643330333233636164386432613436383034623337323531613735656133 63646639386366616230333263313130346663343663623536376664303364623064373562326466
64653232343839653661303662336435653439663732303638323732333064646333313732356339 38383163326637633937663161393538616339326263306463353530303630333937326138363239
31303934613938326365656161383262363633373265616466616562313237363763613265376664 62633535356230353439623234316562653237613130383832343735643661623033316264653362
38636534646237616332653531323036313430643862393362383630653339343931376164373735 37633065313135656637616137653963623331323863363364663761663364663565623535343366
39323136653730316462643964643939396662333462653934623136643839373864613335303463 65313164643461383436623038316466396632626661373438643533336234323132613866393134
61643765656431363734616435343564393663346535636134383637653538646336666164336339 32366363613338646131663738643236613562663262333936656461323336303139616434333334
31353230656364633936643338613563306639316464653864396230626263306338323639323238 38653133633232343164313661623466643061383161303564376638373138646431343634393962
35396334613039343734303232363962653164636561633164303132366234376632653339376538 31306564396262383438643937353563353663353536373032353263636430363235313736653333
37366638376666353733633132636131653462613732656364316530306333313431316164663839 39303336316438616365613961653737633234323131356339623265373463336662366336396364
34646366393835353338373763333666646535363634633864306433316135376663343833613435 38333962373164383630363866343361376262316462333936616230316536396363316163653463
37356636346234623735663361336366363264646535336566363933653832613039663161663762 37306461346136323431323265383030643232633062386433336261316333323030663234663063
65663234666437363834646163643733356136396464633830336533366337303438313665336166 65623434613662306137396361616330333233386630313935653861333761323565646237343430
33376331373032316464353037383433623334643965656434636134333166323238666438653337 38613139663035373563313530366632303232643030643466346531373333363337643831663736
32306234636661656639306464653238326536376661363036626561386630326239616137376565 62636538343035643464396461326363646537393138613166323762346539333033633661383531
32666438356161336437646562373534326632306165666439666130313036373262633164376362 62653634636666343661353565363266303430623131643733633232626230623466376337366137
66646639663663323134626636313130343362343966653564306265623630326664336534333037 65653565626366373337626632346338396533343138393431346333346161353838386434643863
65626562666337653436373130613230656535386264303132373634353861376238386435366636 33383935636132343764656232393335316431633937323533313338366461376438653136363231
38316637613036333836356536306132626631326562363535613835313432353133373138613264 34643363356664373765376465333534653137383961386262633165636666353464323261396465
62396261303239396364613039346135623437336565663034313264643535366336653363336330 37353064353530393037303930303430376530623364633832636434313264393135383536306438
31623539396435643132383363353861323064336430653936623438303933356562613335643861 35316436616536396335393863363863653763303666653161383630336437653663636434366635
39663437333836383331663830626433386431383338373261353266386531373931383632306135 38633633396132623663323137643338303038393061633961353064383765353735393432313766
36316339366539333730656638386635333733363764613364303563323665396336613930346233 61343735363538316134626434326264383932393964646136306537313932316238326362646337
34333433323030643262373636663838343131303637613237376463386662303235623338393063 66363234363334373737623361616235383231303834636536393836373466323265653339326239
66313166343730383961363765663463303266383938653638393830613662643362386361626132 39333135396464346232386362376335333234383231343533393264346335376133313434393633
66306533313461663131613565343534303735366232383164333837363330626534643363626164 34623039373134633032613838616532303130353833323330646165396631313864643831333763
33326134376263333530663631383930623066313035373135616665323564323033323639623235 35633831626465316533346431616362366331633937393037666538633936343964643735363733
35383538356434663035306137366437613537373531316436336366646165346330383538386331 32393939303931393362656332386234323634376534653435343137353063333037633033616639
64666232343961343261393339356531363636303165393532313632613363316665633233316330 62643037376335316662613064396339393639386336616362623963373265383231613063356335
35623939613463333164643736313531666531626232386361663435653938343536363236616431 63633432623061366237636134663834336165306234643537373064633561613561363963323031
61343430363861626339336166316135663234366132313762616230393239663931656536306663 36653439396163333439366534653764616361313633343763323938636638656461616261343536
31343366663063396139336237373361333030353333623064336262313465316538623438313265 37653866346161333533323436323063626534313539363666636232653639343366663663633162
62656232613435643437373233396566623537353038316262643239653432373863626530323334 37343539386163666464643466326562363566316630633530363235663732316463346232366362
35633132353463356634633237386134346532353930343339303337643637373932666665313561 31303037316265333862656137646631616163623330616565303933623731393530333230616533
39346531383663663131623863383832346237356231386263656566653631363836323132333135 33356638303132313864343938313336626265656362613633623639653537366664383265636235
37316135613730386362666564643037653366373464323431303332306364373432646338333031 36303633343439643339653833646536323161323638613139613734396433656365613862303932
31613533633664343038376533306235393030646236346232386236653138636234666561646263 31353764303836653434653637653732363464373238376637393766323661333735363336336662
31386633343265663335323236346435653261363763366234346263626663643964393962343766 65623030633433333339306335626334396162626161373637646337313535666431386432396162
63656237326563653633383461333364396165626138343461353963656131663265313835326465 63333761363462643335633136316139626665633838613533366633656461623064393963346366
65643164316537333531363139623732376364346363613363663066663733616665346233633662 31656637653436653631306230323630333531613465663134393339363930623263373031363839
35343065316437373136656235323466343732613335393761313061353432623664363462383562 35393931313234393761303364386161623065326661323566653535343735346165643961303662
38333139636336366462326565383631633864633165613332343833396237336561346164656664 63323436663930663031366131333361316339356463333634383937633535616663313333313037
63316463323233383434663061633564666264313261353632316164643035306234393732333435 63363363643764633735323331373931396534646131323166626537646638333230346362656262
66623663316334373431633734323232313436366364623037303965366663386237343439613433 64303962653265316530663531613235323165306565613866373966633038353237323933316336
65383763393061633431303736656238396364343765363463333433313836386666613964623634 34313566383234326233313435336665633239666531656536326230373536666565636336653964
30643065626437653966393237326433373936653861306536363834623363613830343036363766 37666533613165666262656637376662656339636538643639356435356332323964643731353462
64386234653331363564373065343139623965646562373933333162386264353832303164336362 30653463326462373734313535643436336432623965616637643537666432356264666338333364
33613036666139396533333862316366396464646465346263623730313336663935356139663762 39353134633761633461346665353161656436303764343661343530333532343739623830393762
65623466323239383732636165333564356534333939316539663366363065623631303933663863 64653831366263366664323534646163663761633335396363653739386431303265643865373830
31393637643761303731646638323133636464623366363032656335643435373064666463366365 35663930396333303430333831666433616366383366333032383232366431616338356138393533
65653831666262616165306537623534653763636633633137653733323234346266363630306434 64613863383631333231373833616230343930393531646535303333376232633162333136646431
64616633326266636134343536363365393033663934663965323537633136356535353436316634 34333639663032656562646561653061313132383832386266613431343630386530636362636330
61643636303237363033313637396533303761303536373836343332636466396339353065386539 62626537383961666664656363343830376662306137336433663162323233616466386438653361
38366530623332316439393633356235386665636364313739643432623032303363613666656264 34343138396237633138326633383335393330653231336238666365353530393232323332333837
31353063633862366638363838663932386131366434646462313130366633643430373230313338 63666462613637313738653136333131623436653033396562373462373665653266366237653932
33383362313230373137393934323561343064623065353063653535366266373237656530303335 35353939316438626233323561336230333330336632323062363436666239613137316563613062
38616263613232353632333361383030626133323261323033396638666231396638353537383338 62393138373036636461393364663934633439623837366536386132663933323139396435393932
33393466663938356363623438366265336330313039313666343462356331626265383565623364 66333662343965323338623531633562666631343963653233333637646565343634373337643636
66323835303365366333623733343664626431343663623465326235363430356661616166346630 64303566643537383633663736393037353635303335393436643634393337396434393430656131
30336266383830336461663130616363663637653964366634663930393066633134626530653766 61643830323039633363326565636139663534326434666161666231623434373963396161326566
34393439363332383831383865393464656165643331333661643138663133643133626236333363 65626636353537343465343062336239313537376462316161343039373032373237313462663032
34643438353037346334316233653034313737616134653762353239636234383233336338633031 35666335626337343334356530616236303639383035333362323035353862303863656331643630
32386332656530313361393532623661393538633463393861636539393666626362653031636566 64663864653066623938323162356631626537663463616464663134613836633033626364313732
34616265353736633539313032346334313339313934323962313463376664373336666236346633 66393065393365343339376637313362343130396464626363346330383164356538363833373430
31306563633966653134343937323839316137356164373338343965643934636631646666386361 62363030663639343934613233366232363637323165363434373262356336663037306163663636
62363165663838626538363966396161363366303162356664313437613034636531356638333237 64346534663833643932373733316331323032373738313637646464363563653932363735316639
35613833366462653834363261653365356336643635363831383930323566623262353865653233 39386433336435316331373330343065396433323637613566613835356436333631323833313866
63333138633466653165666236356430666532353639326261613462636161636634613235353165 33373332323632393239633363356232346634303233373663646536666635663233396335353733
38316566306533373138336334643465616339383739653639303632303661656135313039303632 33336364646233626564663938643230373532613133343439636363323033373461386463643763
66613966633036653461396330663630396663623732346261653265343233393730306537363032 36656234386563666662373737633537656262396234326232396636306139393532623531313431
66653737306431343435316433646164303338353865653336303731636663303863363662333863 65663338663639663462323932653661623436306431323464663430613363303463343236326165
33323334656631326137646563616236393035336539646563643064663564383736343961656435 30626635366639373331663239623763373966323934623365316563383039383737383262353130
36306136353037616634383866303636383531616136633230346538336563656366393466613262 31616463353364353036313863316165656231613664373237373933626331316638373566383139
32663266323333393764616561316636356664346265353433653262313239326264306434383030 66626634313234306137376166613939383664653536386532643636336466623132646639363564
34356263323331313364653966623630326433343863643839313165313063626261646339323837 38373963653337393539326162383535373535376334386439316330386136366337393139336264
64613838353334613661346662346636313432393837386139386136613366353038343962366639 64656337383235383963346335306632653837383166653737343661323237383065656137393232
32626265313764613733313334353432346434323439326637383462313863383165303963353665 66626261396261383466336361343730616336626435363536613730313635323761353335633936
34313635623766313361633030616439343433353735326433383563656435393563 63626164316462666461343038636633366136353864323135346335383034306464373437333062
35626464333537313639356662316366613833343365663132303266333538346562326562323434
65323230653334336239616163643036653537643264656239303666343430333765316631643337
65356333346534623466343439333932656332306564613065656537386232636662373665306465
6563

View file

@ -1,174 +1,178 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
30383238343938316437303961393961633538303835356661366465306161353738616335343563 35383939623164356565323465316566346532343163646633323634396364376462313461366439
6135613063376562303539613535633463616433383239380a323163346131633838393836383539 3637616136336262303234323464343434643234383132300a333665333836653636393166376330
38623766303739623131613935363037323462353664386563356661393665306136323863656363 36666466393762346333363930386334333863616265363661383639333561393061313938373366
3433313638363731630a336165343563653930663435333037653330386364336530373830346336 6562316232653761340a313631633931353736383636326339656432333065663032323033326334
34396361653637626137343033343432303438383761393765313164393631666230616537366636 39646438633330323662643834383438656134376363653938356639356338633635663831323938
33313234636535306535336132373830383438636235636466623861363734636238393234316137 62653533613861383536346230613161393834326637623636356265633237323331323565323339
36643439643130363462643765353061623436376463386139616435323136376366653932323766 61306565663831613635656661373535396564376561653035616362623333386338666432346634
34393161353062386666626633393639623434653864383439343339363665636134636139326538 33373033333737626534366164306436363932653231346134616163633634633131646165316330
36323966373230363938623434336161396235316532663739353837623238343862633032613264 65393031613461623762383066626566373733666639333766643131396433306637653063356361
32626565313637306131393466653739383935646134346330333835393932396634323565313861 35343231356534626661623331653365643230646566323666633031323734663933643864336264
38613864656139646261343835316562323863363836376266653139336638366161323035373265 61616333353139626462623933343234386238393437623833363461323834306233653061363535
39366566333136646134353065653065333337303832363237653361353234386335643165376331 64326339356435626265363235313965346165353434613962396465346265346539343764663733
35316339396130366163313130633561643062316164376262353131323237303861666263643536 31343234356331333536663239336334653864393132666264383263333365663464663931626562
32333062316330313532343832336434653664656565616634643436656466373533376535396533 36343430656262313962633965326539633834306263363036343562663132393537343863313961
35626636393135626539633365326364353462633462656364316361303732643632356230643333 35356161386234326361626165343234393837643364616339666131343364386132333763623737
30396233616633326438393836383237623636383464333830343464343837383231653139386336 39373035626332613566396532343535646235636661663263353338633763666363666363633465
65313337366665343936366430623162643032626430336466643230313530343832383730303263 61353566646261376534323662363062623962643062386164666136623966363535356132656562
65386235633832643931656562303561666131646362303533323430336235643436653866366161 65653465373366636533336539333035346537346261633933626334356631393461373361623537
64636365633731613365663833663264343233313037326537616164656231656332663461653635 34326463373766393965653639313063383764313736626366653063663466646161313365306532
31323237656361666630323930336630626437393836313431353839636435363466376535633962 63353566636433346237393834386537396232383961613932666537373565653338363435383938
63323462626662616139653665346132343736636361643930333366666237303438356364656464 32333438623332626163336631663664396430643566376363366262656432666261383039326431
36663363386131646361316535653463366234663062323539646562633962653537383465366439 63633036393634646237393665353666666239653533393532646464643934373535666137373764
36343635313934353063373734386137653239343538663037646362376434383234363361623165 62646535613563363939313666636466623762636439323237623236383165666630363938393666
66663734313133343062363137323931643338326365346234313835303431613632623461366339 34336439316665326265623335383434323837326661343163643833663330663834376432333134
64656138303166356136313962646133306536333465316239383532353362333932326639393363 32333737643364373035626430393963373934316663626666333837666161616138633032393663
63393430373133316532633562386432663332623934376636306438623061353238333562313737 37323432636435383462383061346332373862376336323363303031666336646161633539643033
63393338333534646265643462666163356365653937643634316266303730346333346465313662 37633962356130613138343235633564393330373463613861313638303633326639626436613763
33326638643639326361386461663931613766373937656266313964336461633939333535646231 61383236643439616232613331366535356130373365643064366533613330383661623833303231
35316331333537303830653336373530353364616161346232323130336137373737616534373435 64353532646337643630373361303564386166306639623137643534376631393731393831383261
35383466666262333834323332393737613763303562643232616432316636386635383934373633 36373934623337646234353165316563303336373437626464356463383733303338643936376164
34316462393064656633373562333039646135373332373063653539313230646466326233313536 63303638313766333832323764666431313937633930623865353331616536653930653336343266
38346238623162353338656437336536663534643062376138643030363935336461333638363134 30333931336165393634633231376266373933646661306138386631663539336139333265663631
30653738383233636531333165386131383061363466313736336632303136616261623137313065 36333562396239623236336333343935663866363063353036663337646431356537373434666331
30323766393862663965623337303638366239663130643638383765383930353533323635316232 39356635306263323365333263386331656636356436373862616434356462376134363034663532
34646339366162653663323964363863623962643166646130633236353563313061353434376334 64333633663662623931343363393233306331303066303664323034373333656132386437366162
66313862313265653238633034616530343164303432666539363733666662653733666462303662 37633830626362326637623139396631663834623436646364363439356361666661396236353739
65663638653534643132353361313130323763636338303836346430623664303732356636636232 39333766396132616333323566393936363137333235643739333639646234313266303062323536
62396135343236646537386334373166303663353661323236336365336533613139373430333364 38633964373238646534626566366438633364636461343861303437356562313966626235326537
65363863323335353663396366616530633836363837653963656636333264323434323365396135 63316438373461313936343634373835306539333436393337656535323662663936656638353838
62613862386361616633333636663263376465613465633362333733326665326639663961313631 38316234663432656539636239363861396139376264303336356630396163353234656562633362
32653735353563366236363936343438623665363834633436393232653737623436303237376530 39613032653163313362643733393232316530613533343535376339636139393936616263346561
34353032633433363865303866643761343130303431326236353332356464396433323430613830 30356134313831316364643439373135393836303330303737636137323035386432343963393165
38373035306137363562376539633863343737616339346463636236393537346163323731333733 66366333306262353763383838376662633766636532643064373962366665313761646336303033
63656161306437343862643836633539326661653062383361613739366237623162653939366335 32643633616162316537376435386536316431343136346264643163373033336463393130383562
30613466643665313830353332393365623933376638326534336664616561363461643237386533 39623635316333383036336538626636363130353733336531396132623466363933333230616364
64376532306663373934356361663832323337393266356138343236663964666637343431663237 30633364393334643866393332346239646235373766346562653061633732326537343634363065
62303531353266633164336363356336616332663730663933353730356365393866313662363730 66646662336661386432306231313362636535316466656435366639383030376365313364666564
63346434663162313333663738393461386638343864616634323938323437363232356466303637 65666535663532383662383833633261343934383535313163643133646663396135613761336337
32663630633466623839306537366465653164616631373564366132636165346231303065653036 64653433366164373461643038353830626139306566643438393933396339616361623062346536
66333134336132376232393639616163393366343365336661633330316436656163396434343963 31353039633437383862343865343133336665633436366137663033643834303835336633616361
30356331393432613561636562343138643062613738613764666232656639393532623433343138 30363863626463333437626165333338366332653838663464633964363961373338336462376332
37623963303237663337626661656638636364323931643730343535303737656461663831336336 63303738636539396635613938366336303462326564663937656231346639326438326561333430
65653031656633386562663837386130613635306438313764653830663966663232646663356132 38646538353362303062376138636362333166373931663036646438663937326438316338653861
61613338663331666265393566613661653462323530623930373034363363363238663465303162 62356365633966623638626138653064663835656431613262393532623731656132343864663966
39303465613435343934636365336262376431616136383538353862323235643835373638663832 31373936333031646131663436323036366637326134336132373565316330663066366237336439
38303336306665616666353963653532313162336536336137613337653363323138626338333861 62656562346639336339363363643933633566646363356565366336633863636230316634663936
36663364656463623337663362643936393664363937306135353464363061393837346161333435 38626662653131623064373639383837366538633339313864346631633032356362373035303665
63343030333830626438653565623065383264616264303035613432313266643739333063653066 61376332313532353665373131613335653732343839366365346330363638366265656139373838
39623863373632363337663065653865343433393333386633626237393162383338343038646165 38633737653565366165306562353333353637326530636535616566323061386362333266383636
30396331643033386331333039663066356432613733336235353266356336326138323864396132 61636365386232306338663962633235613435613466643032323363646232306431646164633639
38313164393833343339663363366438313931393232613935343063306233323061363066616366 36383139313363613630616662613734636465646130363933376438633839363163343866323032
62303564643930643262666364346130363530363630306331393032623736643630376563636533 35356531376663386331666238656537613164633634633934616462383331326633333235626337
62656338343734343739383565396339323138666265626235376235613963666566333862656533 33393330303532626132393239633735623963363562656163383564306461353330376532396334
63626566343737636532363535656238316332363831303862313265383936613339616430376231 30666361353862356636636632383234323565376235343862343564383830326533373861303437
32663363613135626463373166623063336135303437313031353337323939633732396139623731 63613731643964613530343234323661636133643838316564356338366566303261336330616432
36653061313233363837396636643234666439663261316361346263343934393237626134656230 32613535633630303132313933393833636433373539346261613661626135356363303930636138
66326135396661383432323939666662376163376233323339303939336363336531653163633464 39323837383863306264633838636530393632363936633938626465656334336333333961666331
33346266346533346631393666316239343463366636613336313833663730323734613135343930 66653463343333326563356337373732643333333065353436393736613038346636643535383466
62613130613933656237366262363433353434303763326564333965383662336661313037616430 31656535633765386339633938666639396438326638303961303365323032333564636562343361
32643061313638373931646464383465626234323866386336313861336531383638363736633438 65303662343633343364366265646432376230356362373465356539623632653663373631633633
38643662376364333564383963613339623964396666313263653336393666623932393738656665 38666138363837356331343061373237303337656432326633646565353337393238363362396238
63653234316265316535303531646230326530616639653036653731373934316238313563313338 66633966383237653064343333396661653932386536383536366632326234303161353166633836
62373162346333666634346362333232373234613430386237656337353661643839663465663265 37313438393263366436613066386235343034366433343432346266343137346336646238613462
36303738636137633636646537613336386230316334613739383362656661643163373936663130 33336339363037343533616166616565333330333531643364393437393637386330626437346135
37393361323837323032376464323961306335623835616134633735626164306539383936613064 64396334656664336535373764666535373732353639326433646561616338323633623138373832
36653133666230336262616438343539346561363863653364343662356233633239623765383165 30616363303834643532623362306362326230323737653563393838653234373861373933316538
30336635393763646432396437613838383733626565353737336165626333643339376432393366 64376430376161316666396336373662393237383531353361393435386236636631613336386566
31386334326130346164633534366532363037316334373133326362303965346633633939333539 31643637623333623364323734323961643863623532613432386662363361316134626533666339
35613435626232653733303266666431666133366430633538623931623231353235383364303765 34656130633462616337323938626439626235306533336264343138356439633065313434616132
64376133653562336631326630363036623033303039363561643236653531663861336262393865 63646664343962373365663738356233663135653965326534353665316531393964636132393932
37346633626334313736303831633236313562393363313133613836326137303435356435613337 36633638636236326135323335646535396266666433396462623963656664336539386662373233
31613335336562376435393237326439613863383264316537353165373437333866666364316366 64363566363863376466316338316562393461623262393130303762646334336463623632393238
36326332336335396430663332326562613235623338633930633437663162643433663065323234 65656138396536373132363633313636643864353266356266626266643737393366326538353237
36613663356534366433383431386666643736323936383030396139326464623961666666323462 31333961376236653263613930613432666531366131623834633632646332316133666530646139
35613335633666313330636161613836343861313861666530323935343961316631666566653565 65616466646564646437333730383836656566643465303931326665343764396137643338373631
61363033306338323966376631343232343038393564616262323532626131643265303865396539 62333266326265356562656430666538376134356239666635393430343234363231323938393331
62363433353666626666393331636537363535306534383634333262326438366463363138666230 31613463613936656138623535303731333535323130303835366465383665353632636138653338
32386366303462323930343863333463383638653532386362323338306266393337326535363663 35663132386634313538326130343435313131303934393434393736353531336261306265303264
36346366393631396163343930626537643161353038383934313331363834323431653364303939 39376537636566333563393032336534333635346432663235623530666264323930646361313463
37326532643864343338626430363065353833353862353262336235336637663865653263663339 39343437313932323064666632386137353834313930343636356561346535613730363865613433
62363366663838366236653364363064356137346463383933626533343461356162363062653932 63316133663935373238373566326363343130376666613331666361326262353266653535343866
37663966373031363133326534623763643030356335386139363565613135353835343233636330 64383931303037386165663439643232656139653832303239383235383637336664313864663935
66393532396530643532626336303737306134323537373135663435376632343331323663333737 63366631303536336530366438333762393839656435366161353838303732386466356238333632
66316638396563626663313636386566363036383663656230336530376234376138303462323030 34646463646535376139663136613562316166356138343939633935303532326536313033643639
61613931336364383265366234393933653432313562666238666639326430376238623365373838 35653765326234333832366165363962376263383465313633313664336636616430313138313365
38363339616365623065376438323738306633666561326432303935393938373638613736303332 31376535613130666562336533396636646161633932633030363437616337643761343439616338
35353833663431313462333362313732353534383630343030393564626139353139623530633332 62333332376465306264663137613265363432343538643430333764326562613065663062613665
34653639386263313738613430323664383264646632633062643031303437636262623966313630 63643030383163343231353964353264626434383762346639366335346465336365366131646131
30663533623334633164353964643536623566623132666166373039303361346534346337396430 38633962316232663530376133383034303465313331393561393636386663623861373161376366
66633632633162316462636662363938656263663135326237303361386234623661333938616262 37306533636463356232326430346538346136653264343839356662643435633337313232616561
62343731623838646133333135306438623538626639663863313337313862626535303937346138 33633331346166303038656135303532643531383466346334383665613662333431336362333334
64623338336333323239643565336533323234353436616230373063663539613839646238643735 66383336626463653136353861613832366338623631353930353432323338663834316436373230
32613163343637656337653139346463383734363636633635316261646133343731653133613238 37393135303037663035303633643439653238663038626135623436303435303361393064353034
35613265633538323039663665353664333434373834393264653830343766343136653632363532 35663230656434356434386462363834313137353865313831343261623466633861303336366334
65356331633262643635343861393535353532383137346534633661613963333531626463346562 33626164313334306362393461313633376464343037646534666339386462666634363563386661
63323638376536626534353062646561373566396235386634646663616230633635386661333334 37373138643432373834356335623864313561376131633161613035386166623836613339333563
34643833653065633033333839633736656161396236363364393838613038326532353130353063 31613934363331633537663261653230306539616238313837393762323932363365326238353131
62373635356665643133353561633861643436613035636239373630373164386531343736643564 31666564303666373163306237353136636430313639313931303339346335653539643265613230
32656536633631353931666137663234343861633865303436323434303636376634366665313234 62643836353432316165336665373964353762376432373263323666393333393564323932333638
33336163396330383263346333323065616437383564303839636235313964343633626166623833 33643763613739323134666139653862396436393836383232303564636261393161656163653830
62316436326532386338356563643038663737616338363636383032623665373862643631643331 66653237313262616464656437343465623961633562376638626432663530356434396463663465
62336364366537366531663762393964633531333166303662356334383562383466303334663261 39386261343933366666356664313339373231326566633165306632353535363436313864303936
63663638633736353934663530343934613837623963366232323637626466343138613165626634 38613636326666303061616337666436383263363931323339646432373965363565333763343631
38663338386465353463633438356434353839303334343165386430623733393934343466333134 37343566323732303830353537393565306434363130323335633837663762333431376539633765
35373137653635653966383865333637623930666562323236323434653063613464353362396164 61363939626234386564306539636637333137626133363139353235366238326633623062303833
31353632353637326330316239393665653833393438663436376562326638336239396337633134 64303832643830646430333061646333633039663634336263396563393437326135613932386634
39343031323931303061663837353931396263333637633264643966343633363966626135356333 35393639373631323435373864306433373638613836396664633537323636653531616534316465
30643564666336636535663264396632636532616234316130313761333731626639333665393430 63626661313733333431333665663165646234343438356134366131353234366466373133623639
37653765336533346564306139333436623466626664393735363865663733306161393634323161 34656436306433363136666633616464373937633435616534376536393233313236356634323161
38653262303363313562363233643634623364396237316636623431656366393538633131366139 63633632303562346566646166636664376431396162663765386532613832326339666130666536
64383833313537653137363961306538353230656164626663613462323962363631643336356561 36663865633963613536623637303061626336343835646639633031366333393132663033396533
61343539393239623861373633386338663534616438333538613632356265376132356539653964 38383862646631333262366237323234396465356531323363653464643361326362366231653739
61643234373639643933653963323631336433633863326263303938643166356330396339626637 62643738303734643033323362656230616466353161663136623864313136386366376634653664
30353337626231333730386465326533346233626561373564376234343763616431313031656531 31363930373530346333396536623037303162313934333634373033326432373566373032643964
65396363396436383337373133333231393139303734643533623233613136363031616430653530 30663962353664353062303935356262363333366437383338373961616237663361326631353565
31383231333763646437646430346564623739376365656661363539386164346365633730623738 37313936373033323131303161343139653565663466323830663536346665666232643163613562
65373334613138336263623262653833363566633638646139656433326165353637363131316230 30643061653363663864383663326563306261663061326366383731366463356238373539383935
31653436353336636333656430656564356233626535333263616136626136363430353237366230 65626464346366613638623730383631393066393233353130396636393438373565383266636439
37346533316562653764396262646661623232346335633966303833356332346133653535356638 66633837626461623335316438393432303839633234323065396533343466373962633566643032
61386338363139343561636564396232643361333936656637363130323165666536613066663137 35353939323038333434316232326138326266343662636130363565343463636364613263383438
64356233376662666432366364626639373534663865343865323363333239636461326665306537 35653736333339353831383733393161356533343138336161383435333261613262306135393565
35666533643834373839326139623564316533303562306235386238313764666438656139393362 66333134326265376433376538373531353966396138656265666266353737343936366132623633
61353337303761666538636533613839336237646331663231353831303663323739623362326363 66663339616263623139666236373563363666356236383538316363326635396332373161373932
66646136383765356431306639383336623237346534623535613435346238353866316164333763 31313430313065353762646538383361316563326262363833316434343965383032633139663634
62646665396233646632633535633332313934653964396562656464376635306434613932623664 38383430336432373031636635366539663337666330663361303964653331376430303263613461
66303131616137616439353939663731306438383662393039333036663862336537356335306266 39303832306463356465366237373338356636663637353835663336656331366638656433623462
66646538316432346132633764626361353561663937323039383138636331326232643932633932 34623761366365366634353635333632373162643330633435303466326437626138663834323531
34353061396461646664633364303536353833646130303032656238313637363736643663356237 61663433656537366662386134393761396162326265393465363131393333623731393534656338
34356161313463626361393031643332656464326166636333616162383431396662383261383033 35356132323062336235326630353464393434633633343932613432623536343365626165626432
31303537326532323238363539613439626365613538643364646366326236353934376539383865 31633732316364616463656430623763323039623835343164326536316334353666616237623535
32373731323133383335343639626133353232613033306331373237646364643830613532306237 32303036653936363933353932323666636662393231306138306239653065623338336662613633
37663034613363363164363935633332633732653761623439366636646137326163306632316264 34376631386235653161323331313661656366386635343264353535623439383734393363666239
35356164343462633938333331323836313539303961316532613032396632666138646265636337 64303466393539353862626436643366306564336638346432373661336537353033613036393630
38313539633430646166313435376532323630343232393735346335363731363666663363663138 35383962663363366665393938666266326464383936653539363838623338366466626439663438
38373465396461306665303331383266663836666434626137636632653266393239656631353833 35333737356234363731396162353730643665666630366133633839303836313064306330373233
32626531363763303439356565666434333334383737316431353032333638366338383430313436 62613363316238653534313739633033336134386264666362393061653434356637643736633863
62326331353834303261663730303066623062336638323433353565656638336235663734323530 37333766646666626531323738633161366537306539303961373037656461323265353032666338
66396666306534393139656138666430373537653862343232386233313730313831643734353539 30383834386333656334376361643338333662353461303932373132356133643934656466373864
35636361643230316665306563633836656261353338663538336666383462343132666361356233 31306466396231363132636463333633383939376462386230363661656164666331323333363435
32623732646564316461373537373331363138653332393638656437643635376663303430373933 33383262343238383265653232653538643964346236643031386164616364393732336637636239
31383837643033323334326562663135613537373661396166656130613963383265303961323230 39663333646137313933313562626265663365633633653465396234396563656539646630346634
63376662656232393833373731653234316462333834356534303738323430336633646437323332 63643461666365643961623936623364373334663162366537303163393665303633303562336361
34376263396662373931333938623330626438663336323066326239636535323562623936636335 38323431346334623835396165653232663361383836663633386361616630633437623332383732
39373335363663643238316230356534643033393363383436613865336361653566626336666630 33656139323339613164653433623237623939633230663735613063623131623632393535353066
37313739646337653436663665386666393063316263653833633239396632313734616262616166 31633234613563616566396262343334313262366434306662613965316135323965643732356130
38303363646661373139343039353532363736336261356462366238343135313637636166643431 31643437396264303831653762393930383431323062303032333666653761623866653762333663
38633236386535346166386434616234326164346661386534663834646464303038313561613034 32633862383763633663313166313365333963636233386430366165643635633938306533663164
33656265653739383932323632613766333335363633393666396663306337333231316639633731 35326561393265393830376434393235613265653764636538663165326363636538343630323763
35383062613633363065616535666638326138306431366130336238343263356362333535346435 32396531613238313736393462313736393535613662353365636165373831626466386535623433
35643866386430333730663461353136313630323961633764616134333835643234656633303232 63366338616637386336613435316262393561393139336331323132613835663065623637333833
35363333656436653563353336393066306139633937623037643566633166646264313864646364 62663262653536313334623736343535323766643235303865653864613862663664386664643934
36636663613465656339613534613634633733616662346530356361383934633466616138383865 37363832653530626339313336363639633863656633623838653564666135646333306264313765
66313930613030386163346363333836633139376637323337396434613761636434666164393534 39613331313432636330383066653431383333323265623233633434343066323764633765663832
37346437356431313930333932303465326138393262643665643139646134386161613465666363 34653434323631313261653234353437353762616466633463383835313034336234326666303864
32376464653737363130303761303838663061626636643534326235333062643735653837633938 35333034376131323436613735383433393266613966363432646663366636303564666532646163
35336161306435323665653035313930646666366631353464626235313761386135303665636137 38333963306665306438333034313933303337363331376663633333643161636236343662383361
62646466313662613630616234373933376138383037363933626437306466633832343238633964 33333933346665613061346634666530323830653732356231306365613436323263316462373734
30346265653865623537323833393763343632323839353237363466336663396131333266396533 65366462646532366638366235646533383235346463613164393630306636346232626264323932
65626561646233626366353862396564373463623563343961646662633133613333646435303030 37343631656361633235333338613933396565376636343932306363623635373237366639633236
31323332626534383732643839353739653835333934373835653331663762376337393930363833 62653537313134613239353365613239666466616630653336653738393032646263336561623861
36313033633239383830363861623538396463396163333138613437303535396265336664313639 31333434646532393963346238613662343737323831393136383736636631393065306664616333
31653837623938393137643137306566386666653564373838373265306462303062623436653261 32643666393261623262326562356631353432353231383161613964383566643466323962313238
31333138396664613962303965613536373239643166353831623565643662323564 33393531363135636362326434383962633463633039333664353865383231353634633535333738
62636432646461376431396638333231643164306432333132356131316538303366343333396564
35373732323633666263663064356262323432653462333834636433613231356637626265653866
61346366353165363639633466336463313462653137613035373430313334336262626439393539
3663

View file

@ -0,0 +1,85 @@
# `bitcoin_knots`
Builds Bitcoin Knots from source with PGP + SHA256 verification of the release
tarball, runs it as a full node on `knots-box`, and keeps a health check on a
systemd timer. The second play in the calling playbook publishes the P2P port
from the edge host via `socket_proxy`.
Converted from `deploy_bitcoin_knots_playbook.yml` (892 lines) under Plan 6. The
playbook is now 40 lines.
## The build is guarded; the chain is never touched
`build.yml` is 32 tasks, every one carrying
`when: not bitcoind_binary_exists.stat.exists`. On a host that already has the
binary the whole download / verify / 30-60 minute compile skips — **including the
two `state: absent` deletions**, which target `/opt/bitcoin-knots/source` and the
extracted build directory.
The chain lives elsewhere and nothing here touches it:
| | |
|---|---|
| `bitcoin_knots_dir` | `/opt/bitcoin-knots` — build tree, safe to delete |
| `bitcoin_data_dir` | `/var/lib/bitcoin` — config, logs, wallets |
| `bitcoin_large_data_dir` | `/mnt/knots_data`**~875 GB of blockchain** |
The signature-verification tasks are the security control of this role. They are
copied verbatim; do not "simplify" them.
## ⚠ This node is half of the mining setup
`bitcoin.conf` carries a DATUM Gateway section that was hand-added on the node
and was **missing from the playbook's template**:
```ini
blockmaxsize=3985000
blockmaxweight=3985000
blocknotify=killall -USR1 datum_gateway
maxmempool=1000
blockreconstructionextratxn=1000000
```
`blocknotify` is how `datum_gateway` learns a new block landed. Running the old
playbook would have deleted all of it, and solo mining would have carried on
grinding against a stale template — a silent failure that costs money rather
than raising an error. The template now carries it behind
`bitcoin_datum_gateway_enabled`.
**bitcoin-knots and datum-gateway are one system, not two services.** Changing
either config means thinking about both.
## The restart handler, and why exactness matters now
The hand-written `Restart bitcoind` handler carried
`when: uptime_kuma_enabled | default(false)`, so it had been inert since the
decommissioning: `bitcoin.conf` and the systemd unit both notify it and neither
could restart anything. A config change applied to disk, reported success, and
never took effect.
It is ungated here — which raises the bar for the template. **Any** residual
difference between the template and the live file, down to a trailing newline,
means the task reports `changed` and restarts a Bitcoin node on every run. It
took four rounds of `--check --diff` to reach `changed=0`: the DATUM section, an
explanatory comment that was rendering into the deployed file (now a `{# #}`
Jinja comment), a `# Pruning (optional)` comment the live file had, and one
trailing blank line.
## `dbcache`
Computed as 90% of RAM unless `bitcoin_dbcache_mb_override` is set. The live node
was hand-tuned to **200 MB**; the calculation produces 3528. As with fulcrum,
`set_fact` outranks role defaults, so the *calculation* honours the override — a
value pinned only in `defaults/` is silently ignored.
## Monitoring: one variable, no product knowledge
The check tests bitcoind's RPC and records the answer in its exit code, which
systemd keeps: `systemctl is-failed bitcoin-knots-healthcheck.service`. Set
`healthcheck_push_url` to report anywhere that accepts an HTTP ping.
The timer had last fired **2026-08-09** while still reporting `active` and
`enabled` — the same `OnBootSec` + `OnUnitActiveSec` dead chain as fulcrum, where
nothing re-arms it if the service does not run in a given boot. The role runs the
check once after enabling, which both smoke-tests it and supplies the reference
the timer schedules from.

View file

@ -0,0 +1,71 @@
# Bitcoin Knots Configuration Variables
# Version - REQUIRED: Specify exact version/tag to build
bitcoin_knots_version: "v29.2.knots20251110" # Must specify exact version/tag
bitcoin_knots_version_short: "29.2.knots20251110" # Version without 'v' prefix (for tarball URLs)
# Directories
bitcoin_knots_dir: /opt/bitcoin-knots
bitcoin_knots_source_dir: "{{ bitcoin_knots_dir }}/source"
bitcoin_data_dir: /var/lib/bitcoin # Standard location for config, logs, wallets
bitcoin_large_data_dir: /mnt/knots_data # Custom location for blockchain data (blocks, chainstate)
bitcoin_conf_dir: /etc/bitcoin
# Network
bitcoin_rpc_port: 8332
# Shared with the socket-proxy play on the edge host, so it lives in
# services_config.yml rather than only here.
bitcoin_p2p_port: "{{ service_settings.bitcoin.p2p_port }}"
bitcoin_rpc_bind: "0.0.0.0"
# Build options
bitcoin_build_jobs: 4 # Parallel build jobs (-j flag), adjust based on CPU cores
bitcoin_build_prefix: /usr/local
# Configuration options
bitcoin_enable_txindex: true # Set to true if transaction index needed (REQUIRED for Electrum servers like Electrs/ElectrumX)
bitcoin_max_connections: 125
# dbcache will be calculated as 90% of host RAM automatically in playbook
# ZMQ Configuration
bitcoin_zmq_enabled: true
bitcoin_zmq_bind: "tcp://0.0.0.0"
bitcoin_zmq_port_rawblock: 28332
bitcoin_zmq_port_rawtx: 28333
bitcoin_zmq_port_hashblock: 28334
bitcoin_zmq_port_hashtx: 28335
# Service user
bitcoin_user: bitcoin
bitcoin_group: bitcoin
# --- Health check ----------------------------------------------------------
# Checks bitcoind RPC and records the answer in its exit code, which systemd
# keeps: `systemctl is-failed bitcoin-knots-healthcheck.service`.
#
# WHERE TO REPORT HEALTH — the one place to plug in monitoring. Empty means
# check, exit honestly, report nowhere. Any endpoint accepting an HTTP ping
# works; nothing here is specific to a monitoring product.
healthcheck_push_url: ""
# --- Logging ----------------------------------------------------------------
# The live node logs to a file. Set to "" to use printtoconsole=1 (journald).
bitcoin_logfile: "{{ bitcoin_data_dir }}/debug.log"
# --- dbcache ----------------------------------------------------------------
# Computed as 90% of RAM unless this is set. The live node was hand-tuned to
# 200 MB; the calculation would have produced 3528. As with fulcrum, note that
# set_fact outranks role defaults, so the CALCULATION has to honour this - a
# value pinned only in defaults/ is silently ignored.
bitcoin_dbcache_mb_override: 200
# --- DATUM Gateway ----------------------------------------------------------
# This node feeds block templates to datum_gateway on knots-box. These settings
# were hand-added to bitcoin.conf and were missing from the template, so a
# playbook run would have removed them and broken the mining setup.
bitcoin_datum_gateway_enabled: true
bitcoin_blockmaxsize: 3985000
bitcoin_blockmaxweight: 3985000
bitcoin_blocknotify: "killall -USR1 datum_gateway"
bitcoin_maxmempool: 1000
bitcoin_blockreconstructionextratxn: 1000000

View file

@ -0,0 +1,14 @@
---
# Ungated on purpose. The hand-written handler carried
# when: uptime_kuma_enabled | default(false)
# so it has been inert since the decommissioning. Two tasks notify it —
# bitcoin.conf and the systemd unit — and neither could actually restart
# bitcoind. A configuration change to a Bitcoin node therefore applied to disk,
# reported success, and silently never took effect.
#
# Restarting bitcoind re-opens the chainstate; it does not reindex.
- name: Restart bitcoind
systemd:
name: bitcoind
state: restarted
daemon_reload: yes

View file

@ -0,0 +1,222 @@
---
# Every task here is guarded by `when: not bitcoind_binary_exists.stat.exists`,
# so on a host that already has the binary the whole download / verify / build
# sequence skips — including the two `state: absent` deletions, which target
# /opt/bitcoin-knots/{source,bitcoin-<version>} and never the chain data in
# /mnt/knots_data.
- name: Check if bitcoind binary already exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoind"
register: bitcoind_binary_exists
changed_when: false
- name: Install gnupg for signature verification
apt:
name: gnupg
state: present
when: not bitcoind_binary_exists.stat.exists
- name: Import Luke Dashjr's Bitcoin Knots signing key
command: gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 90C8019E36C2E964
register: key_import
changed_when: "'already in secret keyring' not in key_import.stdout and 'already in public keyring' not in key_import.stdout"
when: not bitcoind_binary_exists.stat.exists
failed_when: key_import.rc != 0
- name: Display imported key fingerprint
command: gpg --fingerprint 90C8019E36C2E964
register: key_fingerprint
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Download SHA256SUMS file
get_url:
url: "https://bitcoinknots.org/files/{{ bitcoin_version_major }}.x/{{ bitcoin_knots_version_short }}/SHA256SUMS"
dest: "/tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS"
mode: '0644'
when: not bitcoind_binary_exists.stat.exists
- name: Download SHA256SUMS.asc signature file
get_url:
url: "https://bitcoinknots.org/files/{{ bitcoin_version_major }}.x/{{ bitcoin_knots_version_short }}/SHA256SUMS.asc"
dest: "/tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS.asc"
mode: '0644'
when: not bitcoind_binary_exists.stat.exists
- name: Verify PGP signature on SHA256SUMS file
command: gpg --verify /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS.asc /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS
register: sha256sums_verification
changed_when: false
failed_when: false # Don't fail here - check for 'Good signature' in next task
when: not bitcoind_binary_exists.stat.exists
- name: Display SHA256SUMS verification result
debug:
msg: "{{ sha256sums_verification.stdout_lines + sha256sums_verification.stderr_lines }}"
when: not bitcoind_binary_exists.stat.exists
- name: Fail if SHA256SUMS signature verification failed
fail:
msg: "SHA256SUMS signature verification failed. Aborting build."
when: not bitcoind_binary_exists.stat.exists and ('Good signature' not in sha256sums_verification.stdout and 'Good signature' not in sha256sums_verification.stderr)
- name: Remove any existing tarball to force fresh download
file:
path: /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Download Bitcoin Knots source tarball
get_url:
url: "{{ bitcoin_source_tarball_url }}"
dest: "/tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz"
mode: '0644'
validate_certs: yes
force: yes
when: not bitcoind_binary_exists.stat.exists
- name: Calculate SHA256 checksum of downloaded tarball
command: sha256sum /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
register: tarball_checksum
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Extract expected checksum from SHA256SUMS file
shell: grep "bitcoin-{{ bitcoin_knots_version_short }}.tar.gz" /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS | awk '{print $1}'
register: expected_checksum
changed_when: false
when: not bitcoind_binary_exists.stat.exists
failed_when: expected_checksum.stdout == ""
- name: Display checksum comparison
debug:
msg:
- "Expected: {{ expected_checksum.stdout | trim }}"
- "Actual: {{ tarball_checksum.stdout.split()[0] }}"
when: not bitcoind_binary_exists.stat.exists
- name: Verify tarball checksum matches SHA256SUMS
fail:
msg: "Tarball checksum mismatch! Expected {{ expected_checksum.stdout | trim }}, got {{ tarball_checksum.stdout.split()[0] }}"
when: not bitcoind_binary_exists.stat.exists and expected_checksum.stdout | trim != tarball_checksum.stdout.split()[0]
- name: Remove existing source directory if it exists (to force fresh extraction)
file:
path: "{{ bitcoin_knots_source_dir }}"
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Remove extracted directory if it exists (from previous runs)
file:
path: "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}"
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Extract verified source tarball
unarchive:
src: /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
dest: "{{ bitcoin_knots_dir }}"
remote_src: yes
when: not bitcoind_binary_exists.stat.exists
- name: Check if extracted directory exists
stat:
path: "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}"
register: extracted_dir_stat
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Rename extracted directory to expected name
command: mv "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}" "{{ bitcoin_knots_source_dir }}"
when: not bitcoind_binary_exists.stat.exists and extracted_dir_stat.stat.exists
- name: Check if CMakeLists.txt exists
stat:
path: "{{ bitcoin_knots_source_dir }}/CMakeLists.txt"
register: cmake_exists
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Create CMake build directory
file:
path: "{{ bitcoin_knots_source_dir }}/build"
state: directory
mode: '0755'
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
- name: Configure Bitcoin Knots build with CMake
command: >
cmake
-DCMAKE_INSTALL_PREFIX={{ bitcoin_build_prefix }}
-DBUILD_BITCOIN_WALLET=OFF
-DCMAKE_BUILD_TYPE=Release
-DWITH_ZMQ=ON
..
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
register: configure_result
changed_when: true
- name: Verify CMake enabled ZMQ
shell: |
set -e
cd "{{ bitcoin_knots_source_dir }}/build"
cmake -LAH .. | grep -iE 'ZMQ|WITH_ZMQ|ENABLE_ZMQ|USE_ZMQ'
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
register: zmq_check
changed_when: false
- name: Fail if CMakeLists.txt not found
fail:
msg: "CMakeLists.txt not found in {{ bitcoin_knots_source_dir }}. Cannot build Bitcoin Knots."
when: not bitcoind_binary_exists.stat.exists and not (cmake_exists.stat.exists | default(false))
- name: Build Bitcoin Knots with CMake (this may take 30-60+ minutes)
command: cmake --build . -j{{ bitcoin_build_jobs }}
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
async: 3600
poll: 0
register: build_result
changed_when: true
- name: Check build status
async_status:
jid: "{{ build_result.ansible_job_id }}"
register: build_job_result
until: build_job_result.finished
retries: 120
delay: 60
when: not bitcoind_binary_exists.stat.exists and build_result.ansible_job_id is defined
- name: Fail if build failed
fail:
msg: "Bitcoin Knots build failed: {{ build_job_result.msg }}"
when: not bitcoind_binary_exists.stat.exists and build_result.ansible_job_id is defined and build_job_result.failed | default(false)
- name: Install Bitcoin Knots binaries
command: cmake --install .
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
changed_when: true
- name: Verify bitcoind binary exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoind"
register: bitcoind_installed
changed_when: false
- name: Verify bitcoin-cli binary exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoin-cli"
register: bitcoin_cli_installed
changed_when: false
- name: Fail if binaries not found
fail:
msg: "Bitcoin Knots binaries not found after installation"
when: not bitcoind_installed.stat.exists or not bitcoin_cli_installed.stat.exists

View file

@ -0,0 +1,20 @@
---
# Ownership copied verbatim from the playbook this replaces; verified
# mechanically against `git show HEAD:` rather than retyped from memory.
- name: Create bitcoin.conf configuration file
ansible.builtin.template:
src: bitcoin.conf.j2
dest: "{{ bitcoin_conf_dir }}/bitcoin.conf"
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0640'
notify: Restart bitcoind
- name: Create systemd service file for bitcoind
ansible.builtin.template:
src: bitcoind.service.j2
dest: /etc/systemd/system/bitcoind.service
owner: root
group: root
mode: '0644'
notify: Restart bitcoind

View file

@ -0,0 +1,56 @@
---
# Everything here answers "is bitcoind healthy" and records the answer. The
# Uptime Kuma specifics that used to follow — an embedded Python script creating
# monitors over the API, a /tmp credentials file, push-URL extraction and a
# systemd Environment= rewrite — are gone. Where it reports is now one variable,
# healthcheck_push_url. See the role README.
- name: Install curl for health check script
apt:
name: curl
state: present
- name: Create Bitcoin Knots health check script
ansible.builtin.template:
src: healthcheck.sh.j2
dest: /usr/local/bin/bitcoin-knots-healthcheck-push.sh
owner: root
group: root
mode: '0755'
validate: "bash -n %s"
- name: Create systemd service for Bitcoin Knots health check
ansible.builtin.template:
src: healthcheck.service.j2
dest: /etc/systemd/system/bitcoin-knots-healthcheck.service
owner: root
group: root
mode: '0644'
- name: Create systemd timer for Bitcoin Knots health check
ansible.builtin.template:
src: healthcheck.timer.j2
dest: /etc/systemd/system/bitcoin-knots-healthcheck.timer
owner: root
group: root
mode: '0644'
- name: Reload systemd daemon for health check
systemd:
daemon_reload: yes
- name: Enable and restart the Bitcoin Knots health check timer
systemd:
name: bitcoin-knots-healthcheck.timer
enabled: yes
state: restarted
daemon_reload: yes
# Runs the check once, which is both a smoke test and the thing that actually
# arms the timer. This timer is OnBootSec + OnUnitActiveSec with no OnCalendar:
# OnBootSec elapses once, and OnUnitActiveSec needs the SERVICE to have run this
# boot to have anything to schedule from. Restarting the timer does not supply
# that reference; running the service does. The live timer had last fired on
# 2026-08-09 while still reporting `active` and `enabled`.
- name: Run the Bitcoin Knots health check once to arm the timer
command: systemctl start bitcoin-knots-healthcheck.service
changed_when: false

View file

@ -0,0 +1,104 @@
---
- name: Calculate dbcache as a share of system RAM
set_fact:
bitcoin_dbcache_mb: "{{ (ansible_memtotal_mb | float * 0.9) | int }}"
when: bitcoin_dbcache_mb_override | string | length == 0
- name: Use the explicit dbcache override
set_fact:
bitcoin_dbcache_mb: "{{ bitcoin_dbcache_mb_override }}"
when: bitcoin_dbcache_mb_override | string | length > 0
changed_when: false
- name: Display calculated dbcache value
debug:
msg: "Setting dbcache to {{ bitcoin_dbcache_mb }} MB (90% of {{ ansible_memtotal_mb }} MB total RAM)"
- name: Install build dependencies
apt:
name:
- build-essential
- libtool
- autotools-dev
- automake
- pkg-config
- bsdmainutils
- python3
- python3-pip
- libevent-dev
- libboost-system-dev
- libboost-filesystem-dev
- libboost-test-dev
- libboost-thread-dev
- libboost-chrono-dev
- libboost-program-options-dev
- libboost-dev
- libssl-dev
- libdb-dev
- libminiupnpc-dev
- libzmq3-dev
- libnatpmp-dev
- libsqlite3-dev
- git
- curl
- wget
- cmake
state: present
update_cache: yes
- name: Create bitcoin group
group:
name: "{{ bitcoin_group }}"
system: yes
state: present
- name: Create bitcoin user
user:
name: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
system: yes
shell: /usr/sbin/nologin
home: "{{ bitcoin_data_dir }}"
create_home: yes
state: present
- name: Create bitcoin-knots directory
file:
path: "{{ bitcoin_knots_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create bitcoin-knots source directory
file:
path: "{{ bitcoin_knots_source_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create bitcoin data directory (for config, logs, wallets)
file:
path: "{{ bitcoin_data_dir }}"
state: directory
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0750'
- name: Create bitcoin large data directory (for blockchain)
file:
path: "{{ bitcoin_large_data_dir }}"
state: directory
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0750'
- name: Create bitcoin config directory
file:
path: "{{ bitcoin_conf_dir }}"
state: directory
owner: root
group: root
mode: '0755'

View file

@ -0,0 +1,8 @@
---
# import_tasks, not include_tasks: static imports stay visible to --list-tasks,
# which is how this conversion was verified against the playbook it replaced.
- ansible.builtin.import_tasks: install.yml
- ansible.builtin.import_tasks: build.yml
- ansible.builtin.import_tasks: configure.yml
- ansible.builtin.import_tasks: service.yml
- ansible.builtin.import_tasks: healthcheck.yml

View file

@ -0,0 +1,37 @@
---
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start bitcoind service
systemd:
name: bitcoind
enabled: yes
state: started
- name: Wait for bitcoind RPC to be available
uri:
url: "http://{{ bitcoin_rpc_bind }}:{{ bitcoin_rpc_port }}"
method: POST
body_format: json
body:
jsonrpc: "1.0"
id: "healthcheck"
method: "getblockchaininfo"
params: []
user: "{{ bitcoin_rpc_user }}"
password: "{{ bitcoin_rpc_password }}"
status_code: 200
timeout: 10
register: rpc_check
until: rpc_check.status == 200
retries: 30
delay: 5
ignore_errors: yes
- name: Display RPC connection status
debug:
msg: "Bitcoin Knots RPC is {{ 'available' if rpc_check.status == 200 else 'not yet available' }}"
# ═════════════════════════════════════════════════════════════════════════
# DEPRECATED — Uptime Kuma was decommissioned on 2026-09-11.

View file

@ -0,0 +1,67 @@
# Bitcoin Knots Configuration
# Generated by Ansible
# Data directory (blockchain storage)
datadir={{ bitcoin_large_data_dir }}
# RPC Configuration
server=1
rpcuser={{ bitcoin_rpc_user }}
rpcpassword={{ bitcoin_rpc_password }}
rpcbind={{ bitcoin_rpc_bind }}
rpcport={{ bitcoin_rpc_port }}
rpcallowip=0.0.0.0/0
# Network Configuration
listen=1
port={{ bitcoin_p2p_port }}
maxconnections={{ bitcoin_max_connections }}
# Performance
dbcache={{ bitcoin_dbcache_mb }}
# Transaction Index (optional)
{% if bitcoin_enable_txindex %}
txindex=1
{% endif %}
{# The live node carries this comment and the template never produced it, so a
run would have silently deleted it. Harmless in itself, but matching it keeps
this task at `ok` - which means any future `changed` here is a real signal
rather than known noise. #}
# Pruning (optional)
# Logging
logtimestamps=1
{% if bitcoin_logfile %}
logfile={{ bitcoin_logfile }}
{% else %}
printtoconsole=1
{% endif %}
# ZMQ Configuration
{% if bitcoin_zmq_enabled | default(false) %}
zmqpubrawblock={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_rawblock }}
zmqpubrawtx={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_rawtx }}
zmqpubhashblock={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_hashblock }}
zmqpubhashtx={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_hashtx }}
{% endif %}
# Security
disablewallet=1
{% if bitcoin_datum_gateway_enabled %}
{# These were hand-added on the node and were NOT in this template, so running
the playbook would have stripped them. blocknotify is how datum_gateway
learns a new block landed; without it solo mining keeps grinding on a stale
template - a silent failure that costs money rather than raising an error.
Kept as a Jinja comment so the explanation stays in the repo and out of the
deployed config. #}
# Specific for DATUM gateway
blockmaxsize={{ bitcoin_blockmaxsize }}
blockmaxweight={{ bitcoin_blockmaxweight }}
blocknotify={{ bitcoin_blocknotify }}
maxmempool={{ bitcoin_maxmempool }}
blockreconstructionextratxn={{ bitcoin_blockreconstructionextratxn }}
{% endif %}

View file

@ -0,0 +1,17 @@
[Unit]
Description=Bitcoin Knots daemon
After=network.target
[Service]
Type=simple
User={{ bitcoin_user }}
Group={{ bitcoin_group }}
ExecStart={{ bitcoin_build_prefix }}/bin/bitcoind -conf={{ bitcoin_conf_dir }}/bitcoin.conf
Restart=always
RestartSec=10
TimeoutStopSec=600
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Bitcoin Knots Health Check
After=network.target bitcoind.service
[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/bitcoin-knots-healthcheck-push.sh
Environment=HEALTHCHECK_PUSH_URL={{ healthcheck_push_url }}
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,62 @@
#!/bin/bash
# Bitcoin Knots health check — managed by Ansible (roles/bitcoin_knots)
#
# The exit code is the answer and systemd keeps it:
# systemctl is-failed bitcoin-knots-healthcheck.service
# Reporting anywhere else is optional and generic.
#
#
RPC_HOST="{{ bitcoin_rpc_bind }}"
RPC_PORT={{ bitcoin_rpc_port }}
RPC_USER="{{ bitcoin_rpc_user }}"
RPC_PASSWORD="{{ bitcoin_rpc_password }}"
PUSH_URL="${HEALTHCHECK_PUSH_URL:-}"
# Check if bitcoind RPC is responding
check_bitcoind() {
local response
response=$(curl -s --max-time 30 \
--user "${RPC_USER}:${RPC_PASSWORD}" \
--data-binary '{"jsonrpc":"1.0","id":"healthcheck","method":"getblockchaininfo","params":[]}' \
--header 'Content-Type: application/json' \
"http://${RPC_HOST}:${RPC_PORT}" 2>&1)
if [ $? -eq 0 ]; then
# Check if response contains a non-null error
# Successful responses have "error": null, failures have "error": {...}
if echo "$response" | grep -q '"error":null\|"error": null'; then
return 0
else
return 1
fi
else
return 1
fi
}
report() {
local status=$1
local msg=$2
# No push URL is normal, not an error: the exit code below is still a
# complete answer for anything reading unit state.
[ -n "$PUSH_URL" ] || return 0
# URL encode spaces in message
local encoded_msg="${msg// /%20}"
if ! curl -s --max-time 10 --retry 2 -o /dev/null \
"${PUSH_URL}?status=${status}&msg=${encoded_msg}&ping="; then
return 1
fi
}
# Main health check
if check_bitcoind; then
report "up" "OK"
exit 0
else
report "down" "bitcoind RPC not responding"
exit 1
fi

View file

@ -0,0 +1,11 @@
[Unit]
Description=Bitcoin Knots Health Check Timer
Requires=bitcoind.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=1min
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -1,38 +0,0 @@
# Bitcoin Knots Configuration Variables
# Version - REQUIRED: Specify exact version/tag to build
bitcoin_knots_version: "v29.2.knots20251110" # Must specify exact version/tag
bitcoin_knots_version_short: "29.2.knots20251110" # Version without 'v' prefix (for tarball URLs)
# Directories
bitcoin_knots_dir: /opt/bitcoin-knots
bitcoin_knots_source_dir: "{{ bitcoin_knots_dir }}/source"
bitcoin_data_dir: /var/lib/bitcoin # Standard location for config, logs, wallets
bitcoin_large_data_dir: /mnt/knots_data # Custom location for blockchain data (blocks, chainstate)
bitcoin_conf_dir: /etc/bitcoin
# Network
bitcoin_rpc_port: 8332
bitcoin_p2p_port: 8333
bitcoin_rpc_bind: "0.0.0.0"
# Build options
bitcoin_build_jobs: 4 # Parallel build jobs (-j flag), adjust based on CPU cores
bitcoin_build_prefix: /usr/local
# Configuration options
bitcoin_enable_txindex: true # Set to true if transaction index needed (REQUIRED for Electrum servers like Electrs/ElectrumX)
bitcoin_max_connections: 125
# dbcache will be calculated as 90% of host RAM automatically in playbook
# ZMQ Configuration
bitcoin_zmq_enabled: true
bitcoin_zmq_bind: "tcp://0.0.0.0"
bitcoin_zmq_port_rawblock: 28332
bitcoin_zmq_port_rawtx: 28333
bitcoin_zmq_port_hashblock: 28334
bitcoin_zmq_port_hashtx: 28335
# Service user
bitcoin_user: bitcoin
bitcoin_group: bitcoin

View file

@ -1,3 +1,11 @@
---
# Bitcoin Knots: full node built from source, with PGP signature and SHA256
# verification of the release tarball. The build is guarded by a binary-exists
# check, so a converged host skips the whole 30-60 minute compile.
#
# The chain lives in bitcoin_large_data_dir (/mnt/knots_data, ~875 GB). Nothing
# here touches it; the only `state: absent` tasks target the build tree under
# /opt/bitcoin-knots and run only when the binary is missing.
- name: Build and Deploy Bitcoin Knots from Source - name: Build and Deploy Bitcoin Knots from Source
hosts: bitcoin hosts: bitcoin
become: yes become: yes
@ -5,740 +13,12 @@
- ../../infra_vars.yml - ../../infra_vars.yml
- ../../services_config.yml - ../../services_config.yml
- ../../infra_secrets.yml - ../../infra_secrets.yml
- ./bitcoin_knots_vars.yml
vars: vars:
bitcoin_repo_url: "https://github.com/bitcoinknots/bitcoin.git" # Preserves the push URL this check has been reporting to. The role knows
bitcoin_sigs_base_url: "https://raw.githubusercontent.com/bitcoinknots/guix.sigs/knots" # nothing about Uptime Kuma — this is just "a URL that accepts a ping".
bitcoin_version_major: "{{ bitcoin_knots_version_short | regex_replace('^(\\d+)\\..*', '\\1') }}" healthcheck_push_url: "{{ healthcheck_push_urls.bitcoin_knots | default('') }}"
bitcoin_source_tarball_url: "https://bitcoinknots.org/files/{{ bitcoin_version_major }}.x/{{ bitcoin_knots_version_short }}/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz" roles:
uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}" - bitcoin_knots
tasks:
- name: Calculate 90% of system RAM for dbcache
set_fact:
bitcoin_dbcache_mb: "{{ (ansible_memtotal_mb | float * 0.9) | int }}"
changed_when: false
- name: Display calculated dbcache value
debug:
msg: "Setting dbcache to {{ bitcoin_dbcache_mb }} MB (90% of {{ ansible_memtotal_mb }} MB total RAM)"
- name: Install build dependencies
apt:
name:
- build-essential
- libtool
- autotools-dev
- automake
- pkg-config
- bsdmainutils
- python3
- python3-pip
- libevent-dev
- libboost-system-dev
- libboost-filesystem-dev
- libboost-test-dev
- libboost-thread-dev
- libboost-chrono-dev
- libboost-program-options-dev
- libboost-dev
- libssl-dev
- libdb-dev
- libminiupnpc-dev
- libzmq3-dev
- libnatpmp-dev
- libsqlite3-dev
- git
- curl
- wget
- cmake
state: present
update_cache: yes
- name: Create bitcoin group
group:
name: "{{ bitcoin_group }}"
system: yes
state: present
- name: Create bitcoin user
user:
name: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
system: yes
shell: /usr/sbin/nologin
home: "{{ bitcoin_data_dir }}"
create_home: yes
state: present
- name: Create bitcoin-knots directory
file:
path: "{{ bitcoin_knots_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create bitcoin-knots source directory
file:
path: "{{ bitcoin_knots_source_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create bitcoin data directory (for config, logs, wallets)
file:
path: "{{ bitcoin_data_dir }}"
state: directory
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0750'
- name: Create bitcoin large data directory (for blockchain)
file:
path: "{{ bitcoin_large_data_dir }}"
state: directory
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0750'
- name: Create bitcoin config directory
file:
path: "{{ bitcoin_conf_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Check if bitcoind binary already exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoind"
register: bitcoind_binary_exists
changed_when: false
- name: Install gnupg for signature verification
apt:
name: gnupg
state: present
when: not bitcoind_binary_exists.stat.exists
- name: Import Luke Dashjr's Bitcoin Knots signing key
command: gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 90C8019E36C2E964
register: key_import
changed_when: "'already in secret keyring' not in key_import.stdout and 'already in public keyring' not in key_import.stdout"
when: not bitcoind_binary_exists.stat.exists
failed_when: key_import.rc != 0
- name: Display imported key fingerprint
command: gpg --fingerprint 90C8019E36C2E964
register: key_fingerprint
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Download SHA256SUMS file
get_url:
url: "https://bitcoinknots.org/files/{{ bitcoin_version_major }}.x/{{ bitcoin_knots_version_short }}/SHA256SUMS"
dest: "/tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS"
mode: '0644'
when: not bitcoind_binary_exists.stat.exists
- name: Download SHA256SUMS.asc signature file
get_url:
url: "https://bitcoinknots.org/files/{{ bitcoin_version_major }}.x/{{ bitcoin_knots_version_short }}/SHA256SUMS.asc"
dest: "/tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS.asc"
mode: '0644'
when: not bitcoind_binary_exists.stat.exists
- name: Verify PGP signature on SHA256SUMS file
command: gpg --verify /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS.asc /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS
register: sha256sums_verification
changed_when: false
failed_when: false # Don't fail here - check for 'Good signature' in next task
when: not bitcoind_binary_exists.stat.exists
- name: Display SHA256SUMS verification result
debug:
msg: "{{ sha256sums_verification.stdout_lines + sha256sums_verification.stderr_lines }}"
when: not bitcoind_binary_exists.stat.exists
- name: Fail if SHA256SUMS signature verification failed
fail:
msg: "SHA256SUMS signature verification failed. Aborting build."
when: not bitcoind_binary_exists.stat.exists and ('Good signature' not in sha256sums_verification.stdout and 'Good signature' not in sha256sums_verification.stderr)
- name: Remove any existing tarball to force fresh download
file:
path: /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Download Bitcoin Knots source tarball
get_url:
url: "{{ bitcoin_source_tarball_url }}"
dest: "/tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz"
mode: '0644'
validate_certs: yes
force: yes
when: not bitcoind_binary_exists.stat.exists
- name: Calculate SHA256 checksum of downloaded tarball
command: sha256sum /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
register: tarball_checksum
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Extract expected checksum from SHA256SUMS file
shell: grep "bitcoin-{{ bitcoin_knots_version_short }}.tar.gz" /tmp/bitcoin-knots-{{ bitcoin_knots_version_short }}-SHA256SUMS | awk '{print $1}'
register: expected_checksum
changed_when: false
when: not bitcoind_binary_exists.stat.exists
failed_when: expected_checksum.stdout == ""
- name: Display checksum comparison
debug:
msg:
- "Expected: {{ expected_checksum.stdout | trim }}"
- "Actual: {{ tarball_checksum.stdout.split()[0] }}"
when: not bitcoind_binary_exists.stat.exists
- name: Verify tarball checksum matches SHA256SUMS
fail:
msg: "Tarball checksum mismatch! Expected {{ expected_checksum.stdout | trim }}, got {{ tarball_checksum.stdout.split()[0] }}"
when: not bitcoind_binary_exists.stat.exists and expected_checksum.stdout | trim != tarball_checksum.stdout.split()[0]
- name: Remove existing source directory if it exists (to force fresh extraction)
file:
path: "{{ bitcoin_knots_source_dir }}"
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Remove extracted directory if it exists (from previous runs)
file:
path: "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}"
state: absent
when: not bitcoind_binary_exists.stat.exists
- name: Extract verified source tarball
unarchive:
src: /tmp/bitcoin-{{ bitcoin_knots_version_short }}.tar.gz
dest: "{{ bitcoin_knots_dir }}"
remote_src: yes
when: not bitcoind_binary_exists.stat.exists
- name: Check if extracted directory exists
stat:
path: "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}"
register: extracted_dir_stat
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Rename extracted directory to expected name
command: mv "{{ bitcoin_knots_dir }}/bitcoin-{{ bitcoin_knots_version_short }}" "{{ bitcoin_knots_source_dir }}"
when: not bitcoind_binary_exists.stat.exists and extracted_dir_stat.stat.exists
- name: Check if CMakeLists.txt exists
stat:
path: "{{ bitcoin_knots_source_dir }}/CMakeLists.txt"
register: cmake_exists
changed_when: false
when: not bitcoind_binary_exists.stat.exists
- name: Create CMake build directory
file:
path: "{{ bitcoin_knots_source_dir }}/build"
state: directory
mode: '0755'
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
- name: Configure Bitcoin Knots build with CMake
command: >
cmake
-DCMAKE_INSTALL_PREFIX={{ bitcoin_build_prefix }}
-DBUILD_BITCOIN_WALLET=OFF
-DCMAKE_BUILD_TYPE=Release
-DWITH_ZMQ=ON
..
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
register: configure_result
changed_when: true
- name: Verify CMake enabled ZMQ
shell: |
set -e
cd "{{ bitcoin_knots_source_dir }}/build"
cmake -LAH .. | grep -iE 'ZMQ|WITH_ZMQ|ENABLE_ZMQ|USE_ZMQ'
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
register: zmq_check
changed_when: false
- name: Fail if CMakeLists.txt not found
fail:
msg: "CMakeLists.txt not found in {{ bitcoin_knots_source_dir }}. Cannot build Bitcoin Knots."
when: not bitcoind_binary_exists.stat.exists and not (cmake_exists.stat.exists | default(false))
- name: Build Bitcoin Knots with CMake (this may take 30-60+ minutes)
command: cmake --build . -j{{ bitcoin_build_jobs }}
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
async: 3600
poll: 0
register: build_result
changed_when: true
- name: Check build status
async_status:
jid: "{{ build_result.ansible_job_id }}"
register: build_job_result
until: build_job_result.finished
retries: 120
delay: 60
when: not bitcoind_binary_exists.stat.exists and build_result.ansible_job_id is defined
- name: Fail if build failed
fail:
msg: "Bitcoin Knots build failed: {{ build_job_result.msg }}"
when: not bitcoind_binary_exists.stat.exists and build_result.ansible_job_id is defined and build_job_result.failed | default(false)
- name: Install Bitcoin Knots binaries
command: cmake --install .
args:
chdir: "{{ bitcoin_knots_source_dir }}/build"
when: not bitcoind_binary_exists.stat.exists and cmake_exists.stat.exists | default(false)
changed_when: true
- name: Verify bitcoind binary exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoind"
register: bitcoind_installed
changed_when: false
- name: Verify bitcoin-cli binary exists
stat:
path: "{{ bitcoin_build_prefix }}/bin/bitcoin-cli"
register: bitcoin_cli_installed
changed_when: false
- name: Fail if binaries not found
fail:
msg: "Bitcoin Knots binaries not found after installation"
when: not bitcoind_installed.stat.exists or not bitcoin_cli_installed.stat.exists
- name: Create bitcoin.conf configuration file
copy:
dest: "{{ bitcoin_conf_dir }}/bitcoin.conf"
content: |
# Bitcoin Knots Configuration
# Generated by Ansible
# Data directory (blockchain storage)
datadir={{ bitcoin_large_data_dir }}
# RPC Configuration
server=1
rpcuser={{ bitcoin_rpc_user }}
rpcpassword={{ bitcoin_rpc_password }}
rpcbind={{ bitcoin_rpc_bind }}
rpcport={{ bitcoin_rpc_port }}
rpcallowip=0.0.0.0/0
# Network Configuration
listen=1
port={{ bitcoin_p2p_port }}
maxconnections={{ bitcoin_max_connections }}
# Performance
dbcache={{ bitcoin_dbcache_mb }}
# Transaction Index (optional)
{% if bitcoin_enable_txindex %}
txindex=1
{% endif %}
# Logging (to journald via systemd)
logtimestamps=1
printtoconsole=1
# ZMQ Configuration
{% if bitcoin_zmq_enabled | default(false) %}
zmqpubrawblock={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_rawblock }}
zmqpubrawtx={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_rawtx }}
zmqpubhashblock={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_hashblock }}
zmqpubhashtx={{ bitcoin_zmq_bind }}:{{ bitcoin_zmq_port_hashtx }}
{% endif %}
# Security
disablewallet=1
owner: "{{ bitcoin_user }}"
group: "{{ bitcoin_group }}"
mode: '0640'
notify: Restart bitcoind
- name: Create systemd service file for bitcoind
copy:
dest: /etc/systemd/system/bitcoind.service
content: |
[Unit]
Description=Bitcoin Knots daemon
After=network.target
[Service]
Type=simple
User={{ bitcoin_user }}
Group={{ bitcoin_group }}
ExecStart={{ bitcoin_build_prefix }}/bin/bitcoind -conf={{ bitcoin_conf_dir }}/bitcoin.conf
Restart=always
RestartSec=10
TimeoutStopSec=600
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: '0644'
notify: Restart bitcoind
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start bitcoind service
systemd:
name: bitcoind
enabled: yes
state: started
- name: Wait for bitcoind RPC to be available
uri:
url: "http://{{ bitcoin_rpc_bind }}:{{ bitcoin_rpc_port }}"
method: POST
body_format: json
body:
jsonrpc: "1.0"
id: "healthcheck"
method: "getblockchaininfo"
params: []
user: "{{ bitcoin_rpc_user }}"
password: "{{ bitcoin_rpc_password }}"
status_code: 200
timeout: 10
register: rpc_check
until: rpc_check.status == 200
retries: 30
delay: 5
ignore_errors: yes
- name: Display RPC connection status
debug:
msg: "Bitcoin Knots RPC is {{ 'available' if rpc_check.status == 200 else 'not yet available' }}"
# ═════════════════════════════════════════════════════════════════════════
# DEPRECATED — Uptime Kuma was decommissioned on 2026-09-11.
#
# Every task below is inert: uptime_kuma_enabled is false in
# group_vars/all/main.yml, so they all skip and the deployment above still
# runs normally. Kept because the health-check logic is the durable part —
# when a replacement exists, rewire the push transport and flip the flag.
#
# What was being monitored: archive/uptime_kuma/MONITORS.md
# ═════════════════════════════════════════════════════════════════════════
- name: Create Bitcoin Knots health check and push script
when: uptime_kuma_enabled | default(false)
copy:
dest: /usr/local/bin/bitcoin-knots-healthcheck-push.sh
content: |
#!/bin/bash
#
# Bitcoin Knots Health Check and Push to Uptime Kuma
# Checks if bitcoind RPC is responding and pushes status to Uptime Kuma
#
RPC_HOST="{{ bitcoin_rpc_bind }}"
RPC_PORT={{ bitcoin_rpc_port }}
RPC_USER="{{ bitcoin_rpc_user }}"
RPC_PASSWORD="{{ bitcoin_rpc_password }}"
UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}"
# Check if bitcoind RPC is responding
check_bitcoind() {
local response
response=$(curl -s --max-time 30 \
--user "${RPC_USER}:${RPC_PASSWORD}" \
--data-binary '{"jsonrpc":"1.0","id":"healthcheck","method":"getblockchaininfo","params":[]}' \
--header 'Content-Type: application/json' \
"http://${RPC_HOST}:${RPC_PORT}" 2>&1)
if [ $? -eq 0 ]; then
# Check if response contains a non-null error
# Successful responses have "error": null, failures have "error": {...}
if echo "$response" | grep -q '"error":null\|"error": null'; then
return 0
else
return 1
fi
else
return 1
fi
}
# Push status to Uptime Kuma
push_to_uptime_kuma() {
local status=$1
local msg=$2
if [ -z "$UPTIME_KUMA_PUSH_URL" ]; then
echo "ERROR: UPTIME_KUMA_PUSH_URL not set"
return 1
fi
# URL encode spaces in message
local encoded_msg="${msg// /%20}"
if ! curl -s --max-time 10 --retry 2 -o /dev/null \
"${UPTIME_KUMA_PUSH_URL}?status=${status}&msg=${encoded_msg}&ping="; then
echo "ERROR: Failed to push to Uptime Kuma"
return 1
fi
}
# Main health check
if check_bitcoind; then
push_to_uptime_kuma "up" "OK"
exit 0
else
push_to_uptime_kuma "down" "bitcoind RPC not responding"
exit 1
fi
owner: root
group: root
mode: '0755'
- name: Install curl for health check script
apt:
name: curl
state: present
- name: Create systemd timer for Bitcoin Knots health check
copy:
dest: /etc/systemd/system/bitcoin-knots-healthcheck.timer
content: |
[Unit]
Description=Bitcoin Knots Health Check Timer
Requires=bitcoind.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=1min
Persistent=true
[Install]
WantedBy=timers.target
owner: root
group: root
mode: '0644'
- name: Create systemd service for Bitcoin Knots health check
when: uptime_kuma_enabled | default(false)
copy:
dest: /etc/systemd/system/bitcoin-knots-healthcheck.service
content: |
[Unit]
Description=Bitcoin Knots Health Check and Push to Uptime Kuma
After=network.target bitcoind.service
[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/bitcoin-knots-healthcheck-push.sh
Environment=UPTIME_KUMA_PUSH_URL=
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: '0644'
- name: Reload systemd daemon for health check
systemd:
daemon_reload: yes
- name: Enable and start Bitcoin Knots health check timer
systemd:
name: bitcoin-knots-healthcheck.timer
enabled: yes
state: started
- name: Create Uptime Kuma push monitor setup script for Bitcoin Knots
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
copy:
dest: /tmp/setup_bitcoin_knots_monitor.py
content: |
#!/usr/bin/env python3
import sys
import traceback
import yaml
from uptime_kuma_api import UptimeKumaApi, MonitorType
try:
# Load configs
with open('/tmp/ansible_config.yml', 'r') as f:
config = yaml.safe_load(f)
url = config['uptime_kuma_url']
username = config['username']
password = config['password']
monitor_name = config['monitor_name']
# Connect to Uptime Kuma
api = UptimeKumaApi(url, timeout=30)
api.login(username, password)
# Get all monitors
monitors = api.get_monitors()
# Find or create "services" group
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
if not group:
group_result = api.add_monitor(type='group', name='services')
# Refresh to get the group with id
monitors = api.get_monitors()
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
# Check if monitor already exists
existing_monitor = None
for monitor in monitors:
if monitor.get('name') == monitor_name:
existing_monitor = monitor
break
# Get ntfy notification ID
notifications = api.get_notifications()
ntfy_notification_id = None
for notif in notifications:
if notif.get('type') == 'ntfy':
ntfy_notification_id = notif.get('id')
break
if existing_monitor:
print(f"Monitor '{monitor_name}' already exists (ID: {existing_monitor['id']})")
push_token = existing_monitor.get('pushToken') or existing_monitor.get('push_token')
if not push_token:
raise ValueError("Could not find push token for monitor")
push_url = f"{url}/api/push/{push_token}"
print(f"Push URL: {push_url}")
else:
print(f"Creating push monitor '{monitor_name}'...")
api.add_monitor(
type=MonitorType.PUSH,
name=monitor_name,
parent=group['id'],
interval=60,
maxretries=3,
retryInterval=60,
notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {}
)
monitors = api.get_monitors()
new_monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
if new_monitor:
push_token = new_monitor.get('pushToken') or new_monitor.get('push_token')
if not push_token:
raise ValueError("Could not find push token for new monitor")
push_url = f"{url}/api/push/{push_token}"
print(f"Push URL: {push_url}")
api.disconnect()
print("SUCCESS")
except Exception as e:
error_msg = str(e) if str(e) else repr(e)
print(f"ERROR: {error_msg}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
mode: '0755'
- name: Create temporary config for monitor setup
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
copy:
dest: /tmp/ansible_config.yml
content: |
uptime_kuma_url: "{{ uptime_kuma_api_url }}"
username: "{{ uptime_kuma_username }}"
password: "{{ uptime_kuma_password }}"
monitor_name: "Bitcoin Knots"
mode: '0644'
- name: Run Uptime Kuma push monitor setup
when: uptime_kuma_enabled | default(false)
command: python3 /tmp/setup_bitcoin_knots_monitor.py
delegate_to: localhost
become: no
register: monitor_setup
changed_when: "'SUCCESS' in monitor_setup.stdout"
ignore_errors: yes
- name: Extract push URL from monitor setup output
set_fact:
uptime_kuma_push_url: "{{ monitor_setup.stdout | regex_search('Push URL: (https?://[^\\s]+)', '\\1') | first | default('') }}"
delegate_to: localhost
become: no
when: monitor_setup.stdout is defined
- name: Display extracted push URL
debug:
msg: "Uptime Kuma Push URL: {{ uptime_kuma_push_url }}"
when: uptime_kuma_push_url | default('') != ''
- name: Set push URL in systemd service environment
lineinfile:
path: /etc/systemd/system/bitcoin-knots-healthcheck.service
regexp: '^Environment=UPTIME_KUMA_PUSH_URL='
line: "Environment=UPTIME_KUMA_PUSH_URL={{ uptime_kuma_push_url }}"
state: present
insertafter: '^\[Service\]'
when: uptime_kuma_push_url | default('') != ''
- name: Reload systemd daemon after push URL update
systemd:
daemon_reload: yes
when: uptime_kuma_push_url | default('') != ''
- name: Restart health check timer to pick up new environment
systemd:
name: bitcoin-knots-healthcheck.timer
state: restarted
when: uptime_kuma_push_url | default('') != ''
- name: Clean up temporary files
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
file:
path: "{{ item }}"
state: absent
loop:
- /tmp/setup_bitcoin_knots_monitor.py
- /tmp/ansible_config.yml
handlers:
- name: Restart bitcoind
when: uptime_kuma_enabled | default(false)
systemd:
name: bitcoind
state: restarted
- name: Setup public Bitcoin P2P forwarding on the edge host - name: Setup public Bitcoin P2P forwarding on the edge host
hosts: edge hosts: edge
@ -746,12 +26,6 @@
vars_files: vars_files:
- ../../infra_vars.yml - ../../infra_vars.yml
- ../../services_config.yml - ../../services_config.yml
- ../../infra_secrets.yml
- ./bitcoin_knots_vars.yml
vars:
bitcoin_tailscale_hostname: "knots-box"
uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}"
tasks: tasks:
- name: Expose Bitcoin P2P through a socket proxy - name: Expose Bitcoin P2P through a socket proxy
ansible.builtin.include_role: ansible.builtin.include_role:
@ -759,134 +33,9 @@
vars: vars:
socket_proxy_name: bitcoin-p2p socket_proxy_name: bitcoin-p2p
socket_proxy_description: "Bitcoin P2P" socket_proxy_description: "Bitcoin P2P"
socket_proxy_listen_port: "{{ bitcoin_p2p_port }}" socket_proxy_listen_port: "{{ service_settings.bitcoin.p2p_port }}"
socket_proxy_upstream_host: "{{ bitcoin_tailscale_hostname }}" socket_proxy_upstream_host: "{{ service_settings.bitcoin.tailscale_hostname }}"
# These four were added by hand on vipy and were NOT in this playbook;
# writing the unit without them would have dropped FreeBind, which lets
# the socket bind before the address is up.
socket_proxy_documentation: "https://github.com/bitcoin/bitcoin" socket_proxy_documentation: "https://github.com/bitcoin/bitcoin"
socket_proxy_free_bind: true socket_proxy_free_bind: true
socket_proxy_timeout_stop_sec: 5 socket_proxy_timeout_stop_sec: 5
socket_proxy_log_to_journal: true socket_proxy_log_to_journal: true
- name: Display public endpoint
when: uptime_kuma_enabled | default(false)
debug:
msg: "Bitcoin P2P public endpoint: {{ ansible_host }}:{{ bitcoin_p2p_port }}"
# ===========================================
# Uptime Kuma TCP Monitor for Public P2P
# ===========================================
- name: Create Uptime Kuma TCP monitor setup script for Bitcoin P2P
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
copy:
dest: /tmp/setup_bitcoin_p2p_tcp_monitor.py
content: |
#!/usr/bin/env python3
import sys
import traceback
import yaml
from uptime_kuma_api import UptimeKumaApi, MonitorType
try:
with open('/tmp/ansible_bitcoin_p2p_config.yml', 'r') as f:
config = yaml.safe_load(f)
url = config['uptime_kuma_url']
username = config['username']
password = config['password']
monitor_host = config['monitor_host']
monitor_port = config['monitor_port']
monitor_name = config['monitor_name']
api = UptimeKumaApi(url, timeout=30)
api.login(username, password)
monitors = api.get_monitors()
# Find or create "services" group
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
if not group:
api.add_monitor(type='group', name='services')
monitors = api.get_monitors()
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
# Check if monitor already exists
existing = next((m for m in monitors if m.get('name') == monitor_name), None)
# Get ntfy notification ID
notifications = api.get_notifications()
ntfy_notification_id = None
for notif in notifications:
if notif.get('type') == 'ntfy':
ntfy_notification_id = notif.get('id')
break
if existing:
print(f"Monitor '{monitor_name}' already exists (ID: {existing['id']})")
print("Skipping - monitor already configured")
else:
print(f"Creating TCP monitor '{monitor_name}'...")
api.add_monitor(
type=MonitorType.PORT,
name=monitor_name,
hostname=monitor_host,
port=monitor_port,
parent=group['id'],
interval=60,
maxretries=3,
retryInterval=60,
notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {}
)
api.disconnect()
print("SUCCESS")
except Exception as e:
print(f"ERROR: {str(e)}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
mode: '0755'
- name: Create temporary config for TCP monitor setup
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
copy:
dest: /tmp/ansible_bitcoin_p2p_config.yml
content: |
uptime_kuma_url: "{{ uptime_kuma_api_url }}"
username: "{{ uptime_kuma_username }}"
password: "{{ uptime_kuma_password }}"
monitor_host: "{{ ansible_host }}"
monitor_port: {{ bitcoin_p2p_port }}
monitor_name: "Bitcoin Knots P2P Public"
mode: '0644'
- name: Run Uptime Kuma TCP monitor setup
when: uptime_kuma_enabled | default(false)
command: python3 /tmp/setup_bitcoin_p2p_tcp_monitor.py
delegate_to: localhost
become: no
register: tcp_monitor_setup
changed_when: "'SUCCESS' in tcp_monitor_setup.stdout"
ignore_errors: yes
- name: Display TCP monitor setup output
debug:
msg: "{{ tcp_monitor_setup.stdout_lines }}"
when: tcp_monitor_setup.stdout is defined
- name: Clean up TCP monitor temporary files
when: uptime_kuma_enabled | default(false)
delegate_to: localhost
become: no
file:
path: "{{ item }}"
state: absent
loop:
- /tmp/setup_bitcoin_p2p_tcp_monitor.py
- /tmp/ansible_bitcoin_p2p_config.yml

View file

@ -46,6 +46,12 @@ service_settings:
# from the edge host. A role default cannot serve the second play, so it # from the edge host. A role default cannot serve the second play, so it
# lives here rather than in roles/mempool/defaults. # lives here rather than in roles/mempool/defaults.
frontend_port: 8080 frontend_port: 8080
bitcoin:
# The P2P port is needed on two hosts: the bitcoin_knots role deploys the
# node on knots-box, and the socket-proxy play publishes the port from the
# edge host. A role default cannot reach that second play.
p2p_port: 8333
tailscale_hostname: knots-box
fulcrum: fulcrum:
# Same shape as mempool: the fulcrum role deploys on fulcrum-box, and the # Same shape as mempool: the fulcrum role deploys on fulcrum-box, and the
# socket-proxy play publishes the SSL port from the edge host. A role default # socket-proxy play publishes the SSL port from the edge host. A role default