From 0db4cf94b5f4fd4d7d35c953b49c46d1f00609a2 Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 20 Aug 2025 16:02:48 +0200 Subject: [PATCH] lnbits deployment seems to work --- 01_infra_setup.md | 6 +- 02_vps_core_services_setup.md | 31 +++ .../lnbits/deploy_lnbits_playbook.yml | 196 ++++++++++++++++++ ansible/services/lnbits/lnbits_vars.yml | 17 ++ 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 ansible/services/lnbits/deploy_lnbits_playbook.yml create mode 100644 ansible/services/lnbits/lnbits_vars.yml diff --git a/01_infra_setup.md b/01_infra_setup.md index f023578..cfe44f8 100644 --- a/01_infra_setup.md +++ b/01_infra_setup.md @@ -43,4 +43,8 @@ This describes how to prepare each machine before deploying services on them. * Run `ansible-playbook -i inventory.ini infra/01_user_and_access_setup_playbook.yml -e 'ansible_user="your root user here"'` * Then, configure firewall access, fail2ban and auditd with `ansible-playbook -i inventory.ini infra/02_firewall_and_fail2ban_playbook.yml`. Since the user we will use is now present, there is no need to specify the user anymore. -Note that, by applying these playbooks, both the root user and the `counterweight` user will use the same SSH pubkey for auth. \ No newline at end of file +Note that, by applying these playbooks, both the root user and the `counterweight` user will use the same SSH pubkey for auth. + +## GPG Keys + +Some of the backups are stored encrypted for security. To allow this, fill in the gpg variables listed in `example.inventory.ini` under the `lapy` block. diff --git a/02_vps_core_services_setup.md b/02_vps_core_services_setup.md index ac2a8b8..b406624 100644 --- a/02_vps_core_services_setup.md +++ b/02_vps_core_services_setup.md @@ -142,3 +142,34 @@ ntfy is a notifications server. ### Backups Given that ntfy is almost stateless, no backups are made. If it blows up, simply set it up again. + + +## LNBits + +LNBits is a Lightning Network wallet and accounts system. + +### Deploy + +* Decide what subdomain you want to serve LNBits on and add it to `services/lnbits/lnbits_vars.yml` on the `lnbits_subdomain`. + * Note that you will have to add a DNS entry to point to the VPS public IP. +* Run the deployment playbook: `ansible-playbook -i inventory.ini services/lnbits/deploy_lnbits_playbook.yml`. + +### Configure + +* LNBits will be available for you to create a superuser on first start. Do that and store the creds safely. +* From that point on, you can configure through the Web UI. +* Some advice around specifics of LNbits: + * The default setup uses a FakeWallet backend for testing. Configure a real Lightning backend as needed by modifying the `.env` file located or using the superuser UI. + * For security, disable the new users registration. + +### Set up backups to Lapy + +* Make sure rsync is available on the host and on Lapy. +* Run the backup playbook: `ansible-playbook -i inventory.ini services/lnbits/setup_backup_lnbits_to_lapy.yml`. +* A first backup process gets executed and then a cronjob is set up to refresh backups periodically. The script backs up both the `.env` file and the sqlite database. Backups are gpg encrypted for safety. + +### Restoring to a previous state + +* Stop LNBits. +* Overwrite the data folder with one of the backups. +* Start it up again. diff --git a/ansible/services/lnbits/deploy_lnbits_playbook.yml b/ansible/services/lnbits/deploy_lnbits_playbook.yml new file mode 100644 index 0000000..ea92a82 --- /dev/null +++ b/ansible/services/lnbits/deploy_lnbits_playbook.yml @@ -0,0 +1,196 @@ +- name: Deploy LNBits with Poetry and configure Caddy reverse proxy + hosts: vipy + become: yes + vars_files: + - ../../infra_vars.yml + - ./lnbits_vars.yml + vars: + lnbits_domain: "{{ lnbits_subdomain }}.{{ root_domain }}" + + tasks: + - name: Create lnbits directory + file: + path: "{{ lnbits_dir }}" + state: directory + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0755' + + - name: Install required system packages + apt: + name: + - python3.11 + - python3.11-venv + - python3-pip + - git + - curl + - build-essential + - pkg-config + - libffi-dev + state: present + update_cache: yes + + - name: Install Poetry + shell: | + curl -sSL https://install.python-poetry.org | python3 - + args: + creates: "{{ lookup('env', 'HOME') }}/.local/bin/poetry" + become: yes + become_user: "{{ ansible_user }}" + + - name: Add Poetry to PATH + lineinfile: + path: "{{ lookup('env', 'HOME') }}/.bashrc" + line: 'export PATH="$HOME/.local/bin:$PATH"' + state: present + become: yes + become_user: "{{ ansible_user }}" + + - name: Clone LNBits repository + git: + repo: https://github.com/lnbits/lnbits.git + dest: "{{ lnbits_dir }}/lnbits" + version: main + accept_hostkey: yes + + - name: Change ownership of LNBits directory to user + file: + path: "{{ lnbits_dir }}/lnbits" + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + recurse: yes + + - name: Install LNBits dependencies + command: $HOME/.local/bin/poetry install --only main + args: + chdir: "{{ lnbits_dir }}/lnbits" + + - name: Copy .env.example to .env + copy: + src: "{{ lnbits_dir }}/lnbits/.env.example" + dest: "{{ lnbits_dir }}/lnbits/.env" + remote_src: yes + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0644' + + + - name: Configure LNBits environment variables + lineinfile: + path: "{{ lnbits_dir }}/lnbits/.env" + regexp: "^{{ item.key }}=" + line: "{{ item.key }}={{ item.value }}" + state: present + loop: + - key: "LNBITS_BACKEND_WALLET_CLASS" + value: "FakeWallet" + - key: "LNBITS_ADMIN_UI" + value: "true" + - key: "HOST" + value: "0.0.0.0" + - key: "PORT" + value: "{{ lnbits_port }}" + - key: "LNBITS_DATA_FOLDER" + value: "{{ lnbits_data_dir }}" + - key: "LNBITS_EXTENSIONS_PATH" + value: "{{ lnbits_data_dir }}/extensions" + + - name: Create systemd service file for LNBits + copy: + dest: /etc/systemd/system/lnbits.service + content: | + [Unit] + Description=LNBits + After=network.target + + [Service] + Type=simple + User={{ ansible_user }} + WorkingDirectory={{ lnbits_dir }}/lnbits + ExecStart=/home/{{ ansible_user }}/.local/bin/poetry run lnbits + Restart=always + RestartSec=30 + Environment=PYTHONUNBUFFERED=1 + + [Install] + WantedBy=multi-user.target + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0644' + + - name: Reload systemd + systemd: + daemon_reload: yes + + - name: Enable and start LNBits service + systemd: + name: lnbits + enabled: yes + state: started + + - name: Create Fail2Ban filter for LNBits + copy: + dest: /etc/fail2ban/filter.d/lnbits.local + owner: root + group: root + mode: '0644' + content: | + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*?Invalid credentials.*?IP: .*$ + ignoreregex = + + - name: Create Fail2Ban jail for LNBits + copy: + dest: /etc/fail2ban/jail.d/lnbits.local + owner: root + group: root + mode: '0644' + content: | + [lnbits] + enabled = true + port = http,https + filter = lnbits + logpath = /var/log/lnbits/lnbits.log + maxretry = 10 + findtime = 10m + bantime = 1h + + - name: Restart fail2ban to apply changes + systemd: + name: fail2ban + state: restarted + + - name: Ensure Caddy sites-enabled directory exists + file: + path: "{{ caddy_sites_dir }}" + state: directory + owner: root + group: root + mode: '0755' + + - name: Ensure Caddyfile includes import directive for sites-enabled + lineinfile: + path: /etc/caddy/Caddyfile + line: 'import sites-enabled/*' + insertafter: EOF + state: present + backup: yes + + - name: Create Caddy reverse proxy configuration for lnbits + copy: + dest: "{{ caddy_sites_dir }}/lnbits.conf" + content: | + {{ lnbits_domain }} { + reverse_proxy localhost:{{ lnbits_port }} { + header_up X-Forwarded-Host {{ lnbits_domain }} + } + } + owner: root + group: root + mode: '0644' + + - name: Reload Caddy to apply new config + command: systemctl reload caddy diff --git a/ansible/services/lnbits/lnbits_vars.yml b/ansible/services/lnbits/lnbits_vars.yml new file mode 100644 index 0000000..89317ec --- /dev/null +++ b/ansible/services/lnbits/lnbits_vars.yml @@ -0,0 +1,17 @@ +# General +lnbits_dir: /opt/lnbits +lnbits_data_dir: "{{ lnbits_dir }}/data" +lnbits_port: 8765 + +# Caddy +caddy_sites_dir: /etc/caddy/sites-enabled +lnbits_subdomain: wallet + +# Remote access +remote_host: "{{ groups['vipy'][0] }}" +remote_user: "{{ hostvars[remote_host]['ansible_user'] }}" +remote_key_file: "{{ hostvars[remote_host]['ansible_ssh_private_key_file'] | default('') }}" + +# Local backup +local_backup_dir: "{{ lookup('env', 'HOME') }}/lnbits-backups" +backup_script_path: "{{ lookup('env', 'HOME') }}/.local/bin/lnbits_backup.sh"