From abe57c969320dcb85764b11280df6d64f2d7427a Mon Sep 17 00:00:00 2001 From: /rootzoll Date: Fri, 4 Oct 2024 23:15:19 +0200 Subject: [PATCH] #4568 LNbits install fix for AMD & VMs + update lnbits to v0.12.11 (#4768) * #4568 add missing dependencies for AMD64 * Update: LNbits 0.12.11 * #4765 add check postgres installed check * #3264 add nginx header adjustments * Fix postgres bats test (#4769) * #4204 move .env to data disc * letsencrypt takes care of selfsigned certs --- .github/workflows/test-bats.yml | 4 +- CHANGES.md | 1 + home.admin/_background.sh | 12 ++ home.admin/_provision_.sh | 2 +- .../nginx/sites-available/lnbits_ssl.conf | 1 - .../blitz.subscriptions.letsencrypt.py | 12 +- home.admin/config.scripts/blitz.web.sh | 25 +--- home.admin/config.scripts/bonus.lnbits.sh | 130 +++++++++++------- home.admin/config.scripts/bonus.postgresql.sh | 79 ++++++----- ...letsencrypt.sh => internet.letsencrypt.sh} | 82 ++++++++--- .../config.scripts/internet.selfsignedcert.sh | 15 +- test/bonus.postgresql-13.bats | 2 +- 12 files changed, 222 insertions(+), 143 deletions(-) rename home.admin/config.scripts/{bonus.letsencrypt.sh => internet.letsencrypt.sh} (78%) diff --git a/.github/workflows/test-bats.yml b/.github/workflows/test-bats.yml index b4a64a78a..47a3f3179 100644 --- a/.github/workflows/test-bats.yml +++ b/.github/workflows/test-bats.yml @@ -11,13 +11,13 @@ on: paths: - "home.admin/config.scripts/bonus.postgresql.sh" pull_request: - branches: ["dev"] + branches: ["*"] paths: - "home.admin/config.scripts/bonus.postgresql.sh" jobs: run-bats-tests: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/CHANGES.md b/CHANGES.md index c486256be..fe07db3f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ - Update: LNDK 0.2.0 (Pay BOLT12 offers with LND) [details](https://github.com/lndk-org/lndk/releases/tag/v0.2.0) - Update: Helipad (Podcasting 2.0 Boostagram reader) v0.2.0 [details](https://github.com/Podcastindex-org/helipad/releases/tag/v0.2.0) - Update: Mempool 3.0.0 [details](https://github.com/mempool/mempool/releases/tag/v3.0.0) +- Update: LNbits 0.12.11 [details](https://github.com/lnbits/lnbits/releases/tag/0.12.11) - Update: Telegraf Metrics for InfluxDB/Grafana [details](https://github.com/raspiblitz/raspiblitz/tree/dev/home.admin/assets/telegraf/README.md) - Update: RTL v0.15.2 [details](https://github.com/Ride-The-Lightning/RTL/releases/tag/v0.15.2) - Update: Jam (JoinMarket Web UI) v0.3.0 [details](https://github.com/joinmarket-webui/jam/releases/tag/v0.3.0) diff --git a/home.admin/_background.sh b/home.admin/_background.sh index 345b98158..fbcb96031 100755 --- a/home.admin/_background.sh +++ b/home.admin/_background.sh @@ -696,6 +696,18 @@ do fi fi + ############################### + # SSL CERT RENEWAL + ############################### + # check every 10min + recheckCert=$((($counter % 600)+1)) + if [ ${recheckCert} -eq 10 ]; then + + # TODO: check if letsencrypt certs are valid for more than 10 days & renew if not + + # sets self-signed certs or letsencrypt certs (if valid) to nginx + /home/admin/config.scripts/internet.letsencrypt.sh refresh-nginx-certs + fi ############################### # SUBSCRIPTION RENEWS diff --git a/home.admin/_provision_.sh b/home.admin/_provision_.sh index 744c8b8c7..a53f56750 100755 --- a/home.admin/_provision_.sh +++ b/home.admin/_provision_.sh @@ -621,7 +621,7 @@ fi if [ "${letsencrypt}" = "on" ]; then echo "Provisioning letsencrypt - run config script" >> ${logFile} /home/admin/_cache.sh set message "Setup letsencrypt" - sudo -u admin /home/admin/config.scripts/bonus.letsencrypt.sh on >> ${logFile} 2>&1 + sudo -u admin /home/admin/config.scripts/internet.letsencrypt.sh on >> ${logFile} 2>&1 else echo "Provisioning letsencrypt - keep default" >> ${logFile} fi diff --git a/home.admin/assets/nginx/sites-available/lnbits_ssl.conf b/home.admin/assets/nginx/sites-available/lnbits_ssl.conf index 2ab8c93f4..b6023e045 100644 --- a/home.admin/assets/nginx/sites-available/lnbits_ssl.conf +++ b/home.admin/assets/nginx/sites-available/lnbits_ssl.conf @@ -7,7 +7,6 @@ server { include /etc/nginx/snippets/ssl-params.conf; include /etc/nginx/snippets/ssl-certificate-app-data.conf; - include /etc/nginx/snippets/gzip-params.conf; access_log /var/log/nginx/access_lnbits.log; diff --git a/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py b/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py index c8a9d2383..1c1a4b8a9 100755 --- a/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py +++ b/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py @@ -229,7 +229,7 @@ def subscriptions_new(ip, dnsservice, domain, token, target): raise BlitzError("domain already exists", domain) # make sure lets encrypt client is installed - os.system("/home/admin/config.scripts/bonus.letsencrypt.sh on") + os.system("/home/admin/config.scripts/internet.letsencrypt.sh on") # dyndns real_ip = ip @@ -288,9 +288,9 @@ def subscriptions_new(ip, dnsservice, domain, token, target): # run the ACME script print("# Running letsencrypt ACME script ...") - print("# /home/admin/config.scripts/bonus.letsencrypt.sh issue-cert {0} {1} {2} {3}".format(dnsservice, domain, token, target)) + print("# /home/admin/config.scripts/internet.letsencrypt.sh issue-cert {0} {1} {2} {3}".format(dnsservice, domain, token, target)) acme_result = subprocess.Popen( - ["/home/admin/config.scripts/bonus.letsencrypt.sh", "issue-cert", dnsservice, domain, token, target], + ["/home/admin/config.scripts/internet.letsencrypt.sh", "issue-cert", dnsservice, domain, token, target], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8') out, err = acme_result.communicate() eprint(str(out)) @@ -318,9 +318,9 @@ def subscriptions_cancel(s_id): # run the ACME script to remove cert if removed_cert: - print("# /home/admin/config.scripts/bonus.letsencrypt.sh remove-cert {0} {1}".format(removed_cert['id'], removed_cert['target'])) + print("# /home/admin/config.scripts/internet.letsencrypt.sh remove-cert {0} {1}".format(removed_cert['id'], removed_cert['target'])) acme_result = subprocess.Popen( - ["/home/admin/config.scripts/bonus.letsencrypt.sh", "remove-cert", removed_cert['id'], + ["/home/admin/config.scripts/internet.letsencrypt.sh", "remove-cert", removed_cert['id'], removed_cert['target']], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8') out, err = acme_result.communicate() if out.find("error=") > -1: @@ -336,7 +336,7 @@ def subscriptions_cancel(s_id): # deinstall letsencrypt/dyndns if this was last subscription if len(subs['subscriptions_letsencrypt']) == 0: - os.system("/home/admin/config.scripts/bonus.letsencrypt.sh off") + os.system("/home/admin/config.scripts/internet.letsencrypt.sh off") os.system("/home/admin/config.scripts/internet.dyndomain.sh off") def get_subscription(subscription_id): diff --git a/home.admin/config.scripts/blitz.web.sh b/home.admin/config.scripts/blitz.web.sh index 7fd8b8255..6cc82c234 100755 --- a/home.admin/config.scripts/blitz.web.sh +++ b/home.admin/config.scripts/blitz.web.sh @@ -127,28 +127,9 @@ elif [ "$1" = "https-on" ]; then if ! [ -f /mnt/hdd/app-data/nginx/tls.cert ];then - if [ -f /mnt/hdd/lnd/tls.cert ]; then - # use LND cert by default - echo "# use LND cert for: /mnt/hdd/app-data/nginx/tls.cert" - sudo ln -sf /mnt/hdd/lnd/tls.cert /mnt/hdd/app-data/nginx/tls.cert - sudo ln -sf /mnt/hdd/lnd/tls.key /mnt/hdd/app-data/nginx/tls.key - sudo ln -sf /mnt/hdd/lnd/tls.cert /mnt/hdd/app-data/nginx/tor_tls.cert - sudo ln -sf /mnt/hdd/lnd/tls.key /mnt/hdd/app-data/nginx/tor_tls.key - else - echo "# exists /mnt/hdd/app-data/nginx/tls.cert" - - # create a self-signed cert if the LND cert is not present - /home/admin/config.scripts/internet.selfsignedcert.sh create - - sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.cert \ - /mnt/hdd/app-data/nginx/tls.cert - sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.key \ - /mnt/hdd/app-data/nginx/tls.key - sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.cert \ - /mnt/hdd/app-data/nginx/tor_tls.cert - sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.key \ - /mnt/hdd/app-data/nginx/tor_tls.key - fi + # make sure certs exists + /home/admin/config.scripts/internet.letsencrypt.sh refresh-nginx-certs + else echo "# exists /mnt/hdd/app-data/nginx/tls.cert" fi diff --git a/home.admin/config.scripts/bonus.lnbits.sh b/home.admin/config.scripts/bonus.lnbits.sh index 1cf5e9b19..4785c9773 100644 --- a/home.admin/config.scripts/bonus.lnbits.sh +++ b/home.admin/config.scripts/bonus.lnbits.sh @@ -3,7 +3,7 @@ # https://github.com/lnbits/lnbits # https://github.com/lnbits/lnbits/releases -tag="0.12.8" +tag="v0.12.11" VERSION="${tag}" # command info @@ -29,13 +29,18 @@ fi echo "# Running: 'bonus.lnbits.sh $*'" source /mnt/hdd/raspiblitz.conf +lnbitsDataDir="/mnt/hdd/app-data/LNBits/data" +lnbitsConfig="${lnbitsDataDir}/.env" + function postgresConfig() { + sudo /home/admin/config.scripts/bonus.postgresql.sh on || exit 1 echo "# Generate the database lnbits_db" # migrate clean up source <(/home/admin/_cache.sh get LNBitsMigrate) if [ "${LNBitsMigrate}" == "on" ]; then + echo "# LNBitsMigrate=on --> Cleaning old lnbits_db & lnbits_user" sudo -u postgres psql -c "drop database lnbits_db;" sudo -u postgres psql -c "drop user lnbits_user;" fi @@ -99,11 +104,11 @@ function revertMigration() { # update config echo "# Configure config .env" + sudo sed -i "/^LNBITS_DATABASE_URL=/d" $lnbitsConfig # clean up - sudo sed -i "/^LNBITS_DATABASE_URL=/d" /home/lnbits/lnbits/.env - sudo sed -i "/^LNBITS_DATA_FOLDER=/d" /home/lnbits/lnbits/.env - sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATA_FOLDER=/d" $lnbitsConfig + sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> ${lnbitsConfig}" # start service echo "# Start LNBits" @@ -453,7 +458,7 @@ if [ "$1" = "prestart" ]; then # get if its for lnd or cl service echo "## lnbits.service PRESTART CONFIG" - echo "# --> /home/lnbits/lnbits/.env" + echo "# --> ${lnbitsConfig}" # set values based in funding source in raspiblitz config # portprefix is "" | 1 | 3 @@ -504,23 +509,23 @@ if [ "$1" = "prestart" ]; then echo "# Updating LND TLS & macaroon data fresh for LNbits config ..." # set tls.cert path (use | as separator to avoid escaping file path slashes) - sed -i "s|^LND_REST_CERT=.*|LND_REST_CERT=/mnt/hdd/app-data/lnd/tls.cert|g" /home/lnbits/lnbits/.env + sed -i "s|^LND_REST_CERT=.*|LND_REST_CERT=/mnt/hdd/app-data/lnd/tls.cert|g" $lnbitsConfig # set macaroon path info in .env - USING HEX IMPORT - chmod 600 /home/lnbits/lnbits/.env + chmod 600 $lnbitsConfig macaroonAdminHex=$(xxd -ps -u -c 1000 /mnt/hdd/app-data/lnd/data/chain/${LNBitsNetwork}/${LNBitsChain}net/admin.macaroon) macaroonInvoiceHex=$(xxd -ps -u -c 1000 /mnt/hdd/app-data/lnd/data/chain/${LNBitsNetwork}/${LNBitsChain}net/invoice.macaroon) macaroonReadHex=$(xxd -ps -u -c 1000 /mnt/hdd/app-data/lnd/data/chain/${LNBitsNetwork}/${LNBitsChain}net/readonly.macaroon) - sed -i "s/^LND_REST_ADMIN_MACAROON=.*/LND_REST_ADMIN_MACAROON=${macaroonAdminHex}/g" /home/lnbits/lnbits/.env - sed -i "s/^LND_REST_INVOICE_MACAROON=.*/LND_REST_INVOICE_MACAROON=${macaroonInvoiceHex}/g" /home/lnbits/lnbits/.env - sed -i "s/^LND_REST_READ_MACAROON=.*/LND_REST_READ_MACAROON=${macaroonReadHex}/g" /home/lnbits/lnbits/.env + sed -i "s/^LND_REST_ADMIN_MACAROON=.*/LND_REST_ADMIN_MACAROON=${macaroonAdminHex}/g" $lnbitsConfig + sed -i "s/^LND_REST_INVOICE_MACAROON=.*/LND_REST_INVOICE_MACAROON=${macaroonInvoiceHex}/g" $lnbitsConfig + sed -i "s/^LND_REST_READ_MACAROON=.*/LND_REST_READ_MACAROON=${macaroonReadHex}/g" $lnbitsConfig # set the REST endpoint (use | as separator to avoid escaping slashes) - sed -i "s|^LND_REST_ENDPOINT=.*|LND_REST_ENDPOINT=https://127.0.0.1:${portprefix}8080|g" /home/lnbits/lnbits/.env + sed -i "s|^LND_REST_ENDPOINT=.*|LND_REST_ENDPOINT=https://127.0.0.1:${portprefix}8080|g" $lnbitsConfig elif [ "${LNBitsLightning}" == "cl" ]; then - isUsingCL=$(cat /home/lnbits/lnbits/.env | grep -c "LNBITS_BACKEND_WALLET_CLASS=CLightningWallet") + isUsingCL=$(cat $lnbitsConfig | grep -c "LNBITS_BACKEND_WALLET_CLASS=CLightningWallet") if [ "${isUsingCL}" != "1" ]; then - echo "# FAIL: /home/lnbits/lnbits/.env not set to CLN" + echo "# FAIL: ${lnbitsConfig} not set to CLN" exit 1 fi @@ -632,6 +637,9 @@ if [ "$1" = "install" ]; then echo "# *** INSTALL LNBITS ***" echo "# githubUser=$githubUser tag=$tag" + # make sure dependencies are installed + sudo apt-get install -y pkg-config build-essential python3-dev libsecp256k1-dev libffi-dev libgmp-dev + # add lnbits user echo "*** Add the 'lnbits' user ***" sudo adduser --system --group --home /home/lnbits lnbits @@ -648,7 +656,7 @@ if [ "$1" = "install" ]; then echo "# installing application dependencies" cd /home/lnbits/lnbits || exit 1 - # check if poetry in installed, if not install it + # check if poetry is installed if ! sudo -u lnbits which poetry; then echo "# install poetry" sudo pip3 config set global.break-system-packages true @@ -657,14 +665,21 @@ if [ "$1" = "install" ]; then fi echo "# install" - sudo -u lnbits poetry install + exitCode=0 + if sudo -u lnbits poetry install; then + echo "Poetry install completed successfully." + else + echo "Error: Poetry install failed (see above).. waiting 10 seconds" + exitCode=1 + sleep 10 + fi # make sure default virtaulenv is used sudo apt-get remove -y python3-virtualenv 2>/dev/null sudo pip uninstall -y virtualenv 2>/dev/null sudo apt-get install -y python3-virtualenv - exit 0 + exit $exitCode fi # remove from system @@ -758,28 +773,38 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then exit 1 fi - # prepare .env file + # prepare data dir file + sudo mkdir -p $lnbitsDataDir + sudo chown lnbits:lnbits -R $lnbitsDataDir + echo "# preparing env file" + # delete old .env file or old symbolic link sudo rm /home/lnbits/lnbits/.env 2>/dev/null - sudo -u lnbits touch /home/lnbits/lnbits/.env + # make sure .env file exists at data drive + sudo -u lnbits touch $lnbitsConfig + sudo chown lnbits:lnbits $lnbitsConfig + # crete symbolic link + sudo -u lnbits ln -s $lnbitsConfig /home/lnbits/lnbits/.env # activate admin user - sudo sed -i "/^LNBITS_ADMIN_UI=/d" /home/lnbits/lnbits/.env - sudo bash -c "echo 'LNBITS_ADMIN_UI=true' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_ADMIN_UI=/d" $lnbitsConfig + sudo bash -c "echo 'LNBITS_ADMIN_UI=true' >> ${lnbitsConfig}" if [ ! -e /mnt/hdd/app-data/LNBits/database.sqlite3 ]; then echo "# install database: PostgreSQL" + # POSTGRES postgresConfig - # new data directory - sudo mkdir -p /mnt/hdd/app-data/LNBits/data - # config update # example: postgres://:@/ - sudo bash -c "echo 'LNBITS_DATABASE_URL=postgres://postgres:postgres@localhost:5432/lnbits_db' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits/data' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATABASE_URL=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LNBITS_DATA_FOLDER=/d" $lnbitsConfig 2>/dev/null + sudo bash -c "echo 'LNBITS_DATABASE_URL=postgres://postgres:postgres@localhost:5432/lnbits_db' >> ${lnbitsConfig}" + sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits/data' >> ${lnbitsConfig}" + else + echo "# install database: SQLite" /home/admin/config.scripts/blitz.conf.sh set LNBitsDB "SQLite" @@ -787,14 +812,11 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then sudo mkdir -p /mnt/hdd/app-data/LNBits # config update - sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATA_FOLDER=/d" $lnbitsConfig 2>/dev/null + sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> ${lnbitsConfig}" fi sudo chown lnbits:lnbits -R /mnt/hdd/app-data/LNBits - # let switch command part do the detail config - /home/admin/config.scripts/bonus.lnbits.sh switch ${fundingsource} - cd /home/lnbits/lnbits || exit 1 - # open firewall echo echo "*** Updating Firewall ***" @@ -842,6 +864,10 @@ PrivateDevices=true WantedBy=multi-user.target EOF + # let switch command part do the detail config + /home/admin/config.scripts/bonus.lnbits.sh switch ${fundingsource} + cd /home/lnbits/lnbits || exit 1 + sudo systemctl enable lnbits source <(/home/admin/_cache.sh get state) @@ -946,14 +972,14 @@ if [ "$1" = "switch" ]; then echo "##############" # remove all old possible settings for former funding source (clean state) - sudo sed -i "/^LNBITS_BACKEND_WALLET_CLASS=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LND_REST_ENDPOINT=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LND_REST_CERT=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LND_REST_ADMIN_MACAROON=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LND_REST_INVOICE_MACAROON=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LND_REST_READ_MACAROON=/d" /home/lnbits/lnbits/.env 2>/dev/null + sudo sed -i "/^LNBITS_BACKEND_WALLET_CLASS=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LND_REST_ENDPOINT=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LND_REST_CERT=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LND_REST_ADMIN_MACAROON=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LND_REST_INVOICE_MACAROON=/d" $lnbitsConfig 2>/dev/null + sudo sed -i "/^LND_REST_READ_MACAROON=/d" $lnbitsConfig 2>/dev/null sudo /usr/sbin/usermod -G lnbits lnbits - sudo sed -i "/^CLIGHTNING_RPC=/d" /home/lnbits/lnbits/.env 2>/dev/null + sudo sed -i "/^CLIGHTNING_RPC=/d" $lnbitsConfig 2>/dev/null # LND CONFIG if [ "${fundingsource}" == "lnd" ] || [ "${fundingsource}" == "tlnd" ] || [ "${fundingsource}" == "slnd" ]; then @@ -966,12 +992,12 @@ if [ "$1" = "switch" ]; then # prepare config entries in lnbits config for lnd echo "# preparing lnbits config for lnd" - sudo bash -c "echo 'LNBITS_BACKEND_WALLET_CLASS=LndRestWallet' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LND_REST_ENDPOINT=https://127.0.0.1:8080' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LND_REST_CERT=' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LND_REST_ADMIN_MACAROON=' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LND_REST_INVOICE_MACAROON=' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'LND_REST_READ_MACAROON=' >> /home/lnbits/lnbits/.env" + sudo bash -c "echo 'LNBITS_BACKEND_WALLET_CLASS=LndRestWallet' >> ${lnbitsConfig}" + sudo bash -c "echo 'LND_REST_ENDPOINT=https://127.0.0.1:8080' >> ${lnbitsConfig}" + sudo bash -c "echo 'LND_REST_CERT=' >> ${lnbitsConfig}" + sudo bash -c "echo 'LND_REST_ADMIN_MACAROON=' >> ${lnbitsConfig}" + sudo bash -c "echo 'LND_REST_INVOICE_MACAROON=' >> ${lnbitsConfig}" + sudo bash -c "echo 'LND_REST_READ_MACAROON=' >> ${lnbitsConfig}" fi @@ -996,8 +1022,8 @@ if [ "$1" = "switch" ]; then fi echo "# preparing lnbits config for CLN" - sudo bash -c "echo 'LNBITS_BACKEND_WALLET_CLASS=CLightningWallet' >> /home/lnbits/lnbits/.env" - sudo bash -c "echo 'CLIGHTNING_RPC=/home/bitcoin/.lightning/bitcoin${clrpcsubdir}/lightning-rpc' >> /home/lnbits/lnbits/.env" + sudo bash -c "echo 'LNBITS_BACKEND_WALLET_CLASS=CLightningWallet' >> ${lnbitsConfig}" + sudo bash -c "echo 'CLIGHTNING_RPC=/home/bitcoin/.lightning/bitcoin${clrpcsubdir}/lightning-rpc' >> ${lnbitsConfig}" fi # set raspiblitz config value for funding @@ -1062,6 +1088,7 @@ if [ "$1" = "0" ] || [ "$1" = "off" ]; then echo "# deleting data" sudo -u postgres psql -c "drop database lnbits_db;" sudo -u postgres psql -c "drop user lnbits_user;" + sudo rm /home/lnbits/lnbits/.env sudo rm -R /mnt/hdd/app-data/LNBits else echo "# keeping data" @@ -1182,11 +1209,9 @@ if [ "$1" = "migrate" ]; then # create new backup sudo tar -cf /mnt/hdd/app-data/LNBits_sqlitedb_backup.tar -C /mnt/hdd/app-data LNBits/ - # remove existent config for database - sudo sed -i "/^LNBITS_DATABASE_URL=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo sed -i "/^LNBITS_DATA_FOLDER=/d" /home/lnbits/lnbits/.env 2>/dev/null # restore sqlite database config - sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATA_FOLDER=/d" $lnbitsConfig 2>/dev/null + sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits' >> ${lnbitsConfig}" # stop after sync was done sudo systemctl stop lnbits @@ -1198,7 +1223,8 @@ if [ "$1" = "migrate" ]; then # example: postgres://:@/ # add new postgres config - sudo bash -c "echo 'LNBITS_DATABASE_URL=postgres://lnbits_user:raspiblitz@localhost:5432/lnbits_db' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATABASE_URL=/d" $lnbitsConfig 2>/dev/null + sudo bash -c "echo 'LNBITS_DATABASE_URL=postgres://lnbits_user:raspiblitz@localhost:5432/lnbits_db' >> ${lnbitsConfig}" # clean start on new postgres db prior migration echo "# LNBits first start with clean PostgreSQL" @@ -1240,8 +1266,8 @@ if [ "$1" = "migrate" ]; then sudo chown lnbits:lnbits -R /mnt/hdd/app-data/LNBits/ echo "# Configure .env" - sudo sed -i "/^LNBITS_DATA_FOLDER=/d" /home/lnbits/lnbits/.env 2>/dev/null - sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits/data' >> /home/lnbits/lnbits/.env" + sudo sed -i "/^LNBITS_DATA_FOLDER=/d" $lnbitsConfig 2>/dev/null + sudo bash -c "echo 'LNBITS_DATA_FOLDER=/mnt/hdd/app-data/LNBits/data' >> ${lnbitsConfig}" # setting value in raspi blitz config /home/admin/config.scripts/blitz.conf.sh set LNBitsMigrate "off" diff --git a/home.admin/config.scripts/bonus.postgresql.sh b/home.admin/config.scripts/bonus.postgresql.sh index 796f93ee4..866d9cbbb 100755 --- a/home.admin/config.scripts/bonus.postgresql.sh +++ b/home.admin/config.scripts/bonus.postgresql.sh @@ -21,13 +21,19 @@ echo "# Using the default PostgreSQL version: $PG_VERSION" # switch on if [ "$command" = "1" ] || [ "$command" = "on" ]; then - echo "# Install PostgreSQL" - if [ ! -f /etc/apt/trusted.gpg.d/postgresql.gpg ]; then - curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg - echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list - sudo apt update + + # check if PostgreSQL is already installed + if psql --version | grep -q "psql (PostgreSQL) $PG_VERSION"; then + echo "# PostgreSQL $PG_VERSION is already installed" + else + echo "# Install PostgreSQL" + if [ ! -f /etc/apt/trusted.gpg.d/postgresql.gpg ]; then + curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg + echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list + sudo apt update + fi + sudo apt install -y postgresql-$PG_VERSION fi - sudo apt install -y postgresql-$PG_VERSION postgres_datadir="/var/lib/postgresql" # default data dir postgres_confdir="/etc/postgresql" # default conf dir @@ -39,17 +45,17 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then echo "# There is no old pg data" # symlink conf dir sudo mkdir -p /mnt/hdd/app-data/postgresql-conf/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership - sudo mv $postgres_confdir /etc/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_confdir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership + sudo mv $postgres_confdir /etc/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_confdir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink # symlink data dir sudo mkdir -p /mnt/hdd/app-data/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership - sudo mv $postgres_datadir /var/lib/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_datadir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership + sudo mv $postgres_datadir /var/lib/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_datadir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink echo "# Create PostgreSQL $PG_VERSION data" sudo mkdir -p $postgres_datadir/$PG_VERSION/main @@ -64,10 +70,10 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then if [ -d /mnt/hdd/app-data/postgresql-conf ]; then # symlink conf dir sudo mkdir -p /mnt/hdd/app-data/postgresql-conf/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership - sudo mv $postgres_confdir /etc/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_confdir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership + sudo mv $postgres_confdir /etc/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_confdir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink else # generate new cluster and use default config echo "# Create $PG_VERSION config" @@ -94,10 +100,10 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then # symlink data dir sudo mkdir -p /mnt/hdd/app-data/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership - sudo mv $postgres_datadir /var/lib/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_datadir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership + sudo mv $postgres_datadir /var/lib/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_datadir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink sudo chown -R postgres:postgres $postgres_datadir sudo systemctl start postgresql @@ -113,10 +119,10 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then if [ -d /mnt/hdd/app-data/postgresql-conf ]; then # symlink conf dir sudo mkdir -p /mnt/hdd/app-data/postgresql-conf/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership - sudo mv $postgres_confdir /etc/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_confdir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql-conf # fix ownership + sudo mv $postgres_confdir /etc/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_confdir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql-conf/postgresql /etc/ # create symlink else # generate new cluster and use default config echo "# Create pg 13 config" @@ -126,7 +132,7 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then sudo systemctl start postgresql sudo pg_createcluster 13 main sudo pg_ctlcluster 13 main start - echo "Setting default password for postgres user" + echo "# Setting default password for postgres user" sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'postgres';" sudo systemctl stop postgresql sudo systemctl stop postgresql@13-main @@ -140,10 +146,10 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then # symlink data dir sudo mkdir -p /mnt/hdd/app-data/postgresql - sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership - sudo mv $postgres_datadir /var/lib/postgresql.bak # backup new empty dir - sudo rm -rf $postgres_datadir # not a symlink.. delete it silently - sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink + sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql # fix ownership + sudo mv $postgres_datadir /var/lib/postgresql.bak.$(date +'%Y%m%d_%H%M%S') # backup new empty dir + sudo rm -rf $postgres_datadir # not a symlink.. delete it silently + sudo ln -s /mnt/hdd/app-data/postgresql /var/lib/ # create symlink sudo chown -R postgres:postgres $postgres_datadir sudo systemctl start postgresql @@ -159,6 +165,8 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then sudo pg_dropcluster $PG_VERSION main fi + echo "# Make sure postgresql-$PG_VERSION is installed" + sudo apt install -y postgresql-$PG_VERSION # /usr/bin/pg_upgradecluster [OPTIONS] [] sudo pg_upgradecluster 13 main $postgres_datadir/$PG_VERSION/main || exit 1 sudo chown -R postgres:postgres /mnt/hdd/app-data/postgresql/$PG_VERSION @@ -178,8 +186,10 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then fi # start cluster - sudo systemctl enable --now postgresql - sudo systemctl enable --now postgresql@$PG_VERSION-main + sudo systemctl enable postgresql + sudo systemctl start postgresql + sudo systemctl enable postgresql@$PG_VERSION-main + sudo systemctl start postgresql@$PG_VERSION-main # check if PostgreSQL was installed if psql --version; then @@ -200,13 +210,12 @@ if [ "$command" = "1" ] || [ "$command" = "on" ]; then echo "Setting default password for postgres user" sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'postgres';" echo "OK PostgreSQL installed" + exit 0 else echo "FAIL - Was not able to install PostgreSQL" echo "ABORT - PostgreSQL install" exit 1 fi - - exit 0 fi # switch off diff --git a/home.admin/config.scripts/bonus.letsencrypt.sh b/home.admin/config.scripts/internet.letsencrypt.sh similarity index 78% rename from home.admin/config.scripts/bonus.letsencrypt.sh rename to home.admin/config.scripts/internet.letsencrypt.sh index dd180ed11..aeee3d036 100755 --- a/home.admin/config.scripts/bonus.letsencrypt.sh +++ b/home.admin/config.scripts/internet.letsencrypt.sh @@ -3,15 +3,18 @@ # command info if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ] || [ "$1" = "-help" ]; then echo "config script to install or remove the Let's Encrypt Client (ACME.SH)" - echo "bonus.letsencrypt.sh [on|off]" - echo "bonus.letsencrypt.sh issue-cert DNSSERVICE FULLDOMAINNAME APITOKEN ip|tor|ip&tor" - echo "bonus.letsencrypt.sh remove-cert FULLDOMAINNAME ip|tor|ip&tor" - echo "bonus.letsencrypt.sh refresh-nginx-certs" + echo "internet.letsencrypt.sh [on|off]" + echo "internet.letsencrypt.sh issue-cert DNSSERVICE FULLDOMAINNAME APITOKEN ip|tor|ip&tor" + echo "internet.letsencrypt.sh remove-cert FULLDOMAINNAME ip|tor|ip&tor" + echo "internet.letsencrypt.sh refresh-nginx-certs" exit 1 fi source /mnt/hdd/raspiblitz.conf +# make sure the HDD is mounted +mountpoint -q /mnt/hdd || { echo "# internet.letsencrypt.sh - /mnt/hdd is not mounted. Exiting."; exit 1; } + # https://github.com/acmesh-official/acme.sh/releases ACME_LOAD_BASE_URL="https://github.com/acmesh-official/acme.sh/archive/refs/tags/3.0.7.tar.gz" ACME_VERSION="3.0.7" @@ -113,19 +116,26 @@ function refresh_certs_with_nginx() { # FIRST: SET ALL TO DEFAULT SELF SIGNED + # make a hashs of certs before + certHashBefore1=$(sudo md5sum /mnt/hdd/app-data/nginx/tls.cert | head -n1 | cut -d " " -f1) + certHashBefore2=$(sudo md5sum /mnt/hdd/app-data/nginx/tor_tls.cert | head -n1 | cut -d " " -f1) + + # make sure self-signed cert exists & is valid + /home/admin/config.scripts/internet.selfsignedcert.sh create + echo "# default IP certs" sudo rm /mnt/hdd/app-data/nginx/tls.cert sudo rm /mnt/hdd/app-data/nginx/tls.key - sudo ln -sf /mnt/hdd/lnd/tls.cert /mnt/hdd/app-data/nginx/tls.cert - sudo ln -sf /mnt/hdd/lnd/tls.key /mnt/hdd/app-data/nginx/tls.key + sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.cert /mnt/hdd/app-data/nginx/tls.cert + sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.key /mnt/hdd/app-data/nginx/tls.key echo "# default TOR certs" sudo rm /mnt/hdd/app-data/nginx/tor_tls.cert sudo rm /mnt/hdd/app-data/nginx/tor_tls.key - sudo ln -sf /mnt/hdd/lnd/tls.cert /mnt/hdd/app-data/nginx/tor_tls.cert - sudo ln -sf /mnt/hdd/lnd/tls.key /mnt/hdd/app-data/nginx/tor_tls.key + sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.cert /mnt/hdd/app-data/nginx/tor_tls.cert + sudo ln -sf /mnt/hdd/app-data/selfsignedcert/selfsigned.key /mnt/hdd/app-data/nginx/tor_tls.key - # SECOND: SET LETSENCRPYT CERTS FOR SUBSCRIPTIONS + # SECOND: SET LETSENCRPYT CERTS FOR SUBSCRIPTIONS (ONLY IF VALID) if [ "${letsencrypt}" != "on" ]; then echo "# lets encrypt is off - so no certs replacements" @@ -139,12 +149,30 @@ function refresh_certs_with_nginx() { FQDN=$(echo "${i}" | cut -d "_" -f1) echo "# i(${i})" echo "# FQDN(${FQDN})" + + # check if cert exists and is valid + CERT_FILE="${ACME_CERT_HOME}/${FQDN}_ecc/fullchain.cer" + echo "CERT_FILE(${CERT_FILE})" + if openssl x509 -checkend 86400 -noout -in "${CERT_FILE}"; then + echo "# The certificate is valid for more than one day. OK use them nginx." + else + echo "# The certificate is non-exist, invalid, expired or will expire within a day. DONT use them the nginx." + continue + fi + # check if there is a LetsEncrypt Subscription for this domain details=$(/home/admin/config.scripts/blitz.subscriptions.letsencrypt.py subscription-detail $FQDN) if [ $(echo "${details}" | grep -c "error=") -eq 0 ] && [ ${#details} -gt 10 ]; then echo "# details(${details})" + # check if subscription is active + active=$(echo "${details}" | jq -r ".active") + if [ "${active}" != "true" ]; then + echo "# not active(${active}) ... skipping" + continue + fi + # get target for that domain options=$(echo "${details}" | jq -r ".target") @@ -174,6 +202,26 @@ function refresh_certs_with_nginx() { fi done + # set permissions + sudo chown -h admin:www-data /mnt/hdd/app-data/nginx/tls.cert + sudo chown -h admin:www-data /mnt/hdd/app-data/nginx/tls.key + sudo chown -h admin:www-data /mnt/hdd/app-data/nginx/tor_tls.cert + sudo chown -h admin:www-data /mnt/hdd/app-data/nginx/tor_tls.key + + # make a hashs of certs after + certHashAfter1=$(sudo md5sum /mnt/hdd/app-data/nginx/tls.cert | head -n1 | cut -d " " -f1) + certHashAfter2=$(sudo md5sum /mnt/hdd/app-data/nginx/tor_tls.cert | head -n1 | cut -d " " -f1) + echo "# certHashBefore(${certHashBefore1})" + echo "# certHashAfter(${certHashAfter1})" + echo "# certHashBeforeTor(${certHashBefore2})" + echo "# certHashAfterTor(${certHashAfter2})" + # check if nginx needs to be reloaded + if [ "${certHashBefore1}" != "${certHashAfter1}" ] || [ "${certHashBefore2}" != "${certHashAfter2}" ]; then + echo "# nginx needs to be reloaded" + sudo systemctl restart nginx 2>&1 + else + echo "# nginx certs are the same - no need to reload" + fi } ################### @@ -218,8 +266,6 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then # make sure already existing certs get refreshed in to nginx refresh_certs_with_nginx - echo "# restarting nginx" - sudo systemctl restart nginx 2>&1 exit 0 @@ -324,7 +370,7 @@ elif [ "$1" = "remove-cert" ]; then options="ip&tor" fi - echo "# bonus.letsencrypt.sh remove-cert ${FQDN} ${options}" + echo "# internet.letsencrypt.sh remove-cert ${FQDN} ${options}" # remove cert from renewal $ACME_INSTALL_HOME/acme.sh --remove -d "${FQDN}" --ecc --home "${ACME_INSTALL_HOME}" --config-home "${ACME_CONFIG_HOME}" --cert-home "${ACME_CERT_HOME}" 2>&1 @@ -342,10 +388,6 @@ elif [ "$1" = "remove-cert" ]; then exit 1 fi - # restart nginx - echo "# restarting nginx" - sudo systemctl restart nginx 2>&1 - exit 0 @@ -365,9 +407,6 @@ elif [ "$1" = "refresh-nginx-certs" ]; then exit 1 fi - echo "# restarting nginx" - sudo systemctl restart nginx 2>&1 - ################### # OFF @@ -384,10 +423,11 @@ elif [ "$1" = "0" ] || [ "$1" = "off" ]; then --config-home "${ACME_CONFIG_HOME}" \ --cert-home "${ACME_CERT_HOME}" + # remove certs + sudo rm -r ${ACME_CERT_HOME} + # refresh nginx refresh_certs_with_nginx - echo "# restarting nginx" - sudo systemctl restart nginx 2>&1 # remove old script install sudo rm -r ${ACME_INSTALL_HOME} diff --git a/home.admin/config.scripts/internet.selfsignedcert.sh b/home.admin/config.scripts/internet.selfsignedcert.sh index 1e2a662ac..9121c10cd 100755 --- a/home.admin/config.scripts/internet.selfsignedcert.sh +++ b/home.admin/config.scripts/internet.selfsignedcert.sh @@ -9,10 +9,14 @@ if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then exit 1 fi +# make sure the HDD is mounted +mountpoint -q /mnt/hdd || { echo "# internet.selfsignedcert.sh - /mnt/hdd is not mounted. Exiting."; exit 1; } + CERT_DIR="/mnt/hdd/app-data/selfsignedcert" CERT_FILE="${CERT_DIR}/selfsigned.cert" create_self_signed_cert() { + sudo mkdir -p "${CERT_DIR}" sudo chown -R bitcoin:bitcoin "${CERT_DIR}" cd /mnt/hdd/app-data/selfsignedcert || exit 1 @@ -56,6 +60,13 @@ DNS.3 = $localip sudo -u bitcoin openssl req -new -x509 -sha256 -key selfsigned.key \ -out selfsigned.cert -days 3650 -config localhost.conf + + # set permissions on cert & key + sudo chown -h admin:www-data $CERT_DIR/selfsigned.cert + sudo chown -h admin:www-data $CERT_DIR/selfsigned.key + + # reolad nginx + sudo systemctl reload nginx 2>/dev/null } check_certificate_validity() { @@ -70,6 +81,7 @@ check_certificate_validity() { if [ "$1" = create ]; then if [[ -f "${CERT_DIR}/selfsigned.cert" && -f "${CERT_DIR}/selfsigned.key" ]]; then + # if certificate exists, check if it is still valid if ! check_certificate_validity; then create_self_signed_cert fi @@ -84,9 +96,8 @@ if [ "$1" = reset ]; then echo "# Make sure the old certificate is not present" sudo rm -f "${CERT_DIR}/selfsigned.cert" sudo rm -f "${CERT_DIR}/selfsigned.key" - create_self_signed_cert - + /home/admin/config.scripts/internet.letsencrypt.sh refresh-nginx-certs exit 0 fi diff --git a/test/bonus.postgresql-13.bats b/test/bonus.postgresql-13.bats index 5b472f40a..1071faf71 100644 --- a/test/bonus.postgresql-13.bats +++ b/test/bonus.postgresql-13.bats @@ -55,7 +55,7 @@ run pg_lsclusters # check that no 13 cluster is present [ $(echo "$output" | grep -c "13 main") -eq 0 ] - # check that no 13 cluster is present + # check that pg 15 cluster is present echo "$output" | grep -q "15 main" [ "$?" -eq 0 ] run sudo -u postgres psql -l