diff --git a/Dockerfile b/Dockerfile index 4d8a623..d05c082 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM ghcr.io/getalby/hub:v1.8.0 AS builder +FROM ghcr.io/getalby/hub:v1.10.1 AS builder +RUN apt update; apt install -y --no-install-recommends caddy FROM debian:12-slim AS final @@ -10,5 +11,7 @@ COPY --from=builder /usr/lib/nwc/libglalby_bindings.so /usr/lib/nwc/ COPY --from=builder /usr/lib/nwc/libldk_node.so /usr/lib/nwc/ COPY --from=builder /bin/main /bin/ COPY --chmod=755 docker_entrypoint.sh /usr/local/bin/ +COPY --from=builder /usr/bin/caddy /usr/bin/ +RUN mkdir -p /etc/caddy LABEL maintainer="andrewlunde " diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 08c86cf..0000000 --- a/NOTES.md +++ /dev/null @@ -1,145 +0,0 @@ -Inspired by https://github.com/jensgertsen/sparkkiosk - -After upgrading docker, might have to... -``` -docker buildx create --use -``` - -```sh -docker buildx build --platform linux/arm64,linux/amd64 --tag horologger/albyhub:v0.4.2 --output "type=registry" . - - -docker buildx build --platform linux/arm64 --tag horologger/albyhub:v0.4.2 --load . -docker buildx build --platform linux/amd64 --tag horologger/albyhub:v0.4.2 --load . - -docker buildx build --platform linux/arm64 --tag horologger/albyhub-startos:v0.4.2 --load . - -``` - -On UmbrelPi -```sh -ssh umbrelpi - -export sparkkioskid=$(docker container list | grep sparkkiosk_web_1 | cut -d ' ' -f 1) - -docker exec -it $sparkkioskid /bin/bash - -set - -APP_PASSWORD=5587e4a23eec8a783c88cac48c1ca8f5fdf5ca3b3b2ad0ea4c8596e8e1c5f901 -APP_HIDDEN_SERVICE=http://mc3irxqk3ygz6vtrq3xbjbtk5f6mzyqdi6y7gl5j24zh2ibjtdoeujqd.onion - -LND_GRPC_CERT=/lnd/tls.cert -LND_GRPC_ENDPOINT=10.21.21.9 -LND_GRPC_MACAROON=/lnd/data/chain/bitcoin/mainnet/admin.macaroon -LND_GRPC_PORT=10009 - -sudo ./umbrel/scripts/repo checkout https://github.com/horologger/umbrelappstore.git -sudo ./umbrel/scripts/app install isviable-timeintocrypto -sudo ./umbrel/scripts/app start isviable-timeintocrypto -sudo ./umbrel/scripts/app restart isviable-timeintocrypto - -``` -On Zilla -```sh -su - alunde -docker pull horologger/albyhub:v0.4.2 -mkdir -p ~/.timeintocrypto/data -``` -First run -``` -docker run \ --e PORT=21284 \ --v data:/data \ --p 21284:21284 \ ---name timeintocrypto \ -<<<<<<< Updated upstream --it horologger/albyhub:v0.4.2 -======= --it horologger/albyhub:v0.4.2 ->>>>>>> Stashed changes -``` - -On Ragnar -```sh -su - alunde -docker pull horologger/albyhub:v0.4.2 -mkdir -p ~/.timeintocrypto/data -``` -First run -``` -docker run \ --e LN_BACKEND_TYPE="LND" \ --e LND_ADDRESS=$APP_LIGHTNING_NODE_IP:$APP_LIGHTNING_NODE_GRPC_PORT \ --e LND_CERT_FILE="/lnd/tls.cert" \ --e LND_MACAROON_FILE="/lnd/data/chain/bitcoin/$APP_BITCOIN_NETWORK/admin.macaroon" \ -<<<<<<< Updated upstream --e WORK_DIR="/data/albyhub" \ -======= --e DATABASE_URI="/data/albyhub.db" \ ->>>>>>> Stashed changes --e COOKIE_SECRET="666" \ --v /home/alunde/albyhub/data:/data \ --v /t4/lnd:/lnd:ro \ --p 8080:8080 \ ---name nwc \ -<<<<<<< Updated upstream --it horologger/albyhub:v0.4.2 -======= --it horologger/albyhub:v0.4.2 ->>>>>>> Stashed changes -``` -Subsequent runs -```sh -docker run \ --e LN_BACKEND_TYPE="LND" \ --e LND_ADDRESS=ragnar:10009 \ --e LND_CERT_FILE="/lnd/tls.cert" \ --e LND_MACAROON_FILE="/lnd/data/chain/bitcoin/bitcoin/admin.macaroon" \ -<<<<<<< Updated upstream --e WORK_DIR="/data/albyhub" \ -======= --e DATABASE_URI="/data/albyhub.db" \ ->>>>>>> Stashed changes --e COOKIE_SECRET="666" \ --v /data:/data \ --v /lnd-data:/lnd:ro \ --p 8080:8080 \ ---name nwc \ -<<<<<<< Updated upstream --it horologger/albyhub:v0.4.2 -======= --it horologger/albyhub:v0.4.2 ->>>>>>> Stashed changes - -docker run \ --e LN_BACKEND_TYPE="LND" \ --e LND_ADDRESS=ragnar:10009 \ --e LND_CERT_FILE="/lnd/tls.cert" \ --e LND_MACAROON_FILE="/lnd/data/chain/bitcoin/mainnet/admin.macaroon" \ -<<<<<<< Updated upstream --e WORK_DIR="/data/albyhub" \ -======= --e DATABASE_URI="/data/albyhub.db" \ ->>>>>>> Stashed changes --e COOKIE_SECRET="666" \ --v data:/data \ --v lnd-data:/lnd:ro \ --p 8080:8080 \ ---name nwc \ -<<<<<<< Updated upstream --it horologger/albyhub:v0.4.2 -======= --it horologger/albyhub:v0.4.2 ->>>>>>> Stashed changes - -``` -Inspect -```sh -docker exec -it nwc /bin/bash -``` -Clean up -```sh -docker stop nwc -docker rm nwc -``` diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh index 2b2fc52..e44051b 100644 --- a/docker_entrypoint.sh +++ b/docker_entrypoint.sh @@ -1,19 +1,143 @@ #!/bin/sh -export LN_BACKEND_TYPE="LND" -export LND_ADDRESS="lnd.embassy:10009" #the LND gRPC address, eg. localhost:10009 (used with the LND backend) -export LND_CERT_FILE="/mnt/lnd/tls.cert" #the location where LND's tls.cert file can be found (used with the LND backend) -export LND_MACAROON_FILE="/mnt/lnd/admin.macaroon" #the location where LND's admin.macaroon file can be found (used with the LND backend) +printf "\n\n [i] Starting Alby Hub ...\n\n" + +# Read current LN setup from config +LN_VALUE=$(grep 'lightning:' /data/start9/config.yaml | cut -d ' ' -f 2) + +# File to track initial setup (lnd or alby) +SETUP_FILE="/data/start9/initial_setup" +WORK_DIR="/data/albyhub" +BACKUP_DIR="/data/start9/backups" + +# Ensure the backup directory exists +mkdir -p "$BACKUP_DIR" + +# Determine the initial setup +if [ -f "$SETUP_FILE" ]; then + INITIAL_SETUP=$(cat "$SETUP_FILE") +else + INITIAL_SETUP="$LN_VALUE" + echo "$INITIAL_SETUP" >"$SETUP_FILE" # Store initial setup if it doesn't exist +fi +# Function to create a tar.gz backup of the albyhub directory +backup_dir() { + suffix="$INITIAL_SETUP" + tar_file="$BACKUP_DIR/${suffix}_backup.tar.gz" + + # Create a tar.gz file containing the albyhub directory + tar -czf "$tar_file" -C "/data" albyhub 2>/dev/null + echo "[i] Created backup: $tar_file" +} +# Function to restore the albyhub directory from a tar.gz backup +restore_dir() { + suffix="$1" # Either 'lnd' or 'alby' + tar_file="$BACKUP_DIR/${suffix}_backup.tar.gz" + + if [ -f "$tar_file" ]; then + rm -rf "$WORK_DIR" + tar -xzf "$tar_file" -C "/data" + echo "[i] Restored from backup: $tar_file" + else + echo "[i] No $suffix backup found." + fi +} + +# Handling different setups +if [ "$INITIAL_SETUP" != "$LN_VALUE" ]; then + if [ "$INITIAL_SETUP" = "lnd" ] && [ "$LN_VALUE" = "alby" ]; then + echo "[i] Switching from LND to Alby/LDK..." + + # Backup current LND directory + backup_dir + + # Restore Alby backup if it exists, otherwise start fresh + if [ -f "$BACKUP_DIR/alby_backup.tar.gz" ]; then + restore_dir "alby" + else + echo "[i] No Alby/LDK backup found, starting fresh..." + rm -rf "$WORK_DIR" + mkdir -p "$WORK_DIR" + fi + + # Update the initial setup to 'alby' + echo "alby" >"$SETUP_FILE" + + elif [ "$INITIAL_SETUP" = "alby" ] && [ "$LN_VALUE" = "lnd" ]; then + echo "[i] Switching from Alby/LDK to LND..." + + # Backup current Alby directory + backup_dir + + # Restore LND backup if it exists, otherwise clean up the data directory for initial LND setup + if [ -f "$BACKUP_DIR/lnd_backup.tar.gz" ]; then + restore_dir "lnd" + else + echo "[i] No LND backup found, cleaning up the data directory for initial LND setup..." + rm -rf "$WORK_DIR" + mkdir -p "$WORK_DIR" + fi + + # Update the initial setup to 'lnd' + echo "lnd" >"$SETUP_FILE" + fi +fi + +# Set up environment variables based on LN_VALUE +if [ "$LN_VALUE" = "lnd" ]; then + export LN_BACKEND_TYPE="LND" + export LND_ADDRESS="lnd.embassy:10009" # the LND gRPC address + export LND_CERT_FILE="/mnt/lnd/tls.cert" # the location where LND's tls.cert file can be found + export LND_MACAROON_FILE="/mnt/lnd/admin.macaroon" # the location where LND's admin.macaroon file can be found + export ENABLE_ADVANCED_SETUP=false +else + # Default to Alby/LDK if lightning value is not "lnd" + export LN_BACKEND_TYPE="LDK" + unset LND_ADDRESS + unset LND_CERT_FILE + unset LND_MACAROON_FILE +fi + export WORK_DIR="/data/albyhub" -export PORT=8080 #the port on which the app should listen on (default='blah' #8080) +export PORT=8080 #the port on which the app should listen on (default='blah' #8080) export LOG_EVENTS=true # makes debugging easier -# export TOR_ADDRESS=$(yq e '.tor-address' /data/start9/config.yaml) -# export LAN_ADDRESS=$(yq e '.lan-address' /data/start9/config.yaml) -printf "\n\n [i] Starting Alby Hub ...\n\n" -echo "LN Backend Type: " $LN_BACKEND_TYPE -echo "LN Address: " $LND_ADDRESS -echo "LND Cert: " $LND_CERT_FILE -echo "LND Macaroon: " $LND_MACAROON_FILE +# Reverse proxy configuration (aka Firefox patch) +cat </etc/caddy/Caddyfile +{ + admin off + servers { + protocols h1 h2c h3 + } +} + +:8443 { + tls /mnt/cert/main.cert.pem /mnt/cert/main.key.pem + reverse_proxy albyhub.embassy:8080 +} +EOF + +# Output some debug information +echo "LN Backend Type: $LN_BACKEND_TYPE" +if [ "$LN_VALUE" = "lnd" ]; then + echo "LN Address: $LND_ADDRESS" + echo "LND Cert: $LND_CERT_FILE" + echo "LND Macaroon: $LND_MACAROON_FILE" +fi + +# Set up a trap to catch INT signal for graceful shutdown and start +_term() { + echo "Caught INT signal!" + kill -INT "$alby_process" 2>/dev/null + kill -INT "$caddy_process" 2>/dev/null +} + +main & +alby_process=$! + +caddy run --config /etc/caddy/Caddyfile & +caddy_process=$! + +trap _term INT -exec /bin/main +wait $caddy_process $alby_process diff --git a/instructions.md b/instructions.md index 0410f63..1e4c8be 100644 --- a/instructions.md +++ b/instructions.md @@ -1,22 +1,31 @@ # Quick Start Guide for Alby Hub -1. **Launch Alby Hub** - Click the `Launch UI` button to start Alby Hub. +1. **Configure Alby Hub** + In the Alby Hub configuration settings, select your preferred Lightning implementation: -2. **Get Started** - On the Alby Welcome screen, click **Get Started (LND)**. + - **LND on this server**: This option tells Alby Hub to use the LND node installed on this StartOS server. It is the more sovereign and secure option, allowing full control over your node. + - **Alby Hub embedded light node**: This option tells Alby Hub to use its own, built-in light node. This option is convenient but offers less control over your node. -3. **Create a Strong Password** - Set a strong password for your Alby Hub account. It’s recommended to store this password securely in your self-hosted Vaultwarden. +2. **Start the Service** + After configuring, start the Alby Hub service. -4. **Connect Your Alby Account** +3. **Launch Alby Hub** + Click the `Launch UI` button to open the Alby Hub interface. + +4. **Get Started** + On the Alby Welcome screen, click the **Get Started** button. The button will display either (LND) or (LDK) based on your chosen configuration. + +5. **Create a Strong Password** + Set a strong password for your Alby Hub account. It's recommended to store this password securely in your self-hosted Vaultwarden. If you are using the Alby Hub embedded light node, it is critical you do not lose your password, as it will result in loss of funds. + +6. **Connect Your Alby Account** Follow the on-screen instructions to connect your Alby account. -5. **All Set!** - You’re done! Your Alby Hub is now ready to use. +7. **All Set!** + You're done! Your Alby Hub is now ready to use. ## Getting Help -For more information and help about Alby visit [getalby.com](https://getalby.com) +For more information and help about Alby Hub visit [albyhub.com](https://albyhub.com/) You can also ask for assistance in the [Start9 community chats](https://start9.com/contact). diff --git a/manifest.yaml b/manifest.yaml index a25f446..1d6da78 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,12 +1,12 @@ id: albyhub title: Alby Hub -version: 1.8.0 +version: 1.10.1 release-notes: Alby Hub initial release license: Apache-2.0 -wrapper-repo: "https://github.com/horologger/albyhub-startos" +wrapper-repo: "https://github.com/start9labs/albyhub-startos" upstream-repo: "https://github.com/getAlby/hub" support-site: "https://github.com/getAlby/hub/issues" -marketing-site: "https://getalby.com/" +marketing-site: "https://albyhub.com/" build: ["make"] description: short: Self-custodial Lightning wallet with integrated node. @@ -23,22 +23,26 @@ main: args: [] mounts: main: /data + cert: /mnt/cert lnd: /mnt/lnd health-checks: web-ui: name: Web UI success-message: Alby Hub is ready type: script -config: ~ - # get: - # type: script - # set: - # type: script +config: + get: + type: script + set: + type: script properties: ~ environment: ~ volumes: main: type: data + cert: + type: certificate + interface-id: main lnd: type: pointer package-id: lnd @@ -52,6 +56,7 @@ interfaces: tor-config: port-mapping: 80: "8080" + 443: "8443" lan-config: 443: ssl: true @@ -63,10 +68,10 @@ interfaces: dependencies: lnd: version: ">=0.16.0 <0.20.0" - description: Nostr Wallet Connect works with your LND + description: Alby Hub works with your LND requirement: - type: "required" - how: Use the LND instance by default + type: "opt-in" + how: "Can alternatively use Alby's LDK node" config: ~ backup: create: diff --git a/scripts/procedures/getConfig.ts b/scripts/procedures/getConfig.ts index db04636..1ee7f05 100644 --- a/scripts/procedures/getConfig.ts +++ b/scripts/procedures/getConfig.ts @@ -3,22 +3,27 @@ import { compat, types as T } from "../deps.ts"; export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ - "tor-address": { - "name": "Tor Address", - "description": "The Tor address of the network interface", - "type": "pointer", - "subtype": "package", - "package-id": "albyhub", - "target": "tor-address", - "interface": "main", + "tor-address": { + name: "Tor Address", + description: "The Tor address of the network interface", + type: "pointer", + subtype: "package", + "package-id": "albyhub", + target: "tor-address", + interface: "main", + }, + + lightning: { + name: "Lightning Implementation", + description: + "Choose the Lightning implementation to use with Alby Hub.

