Add headless Angor services and shared-index install guard
Demo images / Build & push demo images (push) Failing after 43s

This commit is contained in:
archipelago
2026-09-30 11:52:19 -04:00
parent 7c4169867c
commit 169bf77de6
24 changed files with 828 additions and 11 deletions
+57
View File
@@ -0,0 +1,57 @@
# Angor Indexer
Headless mainnet API endpoint for Angor. The service reuses this node's Mempool
backend and Electrum index instead of creating a second blockchain database.
An unpruned, fully synced Bitcoin node is required. Installing against a pruned
node must show the existing archival-node requirement; it must never silently
unprune or replace its Bitcoin data.
## Connect Angor
Install **Angor Indexer** in the store. Its API appears under **Services**.
In Angor settings, use `http://<node-address>:8998/` as the custom indexer origin.
The `/health` endpoint reports readiness against Mempool's indexed block height;
it returns 503 while that backend is unavailable. Index building may take time.
Browser clients require a reachable HTTPS origin with a trusted certificate.
Configure your HTTPS reverse proxy to forward to port 8998, then use that HTTPS
origin in Angor. Do not disable browser TLS checks. The API supports both
`/api/v1/` and `/api/` paths, transaction broadcast, and CORS without cookies.
This endpoint intentionally exposes public blockchain queries and transaction
broadcast through the app gate without dashboard-cookie login. It has no Bitcoin
RPC password, wallet keys, or persistent wallet data. The backend stays on the
managed container network; its private port does not become publicly exposed.
You can change network access using the node's normal access controls.
## Relay
A relay is optional. Angor can continue using its configured external relays.
Install **Angor Relay** separately to host project metadata locally, then add
`ws://<node-address>:8091/` in Angor, or a trusted `wss://` proxy origin for browser
clients. Its storage and configuration are separate from the node's internal
relay; installing or uninstalling it does not change the internal relay.
## Packaging
Build the pinned image with:
```
podman build -t source.archipelago-foundation.org/chaum/angor-indexer:1.0.1 apps/angor-indexer/container
```
The image runs as UID 101 with a read-only root filesystem and no capabilities.
Only temporary nginx state is writable. Runtime DNS is read from resolv.conf so
Mempool recreation does not require editing IP addresses or restarting this app.
No app-specific Rust installer is required.
Source documentation: [Angor's official deployment guide](https://github.com/block-core/angor/blob/869dd43cf38332dd7128a284a6bf4c1cac44c1a7/docker/DEPLOY-INDEXER-AND-RELAY.md).
The unmodified icon comes from [angor.io/images/logo-text.svg](https://angor.io/images/logo-text.svg), retrieved 2026-09-30.
Tests and release acceptance are recorded in the next-release checklist. The
health probe establishes backend availability, not a guarantee that every
address query is indexed at the latest Bitcoin tip.
Install Mempool Explorer first. The declarative `install_prerequisites` check
refuses a new adapter installation if its Mempool API component is absent, before
creating an installed-app record. It does not install or resync Bitcoin for you.
+6
View File
@@ -0,0 +1,6 @@
FROM docker.io/library/nginx:1.31.3-alpine@sha256:1d40e3eb3bf4f138de1d67193f2aa5309fcaf343eb5ffadbf5e9439de1eb1ebb
COPY nginx.conf /etc/angor-nginx.conf.template
COPY entrypoint.sh /usr/local/bin/angor-indexer
USER 101:101
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/angor-indexer"]
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
set -eu
# Resolve through the container runtime's DNS, including after dependency
# recreation. Never bake a container IP into the indexer endpoint.
DNS_RESOLVER=$(awk '/^nameserver[[:space:]]/ {print $2; exit}' /etc/resolv.conf)
case "$DNS_RESOLVER" in
''|*[!0-9a-fA-F.:]*) echo 'Container DNS resolver is unavailable' >&2; exit 1 ;;
esac
case "$DNS_RESOLVER" in *:*) DNS_RESOLVER="[$DNS_RESOLVER]" ;; esac
export DNS_RESOLVER
envsubst '${DNS_RESOLVER}' < /etc/angor-nginx.conf.template > /tmp/nginx.conf
exec nginx -c /tmp/nginx.conf -g 'daemon off;'
+63
View File
@@ -0,0 +1,63 @@
worker_processes 1;
pid /tmp/nginx.pid;
error_log /dev/stderr warn;
events { worker_connections 512; }
http {
access_log off;
server_tokens off;
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
resolver ${DNS_RESOLVER} valid=10s ipv6=off;
upstream mempool_backend {
zone mempool_backend 64k;
server mempool-api:8999 resolve;
}
server {
listen 8080;
client_max_body_size 4m;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
proxy_send_timeout 30s;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_set_header Authorization "";
proxy_set_header Cookie "";
proxy_hide_header Access-Control-Allow-Origin;
add_header Access-Control-Allow-Origin '*' always;
add_header Access-Control-Allow-Methods 'GET, HEAD, POST, OPTIONS' always;
add_header Access-Control-Allow-Headers 'Content-Type' always;
add_header Cache-Control 'no-store' always;
if ($request_method = OPTIONS) { return 204; }
# Mempool's backend uses /api/v1. Match its frontend's shorter /api
# surface too, without doubling already-versioned Angor URLs.
rewrite ^/api/(?!v1/)(.*)$ /api/v1/$1 last;
location = / {
default_type application/json;
return 200 '{"service":"Angor Indexer","network":"mainnet","api":"/api/v1","health":"/health"}\n';
}
# Readiness checks the indexing backend, not this gateway's process.
location = /health {
limit_except GET { deny all; }
proxy_pass http://mempool_backend/api/v1/blocks/tip/height;
proxy_intercept_errors on;
error_page 500 502 503 504 =503 @waiting;
}
location @waiting {
default_type application/json;
return 503 '{"status":"waiting","message":"Waiting for Bitcoin and Mempool indexing"}\n';
}
location ~ ^/api/(v1/)?tx$ {
limit_except GET POST { deny all; }
proxy_pass http://mempool_backend;
}
location /api/ {
limit_except GET { deny all; }
proxy_pass http://mempool_backend;
}
location / { return 404; }
}
}
+68
View File
@@ -0,0 +1,68 @@
app:
id: angor-indexer
name: Angor Indexer
version: 1.0.1
description: Headless Bitcoin indexer endpoint for Angor. Reuses this node’s Mempool
and Electrum index; requires a synced, unpruned Bitcoin node. Add this service’s
address as the custom indexer in Angor settings. A relay is optional and installed
separately.
category: money
install_prerequisites:
- mempool-api
upstream:
kind: github
repo: block-core/angor
container:
image: source.archipelago-foundation.org/chaum/angor-indexer:1.0.1
pull_policy: if-not-present
network: archy-net
dependencies:
- app_id: mempool-api
version: '>=3.0.0'
- bitcoin:archival
resources:
cpu_limit: 1
memory_limit: 128Mi
disk_limit: 128Mi
security:
capabilities: []
readonly_root: true
no_new_privileges: true
user: 101
network_policy: isolated
ports:
- host: 8998
container: 8080
protocol: tcp
bind: 127.0.0.1
auth: open
auth_rationale: Public Bitcoin chain-data API and validated transaction broadcast for Angor clients; no wallet keys or node RPC credentials are exposed. Browser cookie login would break machine clients.
interfaces:
main:
name: Angor Indexer API
description: Use this origin as Angor’s custom mainnet indexer URL. HTTPS is
required for browser clients.
type: api
port: 8998
protocol: http
path: /
health_check:
type: http
endpoint: http://localhost:8080
path: /health
interval: 30s
timeout: 8s
retries: 3
bitcoin_integration:
rpc_access: none
sync_required: true
pruning_support: false
metadata:
icon: /assets/img/app-icons/angor.svg
tier: optional
repo: https://github.com/block-core/angor
features:
- Angor mainnet API
- Reuses existing Mempool indexing
- No separate blockchain database
- Optional independent relay