LND on this server: This option tells Alby Hub to use the LND node installed on this StartOS server. It is the more sovereign and secure option, allowing full control over your node.

Alby embedded light node: This option tells Alby Hub to use its own, built-in light node. This option is convenient but offers less control over your node.", + type: "enum", + values: ["lnd", "alby"], + "value-names": { + lnd: "LND on this server", + alby: "Alby Hub embedded light node", }, - "lan-address": { - "name": "LAN Address", - "description": "The LAN address of the network interface", - "type": "pointer", - "subtype": "package", - "package-id": "albyhub", - "target": "lan-address", - "interface": "main", - } - }); + default: "lnd", + // "warning": "The Alby embedded node (LDK) is a convenient starting option, but for increased sovereignty and security, it's recommended to switch to LND when possible." + }, +}); diff --git a/scripts/procedures/migrations.ts b/scripts/procedures/migrations.ts index bbc5071..28df7a1 100644 --- a/scripts/procedures/migrations.ts +++ b/scripts/procedures/migrations.ts @@ -1,4 +1,4 @@ import { compat, types as T } from "../deps.ts"; export const migration: T.ExpectedExports.migration = compat.migrations - .fromMapping({}, "1.8.0" ); + .fromMapping({}, "1.10.1" ); diff --git a/scripts/procedures/setConfig.ts b/scripts/procedures/setConfig.ts index ca6f4b2..c911fed 100644 --- a/scripts/procedures/setConfig.ts +++ b/scripts/procedures/setConfig.ts @@ -2,17 +2,21 @@ import { compat, types as T } from "../deps.ts"; -// export const setConfig = compat.setConfig; +// deno-lint-ignore require-await +export const setConfig: T.ExpectedExports.setConfig = async ( + effects: T.Effects, + newConfig: T.Config +) => { + // deno-lint-ignore no-explicit-any + const dependsOnLND: { [key: string]: string[] } = + (newConfig as any)?.lightning === "lnd" ? { lnd: [] } : {}; -export const setConfig: T.ExpectedExports.setConfig = async (effects, input ) => { - // deno-lint-ignore no-explicit-any - const newConfig = input as any; - - const depsLnd: T.DependsOn = newConfig?.implementation === "LndRestWallet" ? {lnd: []} : {} - const depsCln: T.DependsOn = newConfig?.implementation === "CLightningWallet" ? {"c-lightning": []} : {} - - return await compat.setConfig(effects,input, { - ...depsLnd, - ...depsCln, - }) - } \ No newline at end of file + // deno-lint-ignore no-explicit-any + const dependsOnAlby: { [key: string]: string[] } = + (newConfig as any)?.lightning === "alby" ? { alby: [] } : {}; + + return compat.setConfig(effects, newConfig, { + ...dependsOnLND, + ...dependsOnAlby, + }); +};