From 1b2dfa37cb3a005539d59f4e0cc6586ba2554b2b Mon Sep 17 00:00:00 2001 From: dappnodedev <144998261+dappnodedev@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:28:30 +0200 Subject: [PATCH 01/55] Add Ubuntu ISO (#626) * First approach * Created bootable Ubuntu ISO * Add grub config for Ubuntu * Add autoinstall files * Improve Ubuntu ISO generation * Update Ubuntu ISO * Fix grub theme * Copy grub theme files to ISO * Fix pkg installation * Fix splash image path * Remove unnecessary lines in grub conf * Updated unattended autoinstall * Fix prerequisites for Ubuntu * Update docker install based on docs * Remove unnecessary packages * Update autoinstall attended * Install buildx * Handle dappnode install for Ubuntu * Fix motd generator script * Keep debian grub theme * Set default values * Remove motd script creation * Use common functions for Debian ISO generation * Fix common generation * Add netplan copy to autoinstall * Remove unneeded late commands * Fix common vars * Fix artifact generation * Add ubuntu artifacts to workflows * Add Ubuntu to release action * Update test workflow * Run pre requisites in target for attended * Upload all Ubuntu ISOs * Upload all ubuntu ISOs in artifcats * Use all storage * Add autoinstall validation file * Run autoinstall validation on any PR or push * Fix permission error on yaml validation * Install yq using pip * Update autoinstall format to * Fix yq command * Make ssh interactive in attended * Fix path for common ISO generation script * Removed ISOBUILD from prerequisites * update profile versions * update ubuntu iso * update debian image to 12.11.0 * add release body * add ubuntu test --------- Co-authored-by: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Co-authored-by: pablomendezroyo --- .dappnode_profile | 4 +- .github/workflows/artifacts.yml | 75 +++++-- .github/workflows/release.yml | 202 ++++++++++++++---- .github/workflows/test.yml | 26 ++- .github/workflows/validate_autoinstall.yml | 42 ++++ .yamllint | 6 + docker-compose.yml | 1 + iso/boot/splash.png | Bin 4101 -> 12614 bytes iso/boot/ubuntu/grub.cfg | 21 ++ iso/boot/ubuntu/themes/dappnode/splash.png | Bin 0 -> 12557 bytes iso/boot/ubuntu/themes/dappnode/theme.txt | 41 ++++ iso/preseeds/ubuntu/autoinstall.yaml | 29 +++ .../ubuntu/autoinstall_unattended.yaml | 44 ++++ iso/scripts/common_iso_generation.sh | 75 +++++++ iso/scripts/generate_ISO.sh | 6 +- iso/scripts/generate_dappnode_iso_debian.sh | 173 ++++++++------- iso/scripts/generate_dappnode_iso_ubuntu.sh | 74 +++++++ scripts/dappnode_install.sh | 80 ++++++- scripts/dappnode_install_pre.sh | 68 ++++-- 19 files changed, 789 insertions(+), 178 deletions(-) create mode 100644 .github/workflows/validate_autoinstall.yml create mode 100644 .yamllint create mode 100644 iso/boot/ubuntu/grub.cfg create mode 100644 iso/boot/ubuntu/themes/dappnode/splash.png create mode 100644 iso/boot/ubuntu/themes/dappnode/theme.txt create mode 100644 iso/preseeds/ubuntu/autoinstall.yaml create mode 100644 iso/preseeds/ubuntu/autoinstall_unattended.yaml create mode 100644 iso/scripts/common_iso_generation.sh create mode 100755 iso/scripts/generate_dappnode_iso_ubuntu.sh diff --git a/.dappnode_profile b/.dappnode_profile index 7c6e7f36..9951723d 100755 --- a/.dappnode_profile +++ b/.dappnode_profile @@ -10,10 +10,10 @@ export BIND_VERSION="${BIND_VERSION:-0.2.11}" export IPFS_VERSION="${IPFS_VERSION:-0.2.23}" export VPN_VERSION="${VPN_VERSION:-0.2.10}" -export DAPPMANAGER_VERSION="${DAPPMANAGER_VERSION:-0.2.88}" +export DAPPMANAGER_VERSION="${DAPPMANAGER_VERSION:-0.2.99}" export WIFI_VERSION="${WIFI_VERSION:-0.2.9}" export WIREGUARD_VERSION="${WIREGUARD_VERSION:-0.1.3}" -export HTTPS_VERSION="${HTTPS:-0.2.1}" +export HTTPS_VERSION="${HTTPS:-0.2.2}" export DAPPNODE_DIR="/usr/src/dappnode" export DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 0aa39464..b82ddac0 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -68,39 +68,80 @@ jobs: sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${HTTPS_VERSION}"/" .dappnode_profile cat .dappnode_profile - # ISO ATTENDED - - name: Build attended + # Debian ISO ATTENDED + - name: Build Debian attended run: | + sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml docker compose build docker compose up - # Verify ISO attended created - - name: Check iso attended + - name: Check Debian ISO attended run: | - ls -lrt images/DAppNode-debian-bookworm-amd64.iso + ls -lrt images/Dappnode-debian-*.iso - # Set new name for the release asset - - name: Set DAppNode attended ISO name + - name: Set Debian Dappnode attended ISO name run: | - cp ./images/DAppNode-debian-bookworm-amd64.iso DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso + file=$(ls images/Dappnode-debian-*.iso) + attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + mv "$file" "$attended_filename" - # ISO UNATTENDED - - name: Build unattended + # Debian ISO UNATTENDED + - name: Build Debian unattended run: | + sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml docker compose build docker compose up - # Verify ISO unattended was created - - name: Check iso unattended + - name: Check Debian ISO unattended run: | - ls -lrt images/DAppNode-debian-bookworm-amd64.iso + ls -lrt images/Dappnode-debian-*.iso # Set new name for the release asset - - name: Set DAppNode unttended ISO name + - name: Set Dappnode unttended ISO name + run: | + file=$(ls images/Dappnode-debian-*.iso) + + core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" + + mv "$file" "$unattended_filename" + + # Ubuntu ISO ATTENDED + - name: Build Ubuntu attended + run: | + sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml + sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml + docker-compose up --build + + - name: Check Ubuntu ISO attended + run: | + ls -lrt images/Dappnode-ubuntu-*.iso + + - name: Set Ubuntu Dappnode attended ISO name + run: | + file=$(ls images/Dappnode-ubuntu-*.iso) + attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + mv "$file" "$attended_filename" + + # Ubuntu ISO UNATTENDED + - name: Build Ubuntu unattended + run: | + sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml + sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml + docker-compose up --build + + - name: Check Ubuntu ISO unattended + run: | + ls -lrt images/Dappnode-ubuntu-*.iso + + - name: Set Ubuntu Dappnode unattended ISO name run: | - cp ./images/DAppNode-debian-bookworm-amd64.iso DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso + file=$(ls images/Dappnode-ubuntu-*.iso) + core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" + mv "$file" "$unattended_filename" - name: Create dappnode_profile.sh run: | @@ -112,8 +153,8 @@ jobs: with: name: test-artifact path: | - ./DAppNode-*-amd64.iso - ./DAppNode-*-amd64-unattended.iso + ./Dappnode-debian-*.iso + ./Dappnode-ubuntu-*.iso ./scripts/dappnode_install.sh ./scripts/dappnode_install_pre.sh ./scripts/dappnode_uninstall.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d289db8..7aacdf6f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,14 +39,13 @@ env: jobs: pre-release: - name: create pre release + name: Create pre-release artifacts runs-on: ubuntu-latest defaults: run: shell: bash steps: - # Regex for versions introduced - name: Check versions regex run: | [[ $BIND_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $IPFS_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $DAPPMANAGER_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ @@ -56,7 +55,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - # Edit the profile with the new versions introduced - name: Set new versions run: | sed -i -e "/BIND_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${BIND_VERSION}"/" .dappnode_profile @@ -68,82 +66,119 @@ jobs: sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${HTTPS_VERSION}"/" .dappnode_profile cat .dappnode_profile - # ISO ATTENDED - - name: Build attended + - name: Build Debian attended run: | + sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml docker compose build docker compose up - # Verify ISO attended created - - name: Check iso attended + - name: Check Debian ISO attended run: | - ls -lrt images/DAppNode-debian-bookworm-amd64.iso + ls -lrt images/Dappnode-debian-*.iso - # Set new name for the release asset - - name: Set DAppNode attended ISO name + - name: Set Debian Dappnode attended ISO name run: | - cp ./images/DAppNode-debian-bookworm-amd64.iso DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso + file=$(ls images/Dappnode-debian-*.iso) + attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + mv "$file" "$attended_filename" - # ISO UNATTENDED - - name: Build unattended + - name: Build Debian unattended run: | sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml docker compose build docker compose up - # Verify ISO unattended was created - - name: Check iso unattended + - name: Check Debian ISO unattended run: | - ls -lrt images/DAppNode-debian-bookworm-amd64.iso + ls -lrt images/Dappnode-debian-*.iso - # Set new name for the release asset - - name: Set DAppNode unttended ISO name + - name: Set Dappnode unattended ISO name run: | - cp ./images/DAppNode-debian-bookworm-amd64.iso DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso + file=$(ls images/Dappnode-debian-*.iso) + core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" + mv "$file" "$unattended_filename" + + - name: Build Ubuntu attended + run: | + sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml + sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml + docker-compose up --build + + - name: Check Ubuntu ISO attended + run: | + ls -lrt images/Dappnode-ubuntu-*.iso + + - name: Set Ubuntu Dappnode attended ISO name + run: | + file=$(ls images/Dappnode-ubuntu-*.iso) + attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + mv "$file" "$attended_filename" + + - name: Build Ubuntu unattended + run: | + sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml + sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml + docker-compose up --build + + - name: Check Ubuntu ISO unattended + run: | + ls -lrt images/Dappnode-ubuntu-*.iso + + - name: Set Ubuntu Dappnode unattended ISO name + run: | + file=$(ls images/Dappnode-ubuntu-*.iso) + core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" + mv "$file" "$unattended_filename" - # Create profile.sh script (not able to set dot (.) before the name in the gh release asset) - name: Create dappnode_profile.sh run: | cp .dappnode_profile dappnode_profile.sh # SHASUMs - - name: Get SHA-256 attended - id: shasum-attended + - name: Get SHA-256 Debian attended + id: shasum-debian-attended run: | - SHASUM_ATTENDED=$(shasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso) - echo "::set-output name=SHASUM_ATTENDED::$SHASUM_ATTENDED" + file=$(find . -type f -name 'Dappnode-debian-*.iso' ! -name '*unattended*') + SHASUM_DEBIAN_ATTENDED=$(shasum -a 256 $file) + echo "::set-output name=SHASUM_DEBIAN_ATTENDED::$SHASUM_DEBIAN_ATTENDED" - - name: Get SHA-256 unattended - id: shasum-unattended + - name: Get SHA-256 Debian unattended + id: shasum-debian-unattended run: | - SHASUM_UNATTENDED=$(shasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso) - echo "::set-output name=SHASUM_UNATTENDED::$SHASUM_UNATTENDED" + file=$(find . -type f -name 'Dappnode-debian-*unattended.iso') + SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) + echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - # Release body - - name: Write release content + - name: Get SHA-256 Debian attended + id: shasum-ubuntu-attended run: | - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${BIND_VERSION}|\n|ipfs.dnp.dappnode.eth|${IPFS_VERSION}|\n|vpn.dnp.dappnode.eth |${VPN_VERSION}|\n|dappmanager.dnp.dappnode.eth|${DAPPMANAGER_VERSION}|\n|wifi.dnp.dappnode.eth|${WIFI_VERSION}|\n|https.dnp.dappnode.eth|${HTTPS_VERSION}|\n|wireguard.dnp.dappnode.eth|${WIREGUARD_VERSION}|\n# Changes\nChanges implemented in release ${CORE_VERSION}\n# Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso\n${SHASUM_ATTENDED}\n\`\`\`\n# Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnode.s0\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso\n${SHASUM_UNATTENDED}\n\`\`\`\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md - cat CHANGELOG.md - env: - SHASUM_ATTENDED: ${{ steps.shasum-attended.outputs.SHASUM_ATTENDED }} - SHASUM_UNATTENDED: ${{ steps.shasum-unattended.outputs.SHASUM_UNATTENDED }} + file=$(find . -type f -name 'Dappnode-ubuntu-*.iso' ! -name '*unattended*') + SHASUM_UBUNTU_ATTENDED=$(shasum -a 256 $file)s + echo "::set-output name=SHASUM_UBUNTU_ATTENDED::$SHASUM_UBUNTU_ATTENDED" + + - name: Get SHA-256 Debian unattended + id: shasum-ubuntu-unattended + run: | + file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') + SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) + echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" - # PRE-RELEASE ASSETS - - name: Pre release - uses: softprops/action-gh-release@v1 + # ARTIFACTS ASSETS + - name: Artifact + uses: actions/upload-artifact@v3 with: - tag_name: ${{ github.event.inputs.core }} - prerelease: true - files: | - ./DAppNode-*-amd64.iso - ./DAppNode-*-amd64-unattended.iso + name: test-artifact + path: | + ./Dappnode-debian-*.iso + ./Dappnode-ubuntu-*.iso ./scripts/dappnode_install.sh ./scripts/dappnode_install_pre.sh ./scripts/dappnode_uninstall.sh ./scripts/dappnode_access_credentials.sh dappnode_profile.sh - body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -153,6 +188,85 @@ jobs: run: | git diff --no-index --word-diff-regex=[^[:space:]] --no-patch .dappnode_profile && echo '::set-output name=HAS_CHANGED::true' || echo '::set-output name=HAS_CHANGED::false' + # … your existing "Artifact" upload-artifact@v3 step here … + + # Generate CHANGELOG.md just like before, + - name: Write release content + run: | + cat > CHANGELOG.md < attended.yaml + yq '.autoinstall' iso/preseeds/ubuntu/autoinstall_unattended.yaml > unattended.yaml + + - name: Validate attended autoinstall.yaml + run: | + check-jsonschema --schemafile schema.json attended.yaml + + - name: Validate unattended autoinstall.yaml + run: | + check-jsonschema --schemafile schema.json unattended.yaml diff --git a/.yamllint b/.yamllint new file mode 100644 index 00000000..c9b624e1 --- /dev/null +++ b/.yamllint @@ -0,0 +1,6 @@ +# .yamllint +extends: default + +rules: + line-length: + max: 150 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7eddc984..ed9ebe02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,7 @@ services: - BUILD=false # In case you want to re-generate a all the images, not recommended - CLEAN=true # it remove the images directory - UNATTENDED=false # UNATTENDED version + - BASE_OS=debian # Base OS version (debian or ubuntu) volumes: - ./images:/images - "/var/run/docker.sock:/var/run/docker.sock" diff --git a/iso/boot/splash.png b/iso/boot/splash.png index 835dc493b3b82cf1c97fcf904f3f9d5ead4f2f71..a6f4196e77e581d4910a2dc2de08b7293301def2 100644 GIT binary patch literal 12614 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 literal 4101 zcmeH}=QrG27sr2N5G^txVss+}(MAaOCc446x~LI7YKS^UH<5^742eW9(R+^?Jh~89 zjouQXm(d5KJd?lRdG)-@Uh90szC_-96pxom}j=z5U$nxb1wM>;b@cdfUjXYWXhRxdW3a z8Imeu87Wg#^-5SidYjl1SERWg_dW4pw_3N7cOALY#U4@nKR>gc3L5G?Z?3@>A5Zu0 zS)I1*wEXg)v(!8^k)Is(_v1aprsJ7i=Yl*Ym$$*CF|u;gaX8}3Esw({UyrX2D~uh1 zJpSzBbI1GVIv4bk0ReTXt3Cc=OLn`fSB9YOThJs15z$mUQI_!z&Cb@E&`wx1E^Jq` zq+Vjw_?UcUNVa#&3BWhpxiU~I}{H&cnR$<%S%@O=2LK7Ha+H;u=z-u3ps`qLh%zKpHn(p+w@%lYyxqg+||m12XHl<<(( ztf*37O6|#FQZ+AK>1ll6@abOwBGC+@X$_Axvlc9U#y6sm$$rVD_N((F8Qm>)B}P4c zyBFNorZ5eA(eclPspsrJFhgLovAjMERL{ol)xZ|$81{LE4H3x&iQaqNrBY6%PLEK1 zA8U#n9~+LAy>J=pOfF199cZWNb@LvL*O=kwIO6NL#I9IuVQ6~Ayl$%&HM28gX&PX1@pal^PRy43jH*1IeH?G?%5B0pkc|Yi8@y`Bq%pAk{~OL_3;iIj7L$hbN693LrJme{T74 zlu2bd`4mQ0vOcXb=6!H)Ubr$Y?(7|M;R}I}W0gmaoZ-Nv5!TJhXgV~r!UM-o*(lfR zjf`Y6&D(ts~qn>$~O(W{E|y!mz$Z?tTz?!8;kLm z`oSTQ_O#SOUb{wHRg*NYC8vA0tRk9FKFZ`YzG_jW{>A7r{> z4JE#l4+U;+2q>7a;DXt@Tv)XrGDN|Wj@S+l^1AU>1~j-l3dU(60)5bj>PojsS$>-k z>U(!!LPBaiWIUgX{*#_`&J9XdXT7qx#^gb26@zQu1##6Z&K!=>@YHHo#VlQuH=I4a zky`XkFij;DMDOeVHII;KLSfQn?ysxmwS;U-+$90${%~VmXCi&+Ghe+)6sftrc2ZW> zRaaK#*45WhRo7G@b+Oc-ce2P11@BWY@m?V~xm?Hlt^ANd_*})? ziHLkDk+cIjj}L~tVJE4+{hw$VtPNZ29v@5u(3P`YB{l_}ah)D2 zV*(2qXw#ofU8bdDro{B~uyPI2?Z&AQ7E>aS?H;qdk7*MZ2dUC=O+1b zU1x-iLnN5|&<)Hy!J#z|7DZz+`OWY1s?iJ`Cj8S%WC?leh+z{r=vqU=uiB=31EH4$$+Y+=AfXU;L8glfj}hogkNHh+*<->Y~?m;>f50p z2nIx+qu2n0c^cXDYToE+M2BVYo^O#U%tqY?o{F5kh=~u-G-@~lxB)QtQ>I{}*I)p5 zR73$3M~NNXQZyz6P>AeMV8rb)AcWnXZ!fgu22hc}Vugw7{&5OHg&bs>T|JZtXPH`; zMhg{QMiyVg&&n1*B0AlX#t6Z|bges3NX!(T@9fIKu}CqKl%5@sipL#LzlCUhI<8Jo3h3YS5Mf9rU1^4S`x^o8bgf<-L@qd z_dltZWGoc;mvq!Y?BwGIvt5)BVN?G85lj;240ewWF_j z4o`RE0+g3!bL6>3WJ@{1Hio1KRo4S#a3F`Gx)C$XWj+9jCzlEWtgsFk5LMy4i+bYl zU=Q&H_%|A*SnmB6J99FOh{h)n!YDqb?d;PP$@xK)KQh?P28{98ZQfZHC1JQ+Oo>}w zG4<~~Qn$L_T%N98a$p__**Ei@jC(9r%FAt>K2bxh<8LAyF@`2&*SXK;nBDx90Zqi;&;qfn(GEp zOhS!m#Lv#Zz8K4vbDqAzrYR4u0i>tGErKgEy9pH7lW>!Mq;Qf@wUUH%8UufH+ v0Rkt%nEdzjPy8Y9hrk~Ke+c|90?y|E!xU2WC-o=q-=*p*+K4hGtI+=fc7lZ? diff --git a/iso/boot/ubuntu/grub.cfg b/iso/boot/ubuntu/grub.cfg new file mode 100644 index 00000000..88c8305b --- /dev/null +++ b/iso/boot/ubuntu/grub.cfg @@ -0,0 +1,21 @@ +if loadfont unicode ; then + set gfxmode=800x600 + insmod efi_gop + insmod efi_uga + insmod video_bochs + insmod video_cirrus + insmod gfxterm + insmod png + terminal_output gfxterm +fi + +set timeout=6 + +set theme=/boot/grub/themes/dappnode/theme.txt + +menuentry "Install Dappnode (over Ubuntu Server)" { + set background_color=black + set gfxpayload=keep # Maintain the graphical resolution through the booting + linux /casper/vmlinuz autoinstall vga=788 FRONTEND_BACKGROUND=dark --- # Added autoinstall to make it unattended + initrd /casper/initrd +} \ No newline at end of file diff --git a/iso/boot/ubuntu/themes/dappnode/splash.png b/iso/boot/ubuntu/themes/dappnode/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..236fa0346a2345bb7f717229b3df289bbd4f944b GIT binary patch literal 12557 zcmeHu_ghm-*LFY@Jr+&`rGpY1AOg|}<>*mBnh&CYbU{Q2RZ6HqM5QL!C{k5Q6ifi= zgb+H46d^)rNq|TRkc1FQAnoIM|BUZ?e%P~T&vi{%Gi%LS_dT;y|6^-@{4bfm006-8 zTNXF&006>I0RW-d!-w`ubVg?W?7xnLSlkZ-0FH|P_Ynf*6-ezD3WeP56%9U{BI8arw9K(o57>1r@l2WP(3x;h_nM<_Xpt7HMjSc*JSg(yp4dF-7Qht z3Td2qeiJydjJFhsz-J2VT0NP)`rM~*;xN9iM0Pt(M~op0QJB;V!UWs7ChYKq0N^~p zpZgbYl3$~8Bqw(^oF?wep)CF-qUgmaTfuP05|)8d_0qUG3!PtVs;Uq3(l|(pHr)zl zPL(LY?b9+t-F8t)Es8nB*2@4-^T$0*RYRd+;iGBmu@S2oPAAPH3A&}-R-uxGQr)C8 z+(X5Evzjyq#;{^I9g#mR_7*M z)Y($GYjLft5Lc5WF-pz-8?!f&E^NR}Pj@`3~3yC*UA!Fv4D zr@a%D`G-m(HNE~+;hIZ`GU(%%K{Z50CS*(U+FiYucMn`O4ssvJ^qAxhc~$KGLbWw& z(=e6uRhu2f_l-;3dH`nt@AcIKd6*#XJ#*Td?U2g8kl*UYN(bG2)I2eQ=&8R?+DRX@ zPRQXSG1BK=+V}I8$`8k}@Qk$cg=32iS=t4#LLI}6Sl{z`D`u$Ua)|Bv$~i~=m<$Y6 zU}6hO^fitTQWM5&ug#@H8HZh`B)n9l{;vtM7K}M`MK9)>?#1)dX9g9g|L_>FHmf^ZXs{`q^dRW!$Q@~s^!4Pa=YC=42-PchR5ReXd z=p}bg#4`{}nw?#=_1SAsi1Rtq;6k(fy=A`Hu(_Dzk~NUNvWI(O*}SbebJNK5bhnFM zp(G=Aw_w7)6xc3#x#9HRPf_Aet)GV{ki*j(=bW*7L1h2U2pQ<+vN2L?;+LJ78&opH zSAU9NEMfR^>B#ncXp>1ub!8Jib9kPyqh=;7;OX(*x~Ix&kQ4T1Afbt{eSNyl;J2YV zCgaN-SS9x43A^Hcn&5!x#HksXRx`{VyTADvt$&FK?6T!Ce=Zuy3`fUUb(i_lG=Wk5 zBbg$A065^G(&f~WJ^SV^00deAim;GbKbBx;YzI<7$D=XG{K>Ru+8 zx@t*f0lVhoX=9lvIEStY%q>sEqdft+i2a7v9Ib_NO2U+9`;{jjhE#_|?CHMDH(E(H zc7z^v)O~g%`i~W)fA#l)+I!MA0X?Hw6-?01hr=^O@Ef6t+I?XTrc`=W@748;xB4GkpplrJU5fo> zaR!i~v|o7)*c@5s52bzX^H4Q(F|7BSqSuA`>MJ=N?|Wi1`|j}9o<|AOw{}~f1bSAs zoh>sH5v~^f?|RN%8|bQ!B`T?URS_$S2!vDv)c8Bhvm3`KRmZ;19eQQUqbrVZ_ty7n z%Ghx~HS`-T_iHAf+^@OCS~9zV)Eu0icn|g}F}qv-e7dWqm2@`*8ai*bs#^DNY_pUD^5VtFln81|Gkj(VWXwFGnu);Z+cF|&YId9BH z9jW-IW3O#}8QUhXNEVjER2Hw4H`+QqoZ2Z``+0o?8={ldFnMUfYemGssI{+MguA23y zGgsp15<^yz2iNkZ3UQ#Of|+`c^kFxseLEtA{n3i@CbPAX6^IZ8LBSddxhYWo~@N zC3L5EY4|eWZJ|_RA#$;&RG*pK{$6zSy4kVI>F_T*TU>_ z$LlM0_YX*o*_`jPYwtMpMy+t_e&P?$=Nd0T2tOHi{;G#W?YAUQb#2h0{5yc}*?@3w8{WPC$K02>fE^zEw4p@@nn(zv?RarZRK)>GJ$>@xI;`-$w@6 zx+JBLpOo~A{+nV?iROT-b_yOEdi>p{^O~*d!QRdd$GZ5G)nt9g^2DERog*^4GJ}O( z3nwU39e5v+ZM`H{!S~zUUjuzb%EJU1d?Af1Lf^Zaw{j0qwk6ldE>#4v+Bpxqe5Ifr z0w59@-*~sP`u`k@B(&=_mSi3)l|_{;T#0{Kax#V1B=}MmiubO{xS#JMQqG>-0QUQ-QM1e`9?YaMvHxm&w7OaoTGxUJbX}bYYEztY%4|(YgpMi zMQ5DhZ|_mOf>xnaF|aMVDq`=q|FW#WPZ1=PenC zB21f}uspIKRz$pskkzHXEB1DD1JRz@C?+d@(^hc9nK+P|RU%(*?v?47I?00nZ83{3 z%p%`Em5Fvy1Uv6?EJs%v8IX4R{-$I>wQk3mETrhO_H>AcKZ^O^Dr$f7zUTNpLn%-wqo3!$Xz5uM`( z_$h^DH!})jMpK!2;s|(&n2X_pjB5IhAZwaFfrgaszCjHTYC5pPMpG5(p%W-_qC6fcy&Jo#BidV>5KAbG&c0493^uHnwWU~G zW1-WpP>T+*+dN_^v#U8=Vnk2h7O42`^))x&0%x#Zhzr4@O7E?O6)+oykjMqIWR$r> zPNAbtOA6(XxSEtjD?Yy^H&w!7Nzhk2KcgoYofzKzg}jo^5-fkqO=YDK1fHRVp~Dl? zrwC1(6_ELVdvrz(o>HOzG34+hyM20g%#_98=pxxB9c7W>-S&gEC!8mUB4^${$OBl9 z60ecsc*b4SS=$ATW!p+%1pEupa`QaRHh8nT73+Fq>&hAUagg18EvMUb;a%dLI3-lV1zKx?^)li}ZJG z=nt~Hse@5j`x+_h;Xn$?5~{JQnB##R>?`Vk6k8|^TrnqXidCmPS41WDKK5vMC({v(BTHv z*My?0ZwS-3X2|QB6I;_VYZ?mAy&?YGdeENYg2e+!|6SJNkV%a{?F?cKH!y8ff>Ab$5q9*J9X?%WG@QD3 zTsEDM-y&{!aB=j&={`8QRjd5%vo-OhLUBUACYX~ctpPfLiu znynDt{*JL#uHo2g(?}#8FXg2ZW}wA;rWci;-3f7vAUY!5SlJ3;M5L+0#ln!8cZ{;7 zndUtXF*6)H=?=POYOXU|L1?1pH$oG#!{PATfq5IOa!7XLQ&qQUnj@uwG2_N@PQyvO zAKb|;CD;P*qrI(7t?;t8d?sC>m5{HYMHQsKK- zFKS;~=-zM~@gkMpiy&Ee1gkW1Obb5;pH$9-e_1;jggArPi@`jRe513PiHJ?hOxlS* zgK!OTG(x6y@cN`q#YJ_UWp)X6Yn<3xj@{pK+{9zwNIXKeweZ!KBw&8pYa6RUc_)>r zFkG;T*OxTFp`89l>qOxsO@qCpEHYeRA zEZWsIV+9@y*ETMM^(no&W1%0n7r-*s? z&|zk5A5nc;b-cBd&6%f+oDWOusB;)l|DAt_K`Mhp17r9mAG4My8E8p32(Fpk7lDoBbd&^9(yxU*L-fM!$r#dXmy}wl^(CO z$*Bm_ogOyZgGYPUmwhLy9AG2(Ug*TVTqg0{@2!Q5T7cz)aXC#ev!{+m=J>GgjF)@F1_v&+J`*mP~)dJgTbZXI-fkljqIok-b2gmrowQ;6B{KISXwekd zg-I=qf)LC(i*+xV1bXsZNQp&k^`V-vToVP7OVduFn#*Pnho;9=^m52rl+-6>NpZKtYYd#wCFHrM4UwQb9iW#WoHt!4D4`~jP6BSDl3 z<(@||D2co+yOtiJz8uU%C)SG6KjP+2!p0=-%gw=4#cT_;ygOVh$GccY+PVb&`qNdL{1a&AC}sYe zx~skH!2owkzt>&nzz&z>L~ye2UL>Sb=W1`~8=iDJ-Y)Tetgn>q!W@S}i*ahizb}*Q zWsY3_R|`wlJ{6y2_s@mrNgtxOCo0*5KWFp3DL?i4$UN?~n#J5^=I>|YPPcg^tHo|# zva!0!o~dNFM`7b_BkqjD0{U#$7g9g*+RJN>M4&6K%Ob+f^F~BP6W+zwDVAnSi7xC| zZRFUGl6h+!N-~+bo8 zWj|B55zonE=5z*(9fL;j`96-nhiF!i6P4hsd|ahEj5gjBE^8W#FYD0`m3g36W;e39 zTK?t7R2aH7W{s^HznsZ$ZO{bW9Q4aNE~T93@5?=v$@_H-x>?9ln(^|rLWA{PIszXzD1MqxC)B-#Kr)~ea>Qz*I-2Q(HX zZq}Ebx-Ix1bu-p~QIJCB;$!;~1bPO zGCWMoXt8fB4u^ZtQF8LF>fCc>jK9<>Lyl+~+v6dO4!XyT^V59c^W z-o7|UY|=VjTZ-YMYD(%`4(!y!sS6S|gAq?CkJ}n0vdh8`dE5&w>0>`|Xklv=7e^-D za^?^+2B?VS$vo{(PR7fI2U*Hhxx47c6Y>GV4>pXea!)&N4E(Oz0fjLBEy@@-aq+sK zD*;M&6!eoqcbK#&R-azaHB)Pkz%la;e=y8EdDhd-vr?xC?)tmvt;y@t&Ell4lisVtZa#o+cEK2sw31yv*07d={tw^?aOsd@}ru9?k{8hmeZv~BL_bzJu zy1g4vqI^Gsu}mFb44R}W=phyld+tv8Ic^|Y%+hKryid3|U>y8t|7Lavlqu8bn%X>o zbwc^Rde%SEE^{dvbodMTs35C?Fj@57`i@9ZymQ17^UZvGl{(rnvzB(>J_oI-0=OOZ zfVY#SptTZOtC?Rb`2ebMaNwcLMZV>YpJ~CDIoh-2X?p;-!MWxWfUQyq0)$~ zM4$hP-i3^rpA_vNNXvn=QhGaj-+YD}q4}#~y)77z(-^$PI+xkvU&gSGeEp8;3Zq zH>dmMF7Mxx65It16$n=aBJhXsDnN0lFZgDZLxjBNZ@R|}-TV>F;=MyGn?29Em&3ni zw6*?i;@)`R#Fl2mWByu6;9Tx7u}CAp1WJ4>+Z!{p?d}^(2exA1vX;~0cL$e(XuqiP zK8~&jB1P=mt&8eLyam3GxOKF`6Slyp$zaAQ-0s{U(Qmd?_r>%K;AEjCcMBQWcno^P zTw4zj?qBk(j8qpEao`p*vU)4~qGXR-@g5~=Bp7F~IN%})o}Ln2#pn9P6D1Y%h|bj| zviKj+E##g22U__q$gI58BglC5=@5MJWF}1RuV-{m6T_ zW^3#D0`u}duEglV^Ty?eB5mBl{97^Z>Z8rix0E?`BM%!O$Mb`x5me|z);>(~DJI#e z*ESRaqgHPZq-IsoyMGG&tb$h>b-Z{Ul(zPTyFuY9joIly*;|I#*FB#}Kcm)V-~@TO zv-tD@q@uC*xI1e#beSqJj%-+TZq_RZpZ^MN(1l9mR1sYpbB2ytLkDsP!^5^Ncc9vG z6v1)TpbKYT#1%x(6@WfcfW{ z)K?+7Xm?Mahrv-nv!8)opNalg`kT_{K6~zDKPhzZnQAl?){jFaw>^0jFm=$r!;ioi zAHvEy8ZK3}+?q!xU=pf()!+aJkj4wVw5n~|drRMi!9Q4?V6Yy-Zb>O9&^MeF*A-e? zjN5IcO~xC$P)|tRqt0L^tw+j3zE%_+otU{_fDUEnmNeZPbi+ErqNCO$qi_GYGewPa zShytfJrVHm$z>HY;)#Nu-;7Jsz(ldr_8o$#7_dJk24dcM*Nmp5(&2#MNBFObOfTfM ztvtYwkeOh8@oG)C8CS^(0XNZ0BE;7U^pMKVt|0U3^=v1ZEjoTGwbCwwoXv99!OEfC z-BVh5f7vp8%WJX_rO{otD2zik53=b@mn=F1Q$MJnoJ-y!5E;+m|b^P&)pE#hh^0(d+Qn3S*=PM`Gm)|OkH#C=!jnJ5u4n* z`xY7c>qHuEH1ftQj{B!zjy8YiSG`P0tergYGApqAQD*Oz`MFCEevh9x0jfft&Oni3 zEd;EIL7dcZfRhB+1!~xE^{?Fdb1#1B@AKzZ^GCE*9*-_Tb;|ScEL(ZduRE6z99Z6+ z0fg3+K5>}KNq{Zr7Uy4Q6$reiL-T}L@xjsFns7J4d%T-nWX_jlecZ=bvH4J8wI1?k zaJF{lTR(S@jWjuCR{(bSP{zhoKS4Z*hA)O*RX&`r8M_boOnd_8FZreIwcPe_;xx_A zXHEzW+z3_oywJrAPSt-hy(3guqtw~(l?6t^Sn9x(Ek^iV7Feq_R)BliZV54tk zrduwPTi~WGm%Cl4J+9@MNU!SYCjP`+;9Nx}iq9jZD`X^0#O>H(B|}<7Y4-WWsgCk` zt`EtD) z@jrjt4Tq~X%i^MaX*I|q?U>_UF;&!9stk2$VskSj`rjA^btjzfGMpl*80|!h_Iu8J zn?pc)*-PCsZyhyDt3-4B2OPru8x5}KC{ZUsMW$@$mSTn=dL@l+h>10kR@8*)IjO4F+^l%})d;j&ZJ^Lh=eRGzS|75)~jIec(@o)V!7pn7!PJGRz2pyl<{)3D!~F&M#<2i2Q0M; zyhGW@obkxXavS-a)1mK50XB)_*nfX~v@%0vlxh4oh`t@G+AJ2oGE7OC*BLep)ORa# zzu4oqw@jq&JNlqM2SHV@72cvXiHT#>T`H_CXOj$7e(`8;Ss^W+e1K@9gm(iO2<&r) z*ljrwT|#cEzn1}giA9_tb_JO7$6F&-WfLr>U!i<>$x8XRn; z{uNev7`Y>X|9J8CF2AAN?k9VCyzs`*mFr;~2Lpl+`gK|3z?D2o4(*%y#2Ew^XnqU9<OJ8TWS>~pWnOMm;ihkiy_V0N047c+)XVr0nPHB0oH@Z=+w2}nv z?a)iAILw71?E0JeXi9LLMaR3MuxRhFAK?zfSV2bBYo%?sp0M6j+_@KPI6?ahCRO_D zoE4ChIvlS#gk2srR^nSK=aHi52{goqdxX)zRRh1ewQenv$#&qMQH$Bs;24fAwl|9a ztCvmpL(Mjgnq}D!MK`j&y`+U6UL7DF6v`d&Jhz_u!p}UUy91Jsukl&0Ux9K{{Miwo zV!m4K=0*xgo!CMg@7|00Fn|llTzDEQ)ZXE(YZ_<4?BRGh-g*#5e~}Yu-rr(gC1H>3 zyL-aH7Wh_pbzJGsomYbw9**uaZJ|?u(2XN~y^w50*?qb@ASCBi1d%#x-cplm#_Dgf zwy#kBoei%!TN(q`a)*w-D=ujr+GpcRWYcO5hShJ4#6>WRBY?JSlOju;u>)x@x2>(!)sqK@8xN{5NIre3gbeC2Uq~XSu+=mDKP{?RY z7l^d3%AE4*W~_Ov?L&H=t2^k0t6{|>U4lhT)R3sjxEmuE@#WSkZ$BLgP2--pYu z@^Zsb`mmlWdwQw?$%1XY8moG+_svLtRcHH#AJ#QGm>kpKoiMg68;4!M;c1UC^F{9)q#x&IfX!)+!UCuYg`Dq;n&$en0 zfO%&E4g#$A50j)7cn{W2Pp7mW^rMb>*7k)g1&>b8j-)j4KMoEammA6Kn7WX;NF#k} zS#6X%|J5C|Cu{D^WEX4+0r0@5)-R7^G#@vdOtczrIE0BQ!Id;hL+XL;8&yNUU$;K7 zY}}r(h5U(5TwrR@q%>okj9_j*ozDZxF9O~ls}$%&Rsw-h-4!d3-MmZDMy<`wCc#!0 z^F*(Um4|SIq&0Qe6@9(OO#27Vqo!)K{N6EFIWSd#r{R8>5F%KapveHExPe_05Jz2~ zI&hW_Oml(+?DBSBDTyEXg5Isnka93TQqsn+A{ILYIhrX<^8l@W#YDNEfHmft@T03U zF#B%x9=hYCJhwu&nA+!Yd+TuSUT?;@=f#k_LmTNE9F$Z5cNvDVpZo_?7$8=732@bbUzK^9g;q~B?(`Px zzL>C-9J;yKh0K__>6-_TvtEew2gPE6T_k~YgX*fF-`i^nK6sY40nB1U9LrNZ!X~EY zN!UnyxisLyGiA>UeK`W?nr0C9I(LYVldN2t!OOpp#R`@3i?L5vwar*c{Tu)RnGuWc z@sZ1h@GHpbN#ES=E3$WAc$`cC1iamk6HDP|FtJ(|8{ZEQm8n~_ixg9JzQtG4D#wlp z7)3w#z%(B@SFyyYZ)prsWpJkb_ixJ-C{L^?Dr#l)uIwfd0W{O4PrRKE7Kc1D&ja3H zj_thU86(CEJ7O=wj|3)?r&o(CCvN)e1TRz#trxTh&17L<82e^kZu&-BJE}j*vwPX4 z{bs`N8e%+u!At;<+8@-n{Tmz!Eh>@u9Gqn6Y7WH1nG92cL72%Dx{@$tX}2smvH}7) zN|nlWh(A|N^mpv6(WA*`jo?;JQ0A6U{r8{RJtrUdZ)5p@hZ|gC@z(VKM=N_=0+Vb8 zQ@uGGeNzN&36$EuXn}H|m|(kJcSwDu$7u_Lk9DYI9wmY%^-R)Kwm5;crx6JJK_`D@TV znTVO+F@|kMjNW5BX40X9HfJ>_eoUjS4~kug{dwRc7{#yA=vqo(x0|Nl zX6(EGJbnLP0^q8!q@o;irppUyfp1IT7Aq;VLf4S{?B!@{RV0YEkdG+-ru?vJF*xdI zV+>m-lA8?yh~j^soCvV1L(WfN+`(s6B7lK+`zug(nES}|*$IQIURBLCU2$6#DL8(T zSJ2K#E<9m!Y1;|Bl+5fzie)YZ+;=kVFZ)*G9TMAQ>oe$~?Nxp98Px>mtG4T@Ny8Wd zJauP|JonA)u~Kq}KI;DIt~k9AE077Ld6<3WJFFc}Z@8SIMG(XlG|auz|3f{W^c_MN z-_^NZg>Ox_Q0HDD3Dha&@z4Q|@EH%`SH8s(&(ve?sf*;u8<4_AE#~#w?piC8>$*Ct z{Oo*TUnkZp^l7Q5nEmiRu_2MKBtFVyia@p9g87kbLU%jWp$Gm3M2ZM~uXRc5C`;bC z9wJCuC0l`G@a8hi*l>cv$2VT<6G%jccd?1m31VExnq$VvYmd5sum.txt +} diff --git a/iso/scripts/generate_ISO.sh b/iso/scripts/generate_ISO.sh index 024e5397..bf241775 100755 --- a/iso/scripts/generate_ISO.sh +++ b/iso/scripts/generate_ISO.sh @@ -22,4 +22,8 @@ fi mkdir -p /usr/src/app/dappnode touch /usr/src/app/dappnode/iso_install.log -/usr/src/app/iso/scripts/generate_dappnode_iso_debian.sh +if [ "$BASE_OS" = "ubuntu" ]; then + /usr/src/app/iso/scripts/generate_dappnode_iso_ubuntu.sh +else + /usr/src/app/iso/scripts/generate_dappnode_iso_debian.sh +fi diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index c1c9b132..e5f42ccf 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -1,85 +1,98 @@ #!/bin/bash set -e -# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso -ISO_NAME=debian-12.10.0-amd64-netinst.iso -ISO_PATH="/images/${ISO_NAME}" -ISO_URL=https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/ -SHASUM="ee8d8579128977d7dc39d48f43aec5ab06b7f09e1f40a9d98f2a9d149221704a ${ISO_PATH}" - -echo "Downloading debian ISO image: ${ISO_NAME}..." -if [ ! -f ${ISO_PATH} ]; then - wget ${ISO_URL}/${ISO_NAME} \ - -O ${ISO_PATH} -fi -echo "Done!" - -echo "Verifying download..." -[[ "$(shasum -a 256 ${ISO_PATH})" != "$SHASUM" ]] && { - echo "ERROR: wrong shasum" - exit 1 +SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") + +source ${SCRIPTS_DIR}/common_iso_generation.sh + +# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso +BASE_ISO_NAME="debian-12.11.0-amd64-netinst.iso" +BASE_ISO_PATH="/images/${BASE_ISO_NAME}" +BASE_ISO_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${BASE_ISO_NAME}" +BASE_ISO_SHASUM="30ca12a15cae6a1033e03ad59eb7f66a6d5a258dcf27acd115c2bd42d22640e8 ${BASE_ISO_PATH}" + +DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" +DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" + +customize_debian_preseed() { + local iso_build_path=$1 + local workdir=$2 + + echo "[INFO] Customizing preseed..." + + local tmp_initrd="/tmp/makeinitrd" + local install_dir="${iso_build_path}/install.amd" + local preseeds_dir="${workdir}/iso/preseeds" + + rm -rf "${tmp_initrd}" + mkdir -p "${tmp_initrd}" + + local preseed_name="preseed.cfg" + [[ $UNATTENDED == *"true"* ]] && preseed_name="preseed_unattended.cfg" + + local preseed_file="${preseeds_dir}/${preseed_name}" + + if [ ! -f "${preseed_file}" ]; then + echo "[ERROR] Preseed file not found: ${preseed_file}" + exit 1 + fi + + # Extract the initrd into a temporary directory + gunzip -c "${install_dir}/initrd.gz" | cpio -idum -D "${tmp_initrd}" || { + echo "[ERROR] Could not decompress and extract initrd" + exit 1 + } + + # Add the preseed file to the initrd + cp "${preseed_file}" "${tmp_initrd}/preseed.cfg" || { + echo "[ERROR] Could not copy preseed file" + exit 1 + } + + # Recreate (and recompress) the initrd + (cd "${tmp_initrd}" && find . -print0 | cpio -0 -ov -H newc | gzip >"${install_dir}/initrd.gz") || { + echo "[ERROR] Could not create new initrd" + exit 1 + } + + echo "[INFO] Preseed customization complete." +} + +configure_boot_menu() { + local iso_build_path=$1 + local workdir=$2 + + local boot_dir="${workdir}/iso/boot" + + echo "[INFO] Configuring the boot menu for Dappnode..." + cp ${boot_dir}/grub.cfg ${iso_build_path}/boot/grub/grub.cfg + cp ${boot_dir}/theme_1 ${iso_build_path}/boot/grub/theme/1 + cp ${boot_dir}/isolinux.cfg ${iso_build_path}/isolinux/isolinux.cfg + cp ${boot_dir}/menu.cfg ${iso_build_path}/isolinux/menu.cfg + cp ${boot_dir}/txt.cfg ${iso_build_path}/isolinux/txt.cfg + cp ${boot_dir}/splash.png ${iso_build_path}/isolinux/splash.png +} + +generate_debian_iso() { + local mbr_path=$1 + local iso_output_path=$2 + local iso_build_path=$3 + + echo "[INFO] Generating new ISO..." + + xorriso -as mkisofs -isohybrid-mbr ${mbr_path} \ + -c /isolinux/boot.cat -b /isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 \ + -boot-info-table -eltorito-alt-boot -e /boot/grub/efi.img -no-emul-boot \ + -isohybrid-gpt-basdat -o "${iso_output_path}" ${iso_build_path} } -echo "Clean old files..." -rm -rf dappnode-isoº -rm -rf DappNode-debian-* - -echo "Extracting the iso..." -xorriso -osirrox on -indev /images/${ISO_NAME} \ - -extract / dappnode-iso - -echo "Obtaining the isohdpfx.bin for hybrid ISO..." -dd if=/images/${ISO_NAME} bs=432 count=1 \ - of=dappnode-iso/isolinux/isohdpfx.bin - -cd /usr/src/app/dappnode-iso # /usr/src/app/dappnode-iso - -echo "Downloading third-party packages..." -sed '1,/^\#\!ISOBUILD/!d' /usr/src/app/scripts/dappnode_install_pre.sh >/tmp/vars.sh -# shellcheck disable=SC1091 -source /tmp/vars.sh - -echo "Creating necessary directories and copying files..." -mkdir -p /usr/src/app/dappnode-iso/dappnode -cp -r /usr/src/app/scripts /usr/src/app/dappnode-iso/dappnode -cp -r /usr/src/app/dappnode/* /usr/src/app/dappnode-iso/dappnode - -echo "Customizing preseed..." -mkdir -p /tmp/makeinitrd -cd install.amd -cp initrd.gz /tmp/makeinitrd/ -if [[ $UNATTENDED == *"true"* ]]; then - cp /usr/src/app/iso/preseeds/preseed_unattended.cfg /tmp/makeinitrd/preseed.cfg -else - cp /usr/src/app/iso/preseeds/preseed.cfg /tmp/makeinitrd/preseed.cfg -fi -cd /tmp/makeinitrd -gunzip initrd.gz -cpio -id -H newc /tmp/list -echo "preseed.cfg" >>/tmp/list -rm initrd -cpio -o -H newc initrd -gzip initrd -cd - -mv /tmp/makeinitrd/initrd.gz ./initrd.gz -cd .. - -echo "Configuring the boot menu for DappNode..." -cp /usr/src/app/iso/boot/grub.cfg boot/grub/grub.cfg -cp /usr/src/app/iso/boot/theme_1 boot/grub/theme/1 -cp /usr/src/app/iso/boot/isolinux.cfg isolinux/isolinux.cfg -cp /usr/src/app/iso/boot/menu.cfg isolinux/menu.cfg -cp /usr/src/app/iso/boot/txt.cfg isolinux/txt.cfg -cp /usr/src/app/iso/boot/splash.png isolinux/splash.png - -echo "Fix md5 sum..." -# shellcheck disable=SC2046 -md5sum $(find ! -name "md5sum.txt" ! -path "./isolinux/*" -type f) >md5sum.txt - -echo "Generating new iso..." -xorriso -as mkisofs -isohybrid-mbr isolinux/isohdpfx.bin \ - -c isolinux/boot.cat -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 \ - -boot-info-table -eltorito-alt-boot -e boot/grub/efi.img -no-emul-boot \ - -isohybrid-gpt-basdat -o /images/DAppNode-debian-bookworm-amd64.iso . +download_iso "${BASE_ISO_PATH}" "${BASE_ISO_NAME}" "${BASE_ISO_URL}" +verify_download "${BASE_ISO_PATH}" "${BASE_ISO_SHASUM}" +clean_old_files "${ISO_BUILD_PATH}" "${DAPPNODE_ISO_PREFIX}" +extract_iso "${BASE_ISO_PATH}" "${ISO_BUILD_PATH}" +prepare_boot_process "${BASE_ISO_PATH}" "${ISO_BUILD_PATH}/isolinux/isohdpfx.bin" +add_dappnode_files_to_iso_build "${ISO_BUILD_PATH}" "${WORKDIR}" +customize_debian_preseed "${ISO_BUILD_PATH}" "${WORKDIR}" +configure_boot_menu "${ISO_BUILD_PATH}" "${WORKDIR}" +handle_checksums # TODO: Check if it fits both ubuntu and debian +generate_debian_iso "${ISO_BUILD_PATH}/isolinux/isohdpfx.bin" "${DAPPNODE_ISO_PATH}" "${ISO_BUILD_PATH}" diff --git a/iso/scripts/generate_dappnode_iso_ubuntu.sh b/iso/scripts/generate_dappnode_iso_ubuntu.sh new file mode 100755 index 00000000..6b649689 --- /dev/null +++ b/iso/scripts/generate_dappnode_iso_ubuntu.sh @@ -0,0 +1,74 @@ +#!/bin/bash +set -e + +SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") + +source ${SCRIPTS_DIR}/common_iso_generation.sh + +BASE_ISO_NAME=ubuntu-24.04.2-live-server-amd64.iso +BASE_ISO_PATH="/images/${BASE_ISO_NAME}" +BASE_ISO_URL="https://releases.ubuntu.com/24.04/${BASE_ISO_NAME}" +BASE_ISO_SHASUM="d6dab0c3a657988501b4bd76f1297c053df710e06e0c3aece60dead24f270b4d ${BASE_ISO_PATH}" + +DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" +DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" + +get_efi_partition() { + local base_iso_path=$1 + local dest_efi_path=$2 + local block_size=512 + + local efi_start=$(fdisk -l ${base_iso_path} | grep 'Appended2' | awk '{print $2}') + local efi_end=$(fdisk -l ${base_iso_path} | grep 'Appended2' | awk '{print $3}') + local efi_size=$(expr ${efi_end} - ${efi_start} + 1) + + echo "[INFO] Obtaining the EFI partition image from ${efi_start} with size ${efi_size}..." + dd if=${base_iso_path} bs=${block_size} skip="$efi_start" count="$efi_size" of=${dest_efi_path} +} + +add_ubuntu_autoinstall() { + local preseeds_dir=$1 + local iso_build_path=$2 + + echo "[INFO] Adding preseed..." + if [[ $UNATTENDED == *"true"* ]]; then + cp ${preseeds_dir}/autoinstall_unattended.yaml ${iso_build_path}/autoinstall.yaml + else + cp ${preseeds_dir}/autoinstall.yaml ${iso_build_path}/autoinstall.yaml + fi +} + +configure_boot_menu() { + echo "[INFO] Configuring the boot menu for Dappnode..." + cp -r /usr/src/app/iso/boot/ubuntu/* ${ISO_BUILD_PATH}/boot/grub/ +} + +generate_ubuntu_iso() { + local mbr_path=$1 + local efi_path=$2 + local iso_output_path=$3 + local iso_build_path=$4 + + echo "[INFO] Creating the new Ubuntu ISO..." + mkisofs \ + -rational-rock -joliet -joliet-long -full-iso9660-filenames \ + -iso-level 3 -partition_offset 16 --grub2-mbr ${mbr_path} \ + --mbr-force-bootable -append_partition 2 0xEF ${efi_path} \ + -appended_part_as_gpt \ + -eltorito-catalog /boot.catalog \ + -eltorito-boot /boot/grub/i386-pc/eltorito.img -no-emul-boot -boot-load-size 4 \ + -boot-info-table --grub2-boot-info -eltorito-alt-boot --efi-boot '--interval:appended_partition_2:all::' -no-emul-boot \ + -o ${iso_output_path} ${iso_build_path} +} + +download_iso "${BASE_ISO_PATH}" "${BASE_ISO_NAME}" "${BASE_ISO_URL}" +verify_download "${BASE_ISO_PATH}" "${BASE_ISO_SHASUM}" +clean_old_files "${ISO_BUILD_PATH}" "${DAPPNODE_ISO_PREFIX}" +extract_iso "${BASE_ISO_PATH}" "${ISO_BUILD_PATH}" +prepare_boot_process "${BASE_ISO_PATH}" "${ISO_BUILD_PATH}/mbr" +get_efi_partition "${BASE_ISO_PATH}" "${ISO_BUILD_PATH}/efi" +add_dappnode_files_to_iso_build "${ISO_BUILD_PATH}" "${WORKDIR}" +add_ubuntu_autoinstall "/usr/src/app/iso/preseeds/ubuntu" "${ISO_BUILD_PATH}" +configure_boot_menu +handle_checksums +generate_ubuntu_iso "${ISO_BUILD_PATH}/mbr" "${ISO_BUILD_PATH}/efi" "${DAPPNODE_ISO_PATH}" "${ISO_BUILD_PATH}" diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index 331a252f..b25c7bf5 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -11,6 +11,7 @@ LOGS_DIR="$DAPPNODE_DIR/logs" CONTENT_HASH_FILE="${DAPPNODE_CORE_DIR}/packages-content-hash.csv" LOGFILE="${LOGS_DIR}/dappnode_install.log" MOTD_FILE="/etc/motd" +UPDATE_MOTD_DIR="/etc/update-motd.d" DAPPNODE_PROFILE="${DAPPNODE_CORE_DIR}/.dappnode_profile" # Get URLs PROFILE_BRANCH=${PROFILE_BRANCH:-"master"} @@ -186,16 +187,48 @@ dappnode_core_load() { } customMotd() { - if [ -f ${MOTD_FILE} ]; then - cat <${MOTD_FILE} - ___ _ _ _ _ -| \ /_\ _ __ _ __| \| |___ __| |___ -| |) / _ \| '_ \ '_ \ . / _ \/ _ / -_) -|___/_/ \_\ .__/ .__/_|\_\___/\__,_\___| - |_| |_| -EOF - echo -e "$WELCOME_MESSAGE" >>"$MOTD_FILE" + + generateMotdText + + if [ -d "${UPDATE_MOTD_DIR}" ]; then + # Ubuntu configuration + modifyMotdGeneration + fi +} + +# Debian distros use /etc/motd plain text file +generateMotdText() { + # Check and create the MOTD file if it does not exist + if [ ! -f "${MOTD_FILE}" ]; then + touch "${MOTD_FILE}" fi + + # Write the ASCII art and welcome message as plain text + cat <<'EOF' >"${MOTD_FILE}" + ___ _ + | \ __ _ _ __ _ __ _ _ ___ __| |___ + | |) / _` | '_ \ '_ \ ' \/ _ \/ _` / -_) + |___/\__,_| .__/ .__/_||_\___/\__,_\___| + |_| |_| +EOF + echo -e "$WELCOME_MESSAGE" >>"${MOTD_FILE}" +} + +# Ubuntu distros use /etc/update-motd.d/ to generate the motd +modifyMotdGeneration() { + disabled_motd_dir="${UPDATE_MOTD_DIR}/disabled" + + mkdir -p "${disabled_motd_dir}" + + # Move all the files in /etc/update-motd.d/ to /etc/update-motd.d/disabled/ + # Except for the files listed in "files_to_keep" + files_to_keep="00-header 50-landscape-sysinfo 98-reboot-required" + for file in ${UPDATE_MOTD_DIR}/*; do + base_file=$(basename "${file}") + if [ -f "${file}" ] && ! echo "${files_to_keep}" | grep -qw "${base_file}"; then + mv "${file}" "${disabled_motd_dir}/" + fi + done } addSwap() { @@ -290,6 +323,30 @@ installExtraDpkg() { fi } +# The main user needs to be added to the docker group to be able to run docker commands without sudo +# Explained in: https://docs.docker.com/engine/install/linux-postinstall/ +addUserToDockerGroup() { + # UID is provided to the first regular user created in the system + USER=$(grep 1000 "/etc/passwd" | cut -f 1 -d:) + + # If USER is not found, warn the user and return + if [ -z "$USER" ]; then + echo -e "\e[33mWARN: Default user not found. Could not add it to the docker group.\e[0m" 2>&1 | tee -a $LOGFILE + return + fi + + if groups "$USER" | grep &>/dev/null '\bdocker\b'; then + echo -e "\e[32mUser $USER is already in the docker group\e[0m" 2>&1 | tee -a $LOGFILE + return + fi + + # This step is already done in the dappnode_install_pre.sh script, + # but it's not working in the Ubuntu ISO because the late-commands in the autoinstall.yaml + # file are executed before the user is created. + usermod -aG docker "$USER" + echo -e "\e[32mUser $USER added to the docker group\e[0m" 2>&1 | tee -a $LOGFILE +} + ############################################## #### SCRIPT START #### ############################################## @@ -315,9 +372,12 @@ if [ "$ARCH" == "amd64" ]; then installSgx echo -e "\e[32mInstalling extra packages...\e[0m" 2>&1 | tee -a $LOGFILE - installExtraDpkg + installExtraDpkg # TODO: Why is this being called twice? fi +echo -e "\e[32mAdding user to docker group...\e[0m" 2>&1 | tee -a $LOGFILE +addUserToDockerGroup + echo -e "\e[32mCreating dncore_network if needed...\e[0m" 2>&1 | tee -a $LOGFILE docker network create --driver bridge --subnet 172.33.0.0/16 dncore_network 2>&1 | tee -a $LOGFILE diff --git a/scripts/dappnode_install_pre.sh b/scripts/dappnode_install_pre.sh index e09ae685..d6cf4739 100755 --- a/scripts/dappnode_install_pre.sh +++ b/scripts/dappnode_install_pre.sh @@ -6,8 +6,6 @@ DAPPNODE_DIR="/usr/src/dappnode" LOGS_DIR="$DAPPNODE_DIR/logs" lsb_dist="$(. /etc/os-release && echo "$ID")" -#!ISOBUILD Do not modify, variables above imported for ISO build - detect_installation_type() { if [ -f "${DAPPNODE_DIR}/iso_install.log" ]; then LOG_FILE="${LOGS_DIR}/iso_install.log" @@ -22,21 +20,30 @@ detect_installation_type() { add_docker_repo() { apt-get update -y apt-get remove -y docker docker-engine docker.io containerd runc | tee -a $LOG_FILE - apt-get install -y ca-certificates curl gnupg lsb-release | tee -a $LOG_FILE - mkdir -p /etc/apt/keyrings && chmod -R 0755 /etc/apt/keyrings - curl -fsSL "https://download.docker.com/linux/${lsb_dist}/gpg" | gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg + + # Add Docker GPG key + apt-get install -y ca-certificates curl lsb-release | tee -a $LOG_FILE + install -m 0755 -d /etc/apt/keyrings + curl -fsSL "https://download.docker.com/linux/${lsb_dist}/gpg" -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$lsb_dist $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list >/dev/null + + # Add the repository to APT sources + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$lsb_dist $(lsb_release -cs) stable" | + tee /etc/apt/sources.list.d/docker.list >/dev/null + + apt-get update -y } # DOCKER INSTALLATION install_docker() { apt-get update -y - apt-get install -y docker-ce docker-ce-cli containerd.io | tee -a $LOG_FILE + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | tee -a $LOG_FILE # Ensure xz is installed [ -f "/usr/bin/xz" ] || (apt-get install -y xz-utils) + # Not working in Ubuntu ISO because the user is not created before executing late-commands USER=$(grep 1000 "/etc/passwd" | cut -f 1 -d:) [ -z "$USER" ] || usermod -aG docker "$USER" @@ -102,6 +109,34 @@ host_update() { apt-get -y upgrade 2>&1 | tee -a $LOG_FILE } +check_ubuntu_connectivity() { + { netplan get | grep "dhcp4: true" &>/dev/null; } || { + echo "Interfaces not found" + exit 1 + } +} + +check_debian_connectivity() { + { [ -f /etc/network/interfaces ] && grep "iface en.* inet dhcp" /etc/network/interfaces &>/dev/null; } || { + echo "Interfaces not found" + exit 1 + } +} + +add_debian_missing_interfaces() { + # shellcheck disable=SC2013 + for IFACE in $(grep "en.*" /usr/src/dappnode/hotplug); do + # shellcheck disable=SC2143 + if [[ $(grep -L "$IFACE" /etc/network/interfaces) ]]; then + { + echo "# $IFACE" + echo "allow-hotplug $IFACE" + echo "iface $IFACE inet dhcp" + } >>/etc/network/interfaces + fi + done +} + ############################################## #### SCRIPT START #### ############################################## @@ -147,17 +182,10 @@ else install_lsof 2>&1 | tee -a $LOG_FILE fi -## Add missing interfaces -if [ -f /usr/src/dappnode/hotplug ]; then - # shellcheck disable=SC2013 - for IFACE in $(grep "en.*" /usr/src/dappnode/hotplug); do - # shellcheck disable=SC2143 - if [[ $(grep -L "$IFACE" /etc/network/interfaces) ]]; then - { - echo "# $IFACE" - echo "allow-hotplug $IFACE" - echo "iface $IFACE inet dhcp" - } >>/etc/network/interfaces - fi - done +## Add or Update Network Configuration Based on OS +if [ "$lsb_dist" = "ubuntu" ]; then + check_ubuntu_connectivity +else + check_debian_connectivity + add_debian_missing_interfaces fi From c87370e241568175446123e72273634742624b5a Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 11:38:18 +0200 Subject: [PATCH 02/55] fix release yaml --- .github/workflows/release.yml | 70 ++--------------------------------- 1 file changed, 4 insertions(+), 66 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7aacdf6f..744b48de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -165,8 +165,10 @@ jobs: file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" - - # ARTIFACTS ASSETS + - name: Write release content + run: | + echo "# Versions | Package | Version | |---------------------------------|-----------------------| | bind.dnp.dappnode.eth | ${BIND_VERSION} | | ipfs.dnp.dappnode.eth | ${IPFS_VERSION} | | vpn.dnp.dappnode.eth | ${VPN_VERSION} | | dappmanager.dnp.dappnode.eth | ${DAPPMANAGER_VERSION}| | wifi.dnp.dappnode.eth | ${WIFI_VERSION} | | https.dnp.dappnode.eth | ${HTTPS_VERSION} | | wireguard.dnp.dappnode.eth | ${WIREGUARD_VERSION} | # Changes Changes implemented in release ${CORE_VERSION} # Debian Attended Install and customize Dappnode using the Debian attended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} \`\`\` # Debian Unattended Install Debian unattended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso** Reboot right after installation. :warning: **Warning**: This will install Dappnode automatically, wiping all partitions. ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} \`\`\` # Ubuntu Attended Install using the Ubuntu attended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-attended.outputs.SHASUM_UBUNTU_ATTENDED }} \`\`\` # Ubuntu Unattended Install using the Ubuntu unattended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} \`\`\` # Dappnode for Raspberry Pi 4 (64-bit) [Installation guide →](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide) **Default login:** - __user__: dappnode - __password__: dappnodepi" > CHANGELOG.md + cat CHANGELOG.md - name: Artifact uses: actions/upload-artifact@v3 with: @@ -182,75 +184,11 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Check git diff id: git_diff run: | git diff --no-index --word-diff-regex=[^[:space:]] --no-patch .dappnode_profile && echo '::set-output name=HAS_CHANGED::true' || echo '::set-output name=HAS_CHANGED::false' - # … your existing "Artifact" upload-artifact@v3 step here … - - # Generate CHANGELOG.md just like before, - - name: Write release content - run: | - cat > CHANGELOG.md < Date: Wed, 2 Jul 2025 11:54:40 +0200 Subject: [PATCH 03/55] remove artifacts --- .github/workflows/release.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 744b48de..884dfbe1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -169,21 +169,6 @@ jobs: run: | echo "# Versions | Package | Version | |---------------------------------|-----------------------| | bind.dnp.dappnode.eth | ${BIND_VERSION} | | ipfs.dnp.dappnode.eth | ${IPFS_VERSION} | | vpn.dnp.dappnode.eth | ${VPN_VERSION} | | dappmanager.dnp.dappnode.eth | ${DAPPMANAGER_VERSION}| | wifi.dnp.dappnode.eth | ${WIFI_VERSION} | | https.dnp.dappnode.eth | ${HTTPS_VERSION} | | wireguard.dnp.dappnode.eth | ${WIREGUARD_VERSION} | # Changes Changes implemented in release ${CORE_VERSION} # Debian Attended Install and customize Dappnode using the Debian attended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} \`\`\` # Debian Unattended Install Debian unattended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso** Reboot right after installation. :warning: **Warning**: This will install Dappnode automatically, wiping all partitions. ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} \`\`\` # Ubuntu Attended Install using the Ubuntu attended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-attended.outputs.SHASUM_UBUNTU_ATTENDED }} \`\`\` # Ubuntu Unattended Install using the Ubuntu unattended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} \`\`\` # Dappnode for Raspberry Pi 4 (64-bit) [Installation guide →](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide) **Default login:** - __user__: dappnode - __password__: dappnodepi" > CHANGELOG.md cat CHANGELOG.md - - name: Artifact - uses: actions/upload-artifact@v3 - with: - name: test-artifact - path: | - ./Dappnode-debian-*.iso - ./Dappnode-ubuntu-*.iso - ./scripts/dappnode_install.sh - ./scripts/dappnode_install_pre.sh - ./scripts/dappnode_uninstall.sh - ./scripts/dappnode_access_credentials.sh - dappnode_profile.sh - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check git diff id: git_diff run: | @@ -204,7 +189,6 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Create Pull Request if: steps.git_diff.outputs.HAS_CHANGED == 'true' uses: peter-evans/create-pull-request@v5 From 9062c5eb8241721ecce0570b63aa1998396ef6e2 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:01:08 +0200 Subject: [PATCH 04/55] fix files permissions --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 884dfbe1..d3d337c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,6 +80,7 @@ jobs: - name: Set Debian Dappnode attended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) + chmod 777 "$file" attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" mv "$file" "$attended_filename" @@ -96,6 +97,7 @@ jobs: - name: Set Dappnode unattended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) + chmod 777 "$file" core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" mv "$file" "$unattended_filename" @@ -113,6 +115,7 @@ jobs: - name: Set Ubuntu Dappnode attended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) + chmod 777 "$file" attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" mv "$file" "$attended_filename" @@ -129,6 +132,7 @@ jobs: - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) + chmod 777 "$file" core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" mv "$file" "$unattended_filename" From 30cf69f3e9b3c185617635e161a7175a3fb3ec14 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:23:53 +0200 Subject: [PATCH 05/55] ensure non-root user --- Dockerfile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index e5ef57e6..f5571acb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,12 @@ FROM docker:dind -# hadolint ignore=DL3018 RUN apk update && \ - apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils \ - rm -rf /var/cache/apk/* + apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils && \ + addgroup -S docker && \ + adduser -S docker-user -G docker -#RUN apk add -U --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing aufs-util - -# RUN addgroup -g 2999 docker - -# Create app directory WORKDIR /usr/src/app COPY . . -CMD ["/usr/src/app/iso/scripts/generate_ISO.sh"] +USER docker-user # Ensure the container runs as a non-root user + +CMD ["/usr/src/app/iso/scripts/generate_ISO.sh"] From df6fae255e69e65f6a04e20c795f4d1fbf731cf9 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:27:25 +0200 Subject: [PATCH 06/55] do not create docker group --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index f5571acb..c2d24f45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,11 @@ FROM docker:dind + +# Install required packages RUN apk update && \ apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils && \ - addgroup -S docker && \ - adduser -S docker-user -G docker + # Add user to the existing docker group + adduser -S docker-user && \ + addgroup docker-user docker WORKDIR /usr/src/app COPY . . From 1f3487ef223d7112b047823f98f68dc571ee0901 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:27:44 +0200 Subject: [PATCH 07/55] remove chmods --- .github/workflows/release.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3d337c5..8da2feef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,6 @@ jobs: - name: Set Debian Dappnode attended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - chmod 777 "$file" attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" mv "$file" "$attended_filename" @@ -96,8 +95,7 @@ jobs: - name: Set Dappnode unattended ISO name run: | - file=$(ls images/Dappnode-debian-*.iso) - chmod 777 "$file" + file=$(ls images/Dappnode-debian-*.iso) core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" mv "$file" "$unattended_filename" @@ -115,7 +113,6 @@ jobs: - name: Set Ubuntu Dappnode attended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) - chmod 777 "$file" attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" mv "$file" "$attended_filename" @@ -132,7 +129,6 @@ jobs: - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) - chmod 777 "$file" core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" mv "$file" "$unattended_filename" From e038f85acb492b34d2ff979b9739fa059b0b831d Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:31:34 +0200 Subject: [PATCH 08/55] add docker-user to groupd --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index c2d24f45..de5a5de2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,13 +3,14 @@ FROM docker:dind # Install required packages RUN apk update && \ apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils && \ - # Add user to the existing docker group - adduser -S docker-user && \ + # Create user 'docker-user' and add it to the 'docker' group + adduser -S -D -H docker-user && \ addgroup docker-user docker WORKDIR /usr/src/app COPY . . -USER docker-user # Ensure the container runs as a non-root user +# Switch to 'docker-user' to run as a non-root user +USER docker-user CMD ["/usr/src/app/iso/scripts/generate_ISO.sh"] From 93a76d981295c048acd2134ed96053fb9a8b27e9 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:52:19 +0200 Subject: [PATCH 09/55] remove user --- Dockerfile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index de5a5de2..a09836ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,15 +2,9 @@ FROM docker:dind # Install required packages RUN apk update && \ - apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils && \ - # Create user 'docker-user' and add it to the 'docker' group - adduser -S -D -H docker-user && \ - addgroup docker-user docker + apk add --no-cache xorriso git xz curl ca-certificates iptables cpio bash perl-utils WORKDIR /usr/src/app COPY . . -# Switch to 'docker-user' to run as a non-root user -USER docker-user - CMD ["/usr/src/app/iso/scripts/generate_ISO.sh"] From 1b32f446217d6607dc5b97038999da892db96229 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:52:55 +0200 Subject: [PATCH 10/55] use cp command instead --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8da2feef..36283ca0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,7 +81,7 @@ jobs: run: | file=$(ls images/Dappnode-debian-*.iso) attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - mv "$file" "$attended_filename" + cp "$file" "$attended_filename" - name: Build Debian unattended run: | @@ -98,7 +98,7 @@ jobs: file=$(ls images/Dappnode-debian-*.iso) core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" - mv "$file" "$unattended_filename" + cp "$file" "$unattended_filename" - name: Build Ubuntu attended run: | @@ -114,7 +114,7 @@ jobs: run: | file=$(ls images/Dappnode-ubuntu-*.iso) attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - mv "$file" "$attended_filename" + cp "$file" "$attended_filename" - name: Build Ubuntu unattended run: | @@ -131,7 +131,7 @@ jobs: file=$(ls images/Dappnode-ubuntu-*.iso) core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" - mv "$file" "$unattended_filename" + cp "$file" "$unattended_filename" - name: Create dappnode_profile.sh run: | From cf149b3568b6fb3c01461cf4873a06bfd4c95223 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 12:56:51 +0200 Subject: [PATCH 11/55] use docker compose --- .github/workflows/artifacts.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index b82ddac0..2f0b6891 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -113,7 +113,7 @@ jobs: run: | sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml - docker-compose up --build + docker compose up --build - name: Check Ubuntu ISO attended run: | @@ -130,7 +130,7 @@ jobs: run: | sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml - docker-compose up --build + docker compose up --build - name: Check Ubuntu ISO unattended run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36283ca0..37ed0e85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -104,7 +104,7 @@ jobs: run: | sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml - docker-compose up --build + docker compose up --build - name: Check Ubuntu ISO attended run: | @@ -120,7 +120,7 @@ jobs: run: | sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml - docker-compose up --build + docker compose up --build - name: Check Ubuntu ISO unattended run: | From bf756ea83e16662eaa8c2d7674875006a33680bb Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 13:10:15 +0200 Subject: [PATCH 12/55] comment debian attended --- .github/workflows/release.yml | 44 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37ed0e85..48a3ef3e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,21 +100,21 @@ jobs: unattended_filename="${core_filename/%.iso/-unattended.iso}" cp "$file" "$unattended_filename" - - name: Build Ubuntu attended - run: | - sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml - sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml - docker compose up --build - - - name: Check Ubuntu ISO attended - run: | - ls -lrt images/Dappnode-ubuntu-*.iso - - - name: Set Ubuntu Dappnode attended ISO name - run: | - file=$(ls images/Dappnode-ubuntu-*.iso) - attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - cp "$file" "$attended_filename" + # - name: Build Ubuntu attended + # run: | + # sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml + # sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml + # docker compose up --build + + # - name: Check Ubuntu ISO attended + # run: | + # ls -lrt images/Dappnode-ubuntu-*.iso + + # - name: Set Ubuntu Dappnode attended ISO name + # run: | + # file=$(ls images/Dappnode-ubuntu-*.iso) + # attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + # cp "$file" "$attended_filename" - name: Build Ubuntu unattended run: | @@ -152,12 +152,12 @@ jobs: SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - - name: Get SHA-256 Debian attended - id: shasum-ubuntu-attended - run: | - file=$(find . -type f -name 'Dappnode-ubuntu-*.iso' ! -name '*unattended*') - SHASUM_UBUNTU_ATTENDED=$(shasum -a 256 $file)s - echo "::set-output name=SHASUM_UBUNTU_ATTENDED::$SHASUM_UBUNTU_ATTENDED" + # - name: Get SHA-256 Debian attended + # id: shasum-ubuntu-attended + # run: | + # file=$(find . -type f -name 'Dappnode-ubuntu-*.iso' ! -name '*unattended*') + # SHASUM_UBUNTU_ATTENDED=$(shasum -a 256 $file)s + # echo "::set-output name=SHASUM_UBUNTU_ATTENDED::$SHASUM_UBUNTU_ATTENDED" - name: Get SHA-256 Debian unattended id: shasum-ubuntu-unattended @@ -179,11 +179,11 @@ jobs: with: tag_name: ${{ github.event.inputs.core }} prerelease: true + # ./Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso files: | ./Dappnode-${CORE_VERSION}-debian-*.iso ./Dappnode-${CORE_VERSION}-debian-*-unattended.iso ./Dappnode-${CORE_VERSION}-ubuntu-*.iso - ./Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso ./scripts/dappnode_install*.sh dappnode_profile.sh body_path: CHANGELOG.md From 196542c93a30978246de039532175bb80e658968 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 2 Jul 2025 13:36:17 +0200 Subject: [PATCH 13/55] set os and unnattended as envs --- .github/workflows/artifacts.yml | 22 ++++++++++------------ .github/workflows/release.yml | 18 +++++++++--------- .github/workflows/test.yml | 12 ++++++------ docker-compose.yml | 4 ++-- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 2f0b6891..e48a1e8f 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -71,10 +71,9 @@ jobs: # Debian ISO ATTENDED - name: Build Debian attended run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml - docker compose build - docker compose up + export BASE_OS=debian + export UNATTENDED=false + docker compose up --build - name: Check Debian ISO attended run: | @@ -89,10 +88,9 @@ jobs: # Debian ISO UNATTENDED - name: Build Debian unattended run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml - docker compose build - docker compose up + export BASE_OS=debian + export UNATTENDED=true + docker compose up --build - name: Check Debian ISO unattended run: | @@ -111,8 +109,8 @@ jobs: # Ubuntu ISO ATTENDED - name: Build Ubuntu attended run: | - sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml - sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml + export BASE_OS=ubuntu + export UNATTENDED=false docker compose up --build - name: Check Ubuntu ISO attended @@ -128,8 +126,8 @@ jobs: # Ubuntu ISO UNATTENDED - name: Build Ubuntu unattended run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml + export BASE_OS=ubuntu + export UNATTENDED=true docker compose up --build - name: Check Ubuntu ISO unattended diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48a3ef3e..6f5588c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,10 +68,9 @@ jobs: - name: Build Debian attended run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml - docker compose build - docker compose up + export BASE_OS=debian + export UNATTENDED=false + docker compose up --build - name: Check Debian ISO attended run: | @@ -85,7 +84,8 @@ jobs: - name: Build Debian unattended run: | - sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml + export BASE_OS=debian + export UNATTENDED=true docker compose build docker compose up @@ -102,8 +102,8 @@ jobs: # - name: Build Ubuntu attended # run: | - # sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml - # sed -i -e "/UNATTENDED/s/true/false/" docker-compose.yml + # export BASE_OS=ubuntu + # export UNATTENDED=false # docker compose up --build # - name: Check Ubuntu ISO attended @@ -118,8 +118,8 @@ jobs: - name: Build Ubuntu unattended run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - sed -i -e "/UNATTENDED/s/false/true/" docker-compose.yml + export BASE_OS=ubuntu + export UNATTENDED=true docker compose up --build - name: Check Ubuntu ISO unattended diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fe3793e2..d7c85e1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,9 +42,9 @@ jobs: # Create Debian ISO - name: create Debian ISO run: | - sed -i -e "/BASE_OS/s/ubuntu/debian/" docker-compose.yml - docker compose build - docker compose up + export BASE_OS=debian + export UNATTENDED=true + docker compose up --build ls images/ # Verify Debian ISO creation @@ -55,9 +55,9 @@ jobs: # Create Ubuntu ISO - name: create Ubuntu ISO run: | - sed -i -e "/BASE_OS/s/debian/ubuntu/" docker-compose.yml - docker compose build - docker compose up + export BASE_OS=ubuntu + export UNATTENDED=true + docker compose up --build ls images/ # Verify Ubuntu ISO creation diff --git a/docker-compose.yml b/docker-compose.yml index ed9ebe02..b358db40 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,8 @@ services: environment: - BUILD=false # In case you want to re-generate a all the images, not recommended - CLEAN=true # it remove the images directory - - UNATTENDED=false # UNATTENDED version - - BASE_OS=debian # Base OS version (debian or ubuntu) + - UNATTENDED=${UNATTENDED} # UNATTENDED version + - BASE_OS=${BASE_OS} # Base OS version (debian or ubuntu) volumes: - ./images:/images - "/var/run/docker.sock:/var/run/docker.sock" From 682dae7e329a8f32bc188ff1c7319d0abe5f6818 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 14:11:32 +0200 Subject: [PATCH 14/55] fix body release --- .github/workflows/release.yml | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f5588c4..536ef385 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,8 +79,9 @@ jobs: - name: Set Debian Dappnode attended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - cp "$file" "$attended_filename" + filename=$(basename "$file") + attended_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + cp "$file" "images/$attended_filename" - name: Build Debian unattended run: | @@ -96,7 +97,8 @@ jobs: - name: Set Dappnode unattended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + filename=$(basename "$file") + core_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" cp "$file" "$unattended_filename" @@ -129,9 +131,10 @@ jobs: - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) - core_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" + filename=$(basename "$file") + core_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" unattended_filename="${core_filename/%.iso/-unattended.iso}" - cp "$file" "$unattended_filename" + cp "$file" "images/$unattended_filename" - name: Create dappnode_profile.sh run: | @@ -165,14 +168,16 @@ jobs: file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" + - name: Write release content run: | - echo "# Versions | Package | Version | |---------------------------------|-----------------------| | bind.dnp.dappnode.eth | ${BIND_VERSION} | | ipfs.dnp.dappnode.eth | ${IPFS_VERSION} | | vpn.dnp.dappnode.eth | ${VPN_VERSION} | | dappmanager.dnp.dappnode.eth | ${DAPPMANAGER_VERSION}| | wifi.dnp.dappnode.eth | ${WIFI_VERSION} | | https.dnp.dappnode.eth | ${HTTPS_VERSION} | | wireguard.dnp.dappnode.eth | ${WIREGUARD_VERSION} | # Changes Changes implemented in release ${CORE_VERSION} # Debian Attended Install and customize Dappnode using the Debian attended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} \`\`\` # Debian Unattended Install Debian unattended ISO: **Dappnode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso** Reboot right after installation. :warning: **Warning**: This will install Dappnode automatically, wiping all partitions. ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} \`\`\` # Ubuntu Attended Install using the Ubuntu attended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-attended.outputs.SHASUM_UBUNTU_ATTENDED }} \`\`\` # Ubuntu Unattended Install using the Ubuntu unattended ISO: **Dappnode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso** ## ISO SHA-256 Checksum \`\`\` ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} \`\`\` # Dappnode for Raspberry Pi 4 (64-bit) [Installation guide →](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide) **Default login:** - __user__: dappnode - __password__: dappnodepi" > CHANGELOG.md + echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${BIND_VERSION}|\n|ipfs.dnp.dappnode.eth|${IPFS_VERSION}|\n|vpn.dnp.dappnode.eth |${VPN_VERSION}|\n|dappmanager.dnp.dappnode.eth|${DAPPMANAGER_VERSION}|\n|wifi.dnp.dappnode.eth|${WIFI_VERSION}|\n|https.dnp.dappnode.eth|${HTTPS_VERSION}|\n|wireguard.dnp.dappnode.eth|${WIREGUARD_VERSION}|\n# Changes\nChanges implemented in release ${CORE_VERSION}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso\n${SHASUM_DEBIAN_ATTENDED}\n\`\`\`\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso\n${SHASUM_DEBIAN_UNATTENDED}\n\`\`\`\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso\n${SHASUM_UBUNTU_UNATTENDED}\n\`\`\`\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md cat CHANGELOG.md - - name: Check git diff - id: git_diff - run: | - git diff --no-index --word-diff-regex=[^[:space:]] --no-patch .dappnode_profile && echo '::set-output name=HAS_CHANGED::true' || echo '::set-output name=HAS_CHANGED::false' + env: + SHASUM_DEBIAN_ATTENDED: ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} + SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} + # SHASUM_UBUNTU_ATTENDED: ${{ steps.shasum-ubuntu-attended.outputs.SHASUM_UBUNTU_ATTENDED }} + SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} - name: Create pre-release uses: softprops/action-gh-release@v2 @@ -189,12 +194,3 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Create Pull Request - if: steps.git_diff.outputs.HAS_CHANGED == 'true' - uses: peter-evans/create-pull-request@v5 - with: - add-paths: ".dappnode_profile" - commit-message: "update core packages versions" - branch: "update-profile" - title: "update core packages versions" - delete-branch: true From bd53b6b827bace375815de9e447e8b1cb4132371 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 14:20:48 +0200 Subject: [PATCH 15/55] fix naming set --- .github/workflows/release.yml | 51 +++++++++-------------------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 536ef385..ad42a0e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,9 +79,9 @@ jobs: - name: Set Debian Dappnode attended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - filename=$(basename "$file") - attended_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - cp "$file" "images/$attended_filename" + filename=$(basename "$file") # Extract only the file name (without path) + attended_filename="images/Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION + cp "$file" "$attended_filename" - name: Build Debian unattended run: | @@ -94,29 +94,13 @@ jobs: run: | ls -lrt images/Dappnode-debian-*.iso - - name: Set Dappnode unattended ISO name + - name: Set Debian Dappnode unattended ISO name run: | - file=$(ls images/Dappnode-debian-*.iso) - filename=$(basename "$file") - core_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - unattended_filename="${core_filename/%.iso/-unattended.iso}" - cp "$file" "$unattended_filename" - - # - name: Build Ubuntu attended - # run: | - # export BASE_OS=ubuntu - # export UNATTENDED=false - # docker compose up --build - - # - name: Check Ubuntu ISO attended - # run: | - # ls -lrt images/Dappnode-ubuntu-*.iso - - # - name: Set Ubuntu Dappnode attended ISO name - # run: | - # file=$(ls images/Dappnode-ubuntu-*.iso) - # attended_filename="${file/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - # cp "$file" "$attended_filename" + file=$(ls images/Dappnode-debian-*.iso) + filename=$(basename "$file") # Extract only the file name (without path) + core_filename="Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION + unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso + cp "$file" "images/$unattended_filename" - name: Build Ubuntu unattended run: | @@ -131,9 +115,9 @@ jobs: - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) - filename=$(basename "$file") - core_filename="${filename/images\/Dappnode-/Dappnode-${CORE_VERSION}-}" - unattended_filename="${core_filename/%.iso/-unattended.iso}" + filename=$(basename "$file") # Extract only the file name (without path) + core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION + unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso cp "$file" "images/$unattended_filename" - name: Create dappnode_profile.sh @@ -155,13 +139,6 @@ jobs: SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - # - name: Get SHA-256 Debian attended - # id: shasum-ubuntu-attended - # run: | - # file=$(find . -type f -name 'Dappnode-ubuntu-*.iso' ! -name '*unattended*') - # SHASUM_UBUNTU_ATTENDED=$(shasum -a 256 $file)s - # echo "::set-output name=SHASUM_UBUNTU_ATTENDED::$SHASUM_UBUNTU_ATTENDED" - - name: Get SHA-256 Debian unattended id: shasum-ubuntu-unattended run: | @@ -176,7 +153,6 @@ jobs: env: SHASUM_DEBIAN_ATTENDED: ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} - # SHASUM_UBUNTU_ATTENDED: ${{ steps.shasum-ubuntu-attended.outputs.SHASUM_UBUNTU_ATTENDED }} SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} - name: Create pre-release @@ -184,11 +160,10 @@ jobs: with: tag_name: ${{ github.event.inputs.core }} prerelease: true - # ./Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso files: | ./Dappnode-${CORE_VERSION}-debian-*.iso ./Dappnode-${CORE_VERSION}-debian-*-unattended.iso - ./Dappnode-${CORE_VERSION}-ubuntu-*.iso + ./Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso ./scripts/dappnode_install*.sh dappnode_profile.sh body_path: CHANGELOG.md From ef3ef7b8b95eb3e3794952da91381ee8909b6868 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 14:47:02 +0200 Subject: [PATCH 16/55] use sudo --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad42a0e5..033ef273 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,7 +81,7 @@ jobs: file=$(ls images/Dappnode-debian-*.iso) filename=$(basename "$file") # Extract only the file name (without path) attended_filename="images/Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION - cp "$file" "$attended_filename" + sudo cp "$file" "$attended_filename" - name: Build Debian unattended run: | @@ -100,7 +100,7 @@ jobs: filename=$(basename "$file") # Extract only the file name (without path) core_filename="Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso - cp "$file" "images/$unattended_filename" + sudo cp "$file" "images/$unattended_filename" - name: Build Ubuntu unattended run: | @@ -118,7 +118,7 @@ jobs: filename=$(basename "$file") # Extract only the file name (without path) core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso - cp "$file" "images/$unattended_filename" + sudo cp "$file" "images/$unattended_filename" - name: Create dappnode_profile.sh run: | From bcad9e7d45957cb8931e78e2847fa3bd39f301b9 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 14:54:37 +0200 Subject: [PATCH 17/55] add images subpath --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 033ef273..69510452 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -161,10 +161,10 @@ jobs: tag_name: ${{ github.event.inputs.core }} prerelease: true files: | - ./Dappnode-${CORE_VERSION}-debian-*.iso - ./Dappnode-${CORE_VERSION}-debian-*-unattended.iso - ./Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso - ./scripts/dappnode_install*.sh + ./images/Dappnode-${CORE_VERSION}-debian-*.iso + ./images/Dappnode-${CORE_VERSION}-debian-*-unattended.iso + ./images/Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso + ./images/scripts/dappnode_install*.sh dappnode_profile.sh body_path: CHANGELOG.md env: From e6f160d4de911506e1a24ff718e5c3b68f0d750d Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 15:02:13 +0200 Subject: [PATCH 18/55] add print images dir --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69510452..52a7537e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -155,6 +155,12 @@ jobs: SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} + # print images directory + - name: Print images directory + run: | + echo "Images directory content:" + ls -lrt images/ + - name: Create pre-release uses: softprops/action-gh-release@v2 with: From 70f9649671ba08390bdfbd87f9b199a718f2dc1b Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 15:03:46 +0200 Subject: [PATCH 19/55] add uninstall script --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52a7537e..6ce25256 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -170,7 +170,8 @@ jobs: ./images/Dappnode-${CORE_VERSION}-debian-*.iso ./images/Dappnode-${CORE_VERSION}-debian-*-unattended.iso ./images/Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso - ./images/scripts/dappnode_install*.sh + ./scripts/dappnode_install*.sh + ./scripts/dappnode_uninstall*.sh dappnode_profile.sh body_path: CHANGELOG.md env: From c146bc369fad6815f4de2d8d442dd9a0c6fb218e Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 16:06:51 +0200 Subject: [PATCH 20/55] fix naming regex --- .github/workflows/release.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ce25256..2757a562 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,8 +80,9 @@ jobs: run: | file=$(ls images/Dappnode-debian-*.iso) filename=$(basename "$file") # Extract only the file name (without path) - attended_filename="images/Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION - sudo cp "$file" "$attended_filename" + core_filename="Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION + attended_filename="${core_filename/%.iso/-attended.iso}" # Replace .iso with -attended.iso + sudo cp "$file" "images/$attended_filename" - name: Build Debian unattended run: | @@ -167,9 +168,9 @@ jobs: tag_name: ${{ github.event.inputs.core }} prerelease: true files: | - ./images/Dappnode-${CORE_VERSION}-debian-*.iso - ./images/Dappnode-${CORE_VERSION}-debian-*-unattended.iso - ./images/Dappnode-${CORE_VERSION}-ubuntu-*-unattended.iso + ./images/Dappnode-*-debian-*-attended.iso + ./images/Dappnode-*-debian-*-unattended.iso + ./images/Dappnode-*-ubuntu-*-unattended.iso ./scripts/dappnode_install*.sh ./scripts/dappnode_uninstall*.sh dappnode_profile.sh From a94948591dc7eda8333b4e22831ad40d3ed6cfec Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 16:23:24 +0200 Subject: [PATCH 21/55] compress unattended --- .github/workflows/release.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2757a562..07166ddc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -111,7 +111,12 @@ jobs: - name: Check Ubuntu ISO unattended run: | - ls -lrt images/Dappnode-ubuntu-*.iso + ls -lrt images/Dappnode-ubuntu-*-unattended.iso.xz + + - name: Compress Ubuntu Dappnode unattended ISO + run: | + file=$(ls images/Dappnode-*-ubuntu-*-unattended.iso) + xz -T0 -z -v "$file" - name: Set Ubuntu Dappnode unattended ISO name run: | @@ -120,6 +125,8 @@ jobs: core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso sudo cp "$file" "images/$unattended_filename" + # Compress the new file as well + xz -T0 -z -v "images/$unattended_filename" - name: Create dappnode_profile.sh run: | @@ -140,10 +147,10 @@ jobs: SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - - name: Get SHA-256 Debian unattended + - name: Get SHA-256 Ubuntu unattended id: shasum-ubuntu-unattended run: | - file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') + file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso.xz') SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" @@ -170,7 +177,7 @@ jobs: files: | ./images/Dappnode-*-debian-*-attended.iso ./images/Dappnode-*-debian-*-unattended.iso - ./images/Dappnode-*-ubuntu-*-unattended.iso + ./images/Dappnode-*-ubuntu-*-unattended.iso.xz ./scripts/dappnode_install*.sh ./scripts/dappnode_uninstall*.sh dappnode_profile.sh From a732f1a8bf3b6bce700e805ce6c70ae288151955 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Wed, 2 Jul 2025 17:49:52 +0200 Subject: [PATCH 22/55] fix check --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07166ddc..6c941196 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -111,7 +111,7 @@ jobs: - name: Check Ubuntu ISO unattended run: | - ls -lrt images/Dappnode-ubuntu-*-unattended.iso.xz + ls -lrt images/Dappnode-ubuntu-*.iso - name: Compress Ubuntu Dappnode unattended ISO run: | From a98ee64d7871c92390090de4d4f6e8ebaeca92cc Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Thu, 3 Jul 2025 09:01:39 +0200 Subject: [PATCH 23/55] compress ubuntu --- .github/workflows/release.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6c941196..b8de9dfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,11 +113,6 @@ jobs: run: | ls -lrt images/Dappnode-ubuntu-*.iso - - name: Compress Ubuntu Dappnode unattended ISO - run: | - file=$(ls images/Dappnode-*-ubuntu-*-unattended.iso) - xz -T0 -z -v "$file" - - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) @@ -125,8 +120,11 @@ jobs: core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso sudo cp "$file" "images/$unattended_filename" - # Compress the new file as well - xz -T0 -z -v "images/$unattended_filename" + + - name: Compress Ubuntu Dappnode unattended ISO + run: | + file=$(ls images/Dappnode-*-ubuntu-*-unattended.iso) + xz -T0 -z -v "$file" - name: Create dappnode_profile.sh run: | From acc3d94f83f9f30279f874becd0ba4bd15d429e9 Mon Sep 17 00:00:00 2001 From: Pablo Mendez Date: Thu, 3 Jul 2025 09:06:25 +0200 Subject: [PATCH 24/55] add sudo to xz command --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8de9dfc..33462050 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -124,7 +124,7 @@ jobs: - name: Compress Ubuntu Dappnode unattended ISO run: | file=$(ls images/Dappnode-*-ubuntu-*-unattended.iso) - xz -T0 -z -v "$file" + sudo xz -T0 -z -v "$file" - name: Create dappnode_profile.sh run: | From 8359e95af9381bab1ec3c28872b96214fa0a06fb Mon Sep 17 00:00:00 2001 From: Marc Font <36164126+Marketen@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:41:03 +0200 Subject: [PATCH 25/55] add docker compose down for core pkg (#662) * add docker compose down for core pkg * fix order --- .dappnode_profile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dappnode_profile b/.dappnode_profile index 9951723d..baefcefe 100755 --- a/.dappnode_profile +++ b/.dappnode_profile @@ -30,6 +30,8 @@ alias dappnode_status='docker compose $DNCORE_YMLS ps' alias dappnode_stop='docker compose $DNCORE_YMLS stop && docker stop $(docker container ls -a -q -f name=DAppNode*)' # Start docker core containers alias dappnode_start='docker compose $DNCORE_YMLS up -d && docker start $(docker container ls -a -q -f name=DAppNode*)' +# Remove docker core containers. This does not remove named volumes +alias dappnode_down='docker compose $DNCORE_YMLS down' # Return open-vpn credentials from a specific user. e.g: dappnode_get dappnode_admin alias dappnode_openvpn_get='docker exec -i DAppNodeCore-vpn.dnp.dappnode.eth vpncli get' # Return open-vpn admin credentials From 700b5c33bd40632850d93372979790d83b3640bc Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:13:54 +0200 Subject: [PATCH 26/55] Comment ubuntu release in gha (#665) * Comment ubuntu release in gha * update url * comment ubuntu --- .github/workflows/release.yml | 56 +++++++++------------ .github/workflows/test.yml | 18 +++---- iso/scripts/generate_dappnode_iso_debian.sh | 2 +- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33462050..7a6364ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -103,28 +103,23 @@ jobs: unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso sudo cp "$file" "images/$unattended_filename" - - name: Build Ubuntu unattended - run: | - export BASE_OS=ubuntu - export UNATTENDED=true - docker compose up --build - - - name: Check Ubuntu ISO unattended - run: | - ls -lrt images/Dappnode-ubuntu-*.iso - - - name: Set Ubuntu Dappnode unattended ISO name - run: | - file=$(ls images/Dappnode-ubuntu-*.iso) - filename=$(basename "$file") # Extract only the file name (without path) - core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION - unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso - sudo cp "$file" "images/$unattended_filename" - - - name: Compress Ubuntu Dappnode unattended ISO - run: | - file=$(ls images/Dappnode-*-ubuntu-*-unattended.iso) - sudo xz -T0 -z -v "$file" + # - name: Build Ubuntu unattended + # run: | + # export BASE_OS=ubuntu + # export UNATTENDED=true + # docker compose up --build + + # - name: Check Ubuntu ISO unattended + # run: | + # ls -lrt images/Dappnode-ubuntu-*.iso + + # - name: Set Ubuntu Dappnode unattended ISO name + # run: | + # file=$(ls images/Dappnode-ubuntu-*.iso) + # filename=$(basename "$file") # Extract only the file name (without path) + # core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION + # unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso + # sudo cp "$file" "images/$unattended_filename" - name: Create dappnode_profile.sh run: | @@ -145,21 +140,21 @@ jobs: SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - - name: Get SHA-256 Ubuntu unattended - id: shasum-ubuntu-unattended - run: | - file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso.xz') - SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) - echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" + # - name: Get SHA-256 Ubuntu unattended + # id: shasum-ubuntu-unattended + # run: | + # file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') + # SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) + # echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" - name: Write release content run: | - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${BIND_VERSION}|\n|ipfs.dnp.dappnode.eth|${IPFS_VERSION}|\n|vpn.dnp.dappnode.eth |${VPN_VERSION}|\n|dappmanager.dnp.dappnode.eth|${DAPPMANAGER_VERSION}|\n|wifi.dnp.dappnode.eth|${WIFI_VERSION}|\n|https.dnp.dappnode.eth|${HTTPS_VERSION}|\n|wireguard.dnp.dappnode.eth|${WIREGUARD_VERSION}|\n# Changes\nChanges implemented in release ${CORE_VERSION}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso\n${SHASUM_DEBIAN_ATTENDED}\n\`\`\`\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso\n${SHASUM_DEBIAN_UNATTENDED}\n\`\`\`\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-ubuntu-bookworm-amd64-unattended.iso\n${SHASUM_UBUNTU_UNATTENDED}\n\`\`\`\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md + echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${BIND_VERSION}|\n|ipfs.dnp.dappnode.eth|${IPFS_VERSION}|\n|vpn.dnp.dappnode.eth |${VPN_VERSION}|\n|dappmanager.dnp.dappnode.eth|${DAPPMANAGER_VERSION}|\n|wifi.dnp.dappnode.eth|${WIFI_VERSION}|\n|https.dnp.dappnode.eth|${HTTPS_VERSION}|\n|wireguard.dnp.dappnode.eth|${WIREGUARD_VERSION}|\n# Changes\nChanges implemented in release ${CORE_VERSION}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso\n${SHASUM_DEBIAN_ATTENDED}\n\`\`\`\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso\n${SHASUM_DEBIAN_UNATTENDED}\n\`\`\`\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\n\`\`\`\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md cat CHANGELOG.md env: SHASUM_DEBIAN_ATTENDED: ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} - SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} + # SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} # print images directory - name: Print images directory @@ -175,7 +170,6 @@ jobs: files: | ./images/Dappnode-*-debian-*-attended.iso ./images/Dappnode-*-debian-*-unattended.iso - ./images/Dappnode-*-ubuntu-*-unattended.iso.xz ./scripts/dappnode_install*.sh ./scripts/dappnode_uninstall*.sh dappnode_profile.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7c85e1b..730b5b89 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,14 +53,14 @@ jobs: ls -lrt images/Dappnode-debian-*.iso # Create Ubuntu ISO - - name: create Ubuntu ISO - run: | - export BASE_OS=ubuntu - export UNATTENDED=true - docker compose up --build - ls images/ + # - name: create Ubuntu ISO + # run: | + # export BASE_OS=ubuntu + # export UNATTENDED=true + # docker compose up --build + # ls images/ # Verify Ubuntu ISO creation - - name: verify Ubuntu ISO - run: | - ls -lrt images/Dappnode-ubuntu-*.iso + # - name: verify Ubuntu ISO + # run: | + # ls -lrt images/Dappnode-ubuntu-*.iso diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index e5f42ccf..97d0d52a 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -8,7 +8,7 @@ source ${SCRIPTS_DIR}/common_iso_generation.sh # Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso BASE_ISO_NAME="debian-12.11.0-amd64-netinst.iso" BASE_ISO_PATH="/images/${BASE_ISO_NAME}" -BASE_ISO_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${BASE_ISO_NAME}" +BASE_ISO_URL="https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/${BASE_ISO_NAME}" BASE_ISO_SHASUM="30ca12a15cae6a1033e03ad59eb7f66a6d5a258dcf27acd115c2bd42d22640e8 ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" From 3be6e789c755edec7eaaffea79d9618213af8846 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Thu, 4 Sep 2025 09:27:29 +0200 Subject: [PATCH 27/55] use archive url (#668) --- iso/scripts/generate_dappnode_iso_debian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index 97d0d52a..201e0082 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -5,7 +5,7 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso +# Source = https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso BASE_ISO_NAME="debian-12.11.0-amd64-netinst.iso" BASE_ISO_PATH="/images/${BASE_ISO_NAME}" BASE_ISO_URL="https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/${BASE_ISO_NAME}" From 9362e51e3b20a780c5be529425825473f4f7dabc Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Thu, 4 Sep 2025 10:52:13 +0200 Subject: [PATCH 28/55] Add ubuntu ISO to CI (#669) * Add ubuntu ISO to CI * fix file path usage * feat: add ubuntu test * bump ubuntu to 0.3 --- .github/workflows/release.yml | 59 ++++++++++++--------- .github/workflows/test.yml | 18 +++---- iso/scripts/generate_dappnode_iso_ubuntu.sh | 4 +- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a6364ad..d6a3b89a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -103,23 +103,23 @@ jobs: unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso sudo cp "$file" "images/$unattended_filename" - # - name: Build Ubuntu unattended - # run: | - # export BASE_OS=ubuntu - # export UNATTENDED=true - # docker compose up --build - - # - name: Check Ubuntu ISO unattended - # run: | - # ls -lrt images/Dappnode-ubuntu-*.iso - - # - name: Set Ubuntu Dappnode unattended ISO name - # run: | - # file=$(ls images/Dappnode-ubuntu-*.iso) - # filename=$(basename "$file") # Extract only the file name (without path) - # core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION - # unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso - # sudo cp "$file" "images/$unattended_filename" + - name: Build Ubuntu unattended + run: | + export BASE_OS=ubuntu + export UNATTENDED=true + docker compose up --build + + - name: Check Ubuntu ISO unattended + run: | + ls -lrt images/Dappnode-ubuntu-*.iso + + - name: Set Ubuntu Dappnode unattended ISO name + run: | + file=$(ls images/Dappnode-ubuntu-*.iso) + filename=$(basename "$file") # Extract only the file name (without path) + core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION + unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso + sudo cp "$file" "images/$unattended_filename" - name: Create dappnode_profile.sh run: | @@ -140,12 +140,13 @@ jobs: SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - # - name: Get SHA-256 Ubuntu unattended - # id: shasum-ubuntu-unattended - # run: | - # file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') - # SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) - # echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" + - name: Get SHA-256 Ubuntu unattended + id: shasum-ubuntu-unattended + run: | + file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') + SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) + echo "$SHASUM_UBUNTU_UNATTENDED" > SHASUM_UBUNTU_UNATTENDED.txt + echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" - name: Write release content run: | @@ -154,7 +155,6 @@ jobs: env: SHASUM_DEBIAN_ATTENDED: ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} - # SHASUM_UBUNTU_UNATTENDED: ${{ steps.shasum-ubuntu-unattended.outputs.SHASUM_UBUNTU_UNATTENDED }} # print images directory - name: Print images directory @@ -176,3 +176,14 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Ubuntu unattended to SSH server (and shasum) + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.ISO_SSH_HOST }} + username: ${{ secrets.ISO_SSH_USER }} + key: ${{ secrets.ISO_SSH_PRIVATE_KEY }} + port: ${{ secrets.SSH_PORT }} + source: SHASUM_UBUNTU_UNATTENDED.txt,./images/Dappnode-*-ubuntu-*-unattended.iso + target: ${{ secrets.ISO_SSH_PATH }} + overwrite: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 730b5b89..d7c85e1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,14 +53,14 @@ jobs: ls -lrt images/Dappnode-debian-*.iso # Create Ubuntu ISO - # - name: create Ubuntu ISO - # run: | - # export BASE_OS=ubuntu - # export UNATTENDED=true - # docker compose up --build - # ls images/ + - name: create Ubuntu ISO + run: | + export BASE_OS=ubuntu + export UNATTENDED=true + docker compose up --build + ls images/ # Verify Ubuntu ISO creation - # - name: verify Ubuntu ISO - # run: | - # ls -lrt images/Dappnode-ubuntu-*.iso + - name: verify Ubuntu ISO + run: | + ls -lrt images/Dappnode-ubuntu-*.iso diff --git a/iso/scripts/generate_dappnode_iso_ubuntu.sh b/iso/scripts/generate_dappnode_iso_ubuntu.sh index 6b649689..c1c1a270 100755 --- a/iso/scripts/generate_dappnode_iso_ubuntu.sh +++ b/iso/scripts/generate_dappnode_iso_ubuntu.sh @@ -5,10 +5,10 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -BASE_ISO_NAME=ubuntu-24.04.2-live-server-amd64.iso +BASE_ISO_NAME=ubuntu-24.04.3-live-server-amd64.iso BASE_ISO_PATH="/images/${BASE_ISO_NAME}" BASE_ISO_URL="https://releases.ubuntu.com/24.04/${BASE_ISO_NAME}" -BASE_ISO_SHASUM="d6dab0c3a657988501b4bd76f1297c053df710e06e0c3aece60dead24f270b4d ${BASE_ISO_PATH}" +BASE_ISO_SHASUM="c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" From a0a2a4616075c75e3c6f7f13ed28be66edad997f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:25:36 +0200 Subject: [PATCH 29/55] Ensure .dappnode_profile is sourced in all shell environments (#670) * Initial plan * Fix DAppNode profile sourcing in all shell environments Co-authored-by: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> --- scripts/dappnode_install.sh | 21 +++++++++++++++------ scripts/dappnode_uninstall.sh | 14 ++++++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index b25c7bf5..f285289a 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -266,12 +266,21 @@ dappnode_start() { # Show credentials to the user on login USER=$(grep 1000 /etc/passwd | cut -f 1 -d:) - [ -n "$USER" ] && PROFILE=/home/$USER/.profile || PROFILE=/root/.profile - - if ! grep -q "${DAPPNODE_PROFILE}" "$PROFILE"; then - echo "######## DAPPNODE PROFILE ########" >>$PROFILE - echo -e "source ${DAPPNODE_PROFILE}\n" >>$PROFILE - fi + [ -n "$USER" ] && USER_HOME=/home/$USER || USER_HOME=/root + + # Add profile sourcing to both .profile and .bashrc for maximum compatibility + for config_file in .profile .bashrc; do + CONFIG_PATH="$USER_HOME/$config_file" + + # Create config file if it doesn't exist + [ ! -f "$CONFIG_PATH" ] && touch "$CONFIG_PATH" + + # Add profile sourcing if not already present + if ! grep -q "${DAPPNODE_PROFILE}" "$CONFIG_PATH"; then + echo "######## DAPPNODE PROFILE ########" >>"$CONFIG_PATH" + echo -e "source ${DAPPNODE_PROFILE}\n" >>"$CONFIG_PATH" + fi + done # Remove return from profile sed -i '/return/d' $DAPPNODE_PROFILE | tee -a $LOGFILE diff --git a/scripts/dappnode_uninstall.sh b/scripts/dappnode_uninstall.sh index 9f9c68b7..66bc9f35 100755 --- a/scripts/dappnode_uninstall.sh +++ b/scripts/dappnode_uninstall.sh @@ -45,11 +45,17 @@ uninstall() { echo -e "\e[32mRemoving DAppNode directory\e[0m" rm -rf /usr/src/dappnode - # Remove profile file + # Remove profile file references from shell config files USER=$(grep 1000 /etc/passwd | cut -f 1 -d:) - [ -n "$USER" ] && PROFILE=/home/$USER/.profile || PROFILE=/root/.profile - sed -i '/######## DAPPNODE PROFILE ########/g' $PROFILE - sed -i '/.*dappnode_profile/g' $PROFILE + [ -n "$USER" ] && USER_HOME=/home/$USER || USER_HOME=/root + + for config_file in .profile .bashrc; do + CONFIG_PATH="$USER_HOME/$config_file" + if [ -f "$CONFIG_PATH" ]; then + sed -i '/######## DAPPNODE PROFILE ########/d' "$CONFIG_PATH" + sed -i '/.*dappnode_profile/d' "$CONFIG_PATH" + fi + done echo -e "\e[32mDAppNode uninstalled!\e[0m" } From 88d91c2e8619a729ade1d3eda4817a5af2dba421 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:05:48 +0200 Subject: [PATCH 30/55] fix: ubuntu command execution (#673) --- iso/preseeds/ubuntu/autoinstall.yaml | 3 ++- iso/preseeds/ubuntu/autoinstall_unattended.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/iso/preseeds/ubuntu/autoinstall.yaml b/iso/preseeds/ubuntu/autoinstall.yaml index 1957f019..4fb3eadc 100644 --- a/iso/preseeds/ubuntu/autoinstall.yaml +++ b/iso/preseeds/ubuntu/autoinstall.yaml @@ -19,7 +19,8 @@ autoinstall: - iptables late-commands: - - "curtin in-target --target=/target -- apt update && apt install -y chrony build-essential iw iwd avahi-utils" + - "curtin in-target --target=/target -- apt-get update" + - "curtin in-target --target=/target -- apt-get install -y chrony build-essential iw iwd avahi-utils" - "mkdir -p /target/usr/src/dappnode" - "cp -ar /cdrom/dappnode/* /target/usr/src/dappnode/" - "cp -a /cdrom/dappnode/scripts/rc.local /target/etc/rc.local" diff --git a/iso/preseeds/ubuntu/autoinstall_unattended.yaml b/iso/preseeds/ubuntu/autoinstall_unattended.yaml index bb43891a..0e4fd24e 100644 --- a/iso/preseeds/ubuntu/autoinstall_unattended.yaml +++ b/iso/preseeds/ubuntu/autoinstall_unattended.yaml @@ -33,7 +33,8 @@ autoinstall: timezone: UTC late-commands: - - "curtin in-target --target=/target -- apt update && apt install -y chrony build-essential iw iwd avahi-utils" + - "curtin in-target --target=/target -- apt-get update" + - "curtin in-target --target=/target -- apt-get install -y chrony build-essential iw iwd avahi-utils" - "mkdir -p /target/usr/src/dappnode" - "cp -ar /cdrom/dappnode/* /target/usr/src/dappnode/" - "cp -a /cdrom/dappnode/scripts/rc.local /target/etc/rc.local" From e214226719117d07facab3d6ef3bb7bc62c7afc1 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:27:39 +0100 Subject: [PATCH 31/55] Add missing `access_credential.sh` script (#677) --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d6a3b89a..022b2869 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -172,6 +172,7 @@ jobs: ./images/Dappnode-*-debian-*-unattended.iso ./scripts/dappnode_install*.sh ./scripts/dappnode_uninstall*.sh + ./scripts/dappnode_access_credentials*.sh dappnode_profile.sh body_path: CHANGELOG.md env: From 056f53d24485a05ce3ac668938c404db9678d6fe Mon Sep 17 00:00:00 2001 From: 3alpha Date: Wed, 12 Nov 2025 09:30:11 -0300 Subject: [PATCH 32/55] parallelize workflows --- .github/workflows/release.yml | 188 ++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 66 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 022b2869..05273600 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,23 +38,26 @@ env: CORE_VERSION: ${{ github.event.inputs.core }} jobs: - pre-release: - name: Create pre-release artifacts + set-versions: + name: Set versions and check regex runs-on: ubuntu-latest - defaults: - run: - shell: bash - + outputs: + bind: ${{ env.BIND_VERSION }} + ipfs: ${{ env.IPFS_VERSION }} + dappmanager: ${{ env.DAPPMANAGER_VERSION }} + wifi: ${{ env.WIFI_VERSION }} + wireguard: ${{ env.WIREGUARD_VERSION }} + https: ${{ env.HTTPS_VERSION }} + vpn: ${{ env.VPN_VERSION }} + core: ${{ env.CORE_VERSION }} steps: - name: Check versions regex run: | [[ $BIND_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $IPFS_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $DAPPMANAGER_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ [[ $WIFI_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $WIREGUARD_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $HTTPS_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ [[ $VPN_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $CORE_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "versions introduced in wrong format"; exit 1; } - - name: Checkout uses: actions/checkout@v4 - - name: Set new versions run: | sed -i -e "/BIND_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${BIND_VERSION}"/" .dappnode_profile @@ -65,107 +68,161 @@ jobs: sed -i -e "/WIREGUARD_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${WIREGUARD_VERSION}"/" .dappnode_profile sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${HTTPS_VERSION}"/" .dappnode_profile cat .dappnode_profile + - name: Create dappnode_profile.sh + run: cp .dappnode_profile dappnode_profile.sh + - name: Upload dappnode_profile.sh + uses: actions/upload-artifact@v4 + with: + name: dappnode_profile + path: dappnode_profile.sh + build-debian-attended: + name: Build Debian attended ISO + runs-on: ubuntu-latest + needs: set-versions + steps: + - uses: actions/checkout@v4 + - name: Download dappnode_profile + uses: actions/download-artifact@v4 + with: + name: dappnode_profile - name: Build Debian attended run: | export BASE_OS=debian export UNATTENDED=false docker compose up --build - - - name: Check Debian ISO attended - run: | - ls -lrt images/Dappnode-debian-*.iso - - name: Set Debian Dappnode attended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - filename=$(basename "$file") # Extract only the file name (without path) - core_filename="Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION - attended_filename="${core_filename/%.iso/-attended.iso}" # Replace .iso with -attended.iso + filename=$(basename "$file") + core_filename="Dappnode-${{ needs.set-versions.outputs.core }}-debian-${filename#Dappnode-debian-}" + attended_filename="${core_filename/%.iso/-attended.iso}" sudo cp "$file" "images/$attended_filename" + - name: Upload Debian attended ISO + uses: actions/upload-artifact@v4 + with: + name: debian-attended-iso + path: images/*-attended.iso + - name: Get SHA-256 Debian attended + run: | + file=$(find images/ -type f -name '*-attended.iso') + shasum -a 256 $file > SHASUM_DEBIAN_ATTENDED.txt + - name: Upload Debian attended SHA256 + uses: actions/upload-artifact@v4 + with: + name: debian-attended-sha + path: SHASUM_DEBIAN_ATTENDED.txt + build-debian-unattended: + name: Build Debian unattended ISO + runs-on: ubuntu-latest + needs: set-versions + steps: + - uses: actions/checkout@v4 + - name: Download dappnode_profile + uses: actions/download-artifact@v4 + with: + name: dappnode_profile - name: Build Debian unattended run: | export BASE_OS=debian export UNATTENDED=true docker compose build docker compose up - - - name: Check Debian ISO unattended - run: | - ls -lrt images/Dappnode-debian-*.iso - - name: Set Debian Dappnode unattended ISO name run: | file=$(ls images/Dappnode-debian-*.iso) - filename=$(basename "$file") # Extract only the file name (without path) - core_filename="Dappnode-${CORE_VERSION}-debian-${filename#Dappnode-debian-}" # Modify the filename using CORE_VERSION - unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso + filename=$(basename "$file") + core_filename="Dappnode-${{ needs.set-versions.outputs.core }}-debian-${filename#Dappnode-debian-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" sudo cp "$file" "images/$unattended_filename" + - name: Upload Debian unattended ISO + uses: actions/upload-artifact@v4 + with: + name: debian-unattended-iso + path: images/*-unattended.iso + - name: Get SHA-256 Debian unattended + run: | + file=$(find images/ -type f -name '*-unattended.iso') + shasum -a 256 $file > SHASUM_DEBIAN_UNATTENDED.txt + - name: Upload Debian unattended SHA256 + uses: actions/upload-artifact@v4 + with: + name: debian-unattended-sha + path: SHASUM_DEBIAN_UNATTENDED.txt + build-ubuntu-unattended: + name: Build Ubuntu unattended ISO + runs-on: ubuntu-latest + needs: set-versions + steps: + - uses: actions/checkout@v4 + - name: Download dappnode_profile + uses: actions/download-artifact@v4 + with: + name: dappnode_profile - name: Build Ubuntu unattended run: | export BASE_OS=ubuntu export UNATTENDED=true docker compose up --build - - - name: Check Ubuntu ISO unattended - run: | - ls -lrt images/Dappnode-ubuntu-*.iso - - name: Set Ubuntu Dappnode unattended ISO name run: | file=$(ls images/Dappnode-ubuntu-*.iso) - filename=$(basename "$file") # Extract only the file name (without path) - core_filename="Dappnode-${CORE_VERSION}-ubuntu-${filename#Dappnode-ubuntu-}" # Modify the filename using CORE_VERSION - unattended_filename="${core_filename/%.iso/-unattended.iso}" # Replace .iso with -unattended.iso + filename=$(basename "$file") + core_filename="Dappnode-${{ needs.set-versions.outputs.core }}-ubuntu-${filename#Dappnode-ubuntu-}" + unattended_filename="${core_filename/%.iso/-unattended.iso}" sudo cp "$file" "images/$unattended_filename" - - - name: Create dappnode_profile.sh - run: | - cp .dappnode_profile dappnode_profile.sh - - # SHASUMs - - name: Get SHA-256 Debian attended - id: shasum-debian-attended - run: | - file=$(find . -type f -name 'Dappnode-debian-*.iso' ! -name '*unattended*') - SHASUM_DEBIAN_ATTENDED=$(shasum -a 256 $file) - echo "::set-output name=SHASUM_DEBIAN_ATTENDED::$SHASUM_DEBIAN_ATTENDED" - - - name: Get SHA-256 Debian unattended - id: shasum-debian-unattended - run: | - file=$(find . -type f -name 'Dappnode-debian-*unattended.iso') - SHASUM_DEBIAN_UNATTENDED=$(shasum -a 256 $file) - echo "::set-output name=SHASUM_DEBIAN_UNATTENDED::$SHASUM_DEBIAN_UNATTENDED" - - name: Get SHA-256 Ubuntu unattended - id: shasum-ubuntu-unattended run: | - file=$(find . -type f -name 'Dappnode-ubuntu-*unattended.iso') - SHASUM_UBUNTU_UNATTENDED=$(shasum -a 256 $file) - echo "$SHASUM_UBUNTU_UNATTENDED" > SHASUM_UBUNTU_UNATTENDED.txt - echo "::set-output name=SHASUM_UBUNTU_UNATTENDED::$SHASUM_UBUNTU_UNATTENDED" + file=$(find images/ -type f -name '*-ubuntu-*-unattended.iso') + shasum -a 256 $file > SHASUM_UBUNTU_UNATTENDED.txt + - name: Upload Ubuntu unattended ISO and SHA256 to SSH + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.ISO_SSH_HOST }} + username: ${{ secrets.ISO_SSH_USER }} + key: ${{ secrets.ISO_SSH_PRIVATE_KEY }} + port: ${{ secrets.SSH_PORT }} + source: SHASUM_UBUNTU_UNATTENDED.txt,images/*-ubuntu-*-unattended.iso + target: ${{ secrets.ISO_SSH_PATH }} + overwrite: true + release: + name: Combine, release, and upload + runs-on: ubuntu-latest + needs: + - build-debian-attended + - build-debian-unattended + - build-ubuntu-unattended + steps: + - uses: actions/checkout@v4 + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: ./artifacts + - name: Move ISOs and SHAs + run: | + mkdir -p images + mv artifacts/debian-attended-iso/* images/ + mv artifacts/debian-unattended-iso/* images/ + mv artifacts/debian-attended-sha/* . + mv artifacts/debian-unattended-sha/* . + mv artifacts/dappnode_profile/* . - name: Write release content run: | - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${BIND_VERSION}|\n|ipfs.dnp.dappnode.eth|${IPFS_VERSION}|\n|vpn.dnp.dappnode.eth |${VPN_VERSION}|\n|dappmanager.dnp.dappnode.eth|${DAPPMANAGER_VERSION}|\n|wifi.dnp.dappnode.eth|${WIFI_VERSION}|\n|https.dnp.dappnode.eth|${HTTPS_VERSION}|\n|wireguard.dnp.dappnode.eth|${WIREGUARD_VERSION}|\n# Changes\nChanges implemented in release ${CORE_VERSION}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64.iso\n${SHASUM_DEBIAN_ATTENDED}\n\`\`\`\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\nshasum -a 256 DAppNode-${CORE_VERSION}-debian-bookworm-amd64-unattended.iso\n${SHASUM_DEBIAN_UNATTENDED}\n\`\`\`\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n\`\`\`\n\`\`\`\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md + SHASUM_DEBIAN_ATTENDED=$(cat SHASUM_DEBIAN_ATTENDED.txt) + SHASUM_DEBIAN_UNATTENDED=$(cat SHASUM_DEBIAN_UNATTENDED.txt) + echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\nUploaded directly to SSH server.\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md cat CHANGELOG.md - env: - SHASUM_DEBIAN_ATTENDED: ${{ steps.shasum-debian-attended.outputs.SHASUM_DEBIAN_ATTENDED }} - SHASUM_DEBIAN_UNATTENDED: ${{ steps.shasum-debian-unattended.outputs.SHASUM_DEBIAN_UNATTENDED }} - - # print images directory - name: Print images directory run: | echo "Images directory content:" ls -lrt images/ - - name: Create pre-release uses: softprops/action-gh-release@v2 with: - tag_name: ${{ github.event.inputs.core }} + tag_name: ${{ needs.set-versions.outputs.core }} prerelease: true files: | ./images/Dappnode-*-debian-*-attended.iso @@ -177,7 +234,6 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Ubuntu unattended to SSH server (and shasum) uses: appleboy/scp-action@v0.1.7 with: From 77bdf5a0baaec866b3a4ff73e654c042178fe98f Mon Sep 17 00:00:00 2001 From: 3alpha Date: Wed, 12 Nov 2025 10:13:29 -0300 Subject: [PATCH 33/55] fix wf issues --- .github/workflows/release.yml | 77 +++++++++++++++++------------------ 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05273600..3fa53176 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,46 +27,37 @@ on: description: "Version of the OpenVPN Package. Only numbers" required: true -env: - BIND_VERSION: ${{ github.event.inputs.bind }} - IPFS_VERSION: ${{ github.event.inputs.ipfs }} - DAPPMANAGER_VERSION: ${{ github.event.inputs.dappmanager }} - WIFI_VERSION: ${{ github.event.inputs.wifi }} - WIREGUARD_VERSION: ${{ github.event.inputs.wireguard }} - HTTPS_VERSION: ${{ github.event.inputs.https }} - VPN_VERSION: ${{ github.event.inputs.vpn }} - CORE_VERSION: ${{ github.event.inputs.core }} jobs: set-versions: name: Set versions and check regex runs-on: ubuntu-latest outputs: - bind: ${{ env.BIND_VERSION }} - ipfs: ${{ env.IPFS_VERSION }} - dappmanager: ${{ env.DAPPMANAGER_VERSION }} - wifi: ${{ env.WIFI_VERSION }} - wireguard: ${{ env.WIREGUARD_VERSION }} - https: ${{ env.HTTPS_VERSION }} - vpn: ${{ env.VPN_VERSION }} - core: ${{ env.CORE_VERSION }} + bind: ${{ steps.set_outputs.outputs.bind }} + ipfs: ${{ steps.set_outputs.outputs.ipfs }} + dappmanager: ${{ steps.set_outputs.outputs.dappmanager }} + wifi: ${{ steps.set_outputs.outputs.wifi }} + wireguard: ${{ steps.set_outputs.outputs.wireguard }} + https: ${{ steps.set_outputs.outputs.https }} + vpn: ${{ steps.set_outputs.outputs.vpn }} + core: ${{ steps.set_outputs.outputs.core }} steps: - name: Check versions regex run: | - [[ $BIND_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $IPFS_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $DAPPMANAGER_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ - [[ $WIFI_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $WIREGUARD_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $HTTPS_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ - [[ $VPN_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $CORE_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "versions introduced in wrong format"; exit 1; } + [[ "${{ github.event.inputs.bind }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.ipfs }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.dappmanager }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ + [[ "${{ github.event.inputs.wifi }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.wireguard }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.https }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ + [[ "${{ github.event.inputs.vpn }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.core }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "versions introduced in wrong format"; exit 1; } - name: Checkout uses: actions/checkout@v4 - name: Set new versions run: | - sed -i -e "/BIND_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${BIND_VERSION}"/" .dappnode_profile - sed -i -e "/IPFS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${IPFS_VERSION}"/" .dappnode_profile - sed -i -e "/VPN_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${VPN_VERSION}"/" .dappnode_profile - sed -i -e "/DAPPMANAGER_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${DAPPMANAGER_VERSION}"/" .dappnode_profile - sed -i -e "/WIFI_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${WIFI_VERSION}"/" .dappnode_profile - sed -i -e "/WIREGUARD_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${WIREGUARD_VERSION}"/" .dappnode_profile - sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${HTTPS_VERSION}"/" .dappnode_profile + sed -i -e "/BIND_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.bind }}"/" .dappnode_profile + sed -i -e "/IPFS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.ipfs }}"/" .dappnode_profile + sed -i -e "/VPN_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.vpn }}"/" .dappnode_profile + sed -i -e "/DAPPMANAGER_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.dappmanager }}"/" .dappnode_profile + sed -i -e "/WIFI_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.wifi }}"/" .dappnode_profile + sed -i -e "/WIREGUARD_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.wireguard }}"/" .dappnode_profile + sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.https }}"/" .dappnode_profile cat .dappnode_profile - name: Create dappnode_profile.sh run: cp .dappnode_profile dappnode_profile.sh @@ -75,6 +66,17 @@ jobs: with: name: dappnode_profile path: dappnode_profile.sh + - name: Set outputs + id: set_outputs + run: | + echo "core=${{ github.event.inputs.core }}" >> $GITHUB_OUTPUT + echo "bind=${{ github.event.inputs.bind }}" >> $GITHUB_OUTPUT + echo "ipfs=${{ github.event.inputs.ipfs }}" >> $GITHUB_OUTPUT + echo "dappmanager=${{ github.event.inputs.dappmanager }}" >> $GITHUB_OUTPUT + echo "wifi=${{ github.event.inputs.wifi }}" >> $GITHUB_OUTPUT + echo "wireguard=${{ github.event.inputs.wireguard }}" >> $GITHUB_OUTPUT + echo "https=${{ github.event.inputs.https }}" >> $GITHUB_OUTPUT + echo "vpn=${{ github.event.inputs.vpn }}" >> $GITHUB_OUTPUT build-debian-attended: name: Build Debian attended ISO @@ -187,6 +189,11 @@ jobs: source: SHASUM_UBUNTU_UNATTENDED.txt,images/*-ubuntu-*-unattended.iso target: ${{ secrets.ISO_SSH_PATH }} overwrite: true + - name: Upload Ubuntu unattended SHA256 as artifact + uses: actions/upload-artifact@v4 + with: + name: ubuntu-unattended-sha + path: SHASUM_UBUNTU_UNATTENDED.txt release: name: Combine, release, and upload @@ -208,12 +215,14 @@ jobs: mv artifacts/debian-unattended-iso/* images/ mv artifacts/debian-attended-sha/* . mv artifacts/debian-unattended-sha/* . + mv artifacts/ubuntu-unattended-sha/* . mv artifacts/dappnode_profile/* . - name: Write release content run: | SHASUM_DEBIAN_ATTENDED=$(cat SHASUM_DEBIAN_ATTENDED.txt) SHASUM_DEBIAN_UNATTENDED=$(cat SHASUM_DEBIAN_UNATTENDED.txt) - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\nUploaded directly to SSH server.\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md + SHASUM_UBUNTU_UNATTENDED=$(cat SHASUM_UBUNTU_UNATTENDED.txt) + echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso\n$SHASUM_UBUNTU_UNATTENDED\n```\nUploaded at https://ubuntu.iso.dappnode.io\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md cat CHANGELOG.md - name: Print images directory run: | @@ -233,14 +242,4 @@ jobs: dappnode_profile.sh body_path: CHANGELOG.md env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Ubuntu unattended to SSH server (and shasum) - uses: appleboy/scp-action@v0.1.7 - with: - host: ${{ secrets.ISO_SSH_HOST }} - username: ${{ secrets.ISO_SSH_USER }} - key: ${{ secrets.ISO_SSH_PRIVATE_KEY }} - port: ${{ secrets.SSH_PORT }} - source: SHASUM_UBUNTU_UNATTENDED.txt,./images/Dappnode-*-ubuntu-*-unattended.iso - target: ${{ secrets.ISO_SSH_PATH }} - overwrite: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 775f396f0641b10627ed84799c5ff9bfab12e50d Mon Sep 17 00:00:00 2001 From: 3alpha Date: Wed, 12 Nov 2025 10:44:34 -0300 Subject: [PATCH 34/55] fix wf --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3fa53176..5762c75f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -199,6 +199,7 @@ jobs: name: Combine, release, and upload runs-on: ubuntu-latest needs: + - set-versions - build-debian-attended - build-debian-unattended - build-ubuntu-unattended From 09dc55ae4c9af427c481862fc08ccb719956ec15 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:26:33 +0100 Subject: [PATCH 35/55] set correct name to dappnode_profile (#680) --- .github/workflows/release.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5762c75f..94223b52 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,6 @@ on: description: "Version of the OpenVPN Package. Only numbers" required: true - jobs: set-versions: name: Set versions and check regex @@ -88,6 +87,8 @@ jobs: uses: actions/download-artifact@v4 with: name: dappnode_profile + - name: Rename dappnode_profile.sh to .dappnode_profile + run: mv dappnode_profile.sh .dappnode_profile - name: Build Debian attended run: | export BASE_OS=debian @@ -125,6 +126,8 @@ jobs: uses: actions/download-artifact@v4 with: name: dappnode_profile + - name: Rename dappnode_profile.sh to .dappnode_profile + run: mv dappnode_profile.sh .dappnode_profile - name: Build Debian unattended run: | export BASE_OS=debian @@ -163,6 +166,8 @@ jobs: uses: actions/download-artifact@v4 with: name: dappnode_profile + - name: Rename dappnode_profile.sh to .dappnode_profile + run: mv dappnode_profile.sh .dappnode_profile - name: Build Ubuntu unattended run: | export BASE_OS=ubuntu @@ -243,4 +248,4 @@ jobs: dappnode_profile.sh body_path: CHANGELOG.md env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c6fb055f763854f57e7d441bb55712fc0ffd383b Mon Sep 17 00:00:00 2001 From: Marketen Date: Thu, 18 Dec 2025 19:00:16 +0100 Subject: [PATCH 36/55] check if 80 and 443 ports are used & https running --- scripts/dappnode_install.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index f285289a..fc58ff17 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -57,9 +57,27 @@ is_iso_install() { fi } -# Check is port 80 in used (necessary for HTTPS) +# Check if port 80 is in use (necessary for HTTPS) +# Returns IS_PORT_USED=true only if port 80 or 443 is used by something OTHER than our HTTPS container is_port_used() { - lsof -i -P -n | grep ":80 (LISTEN)" &>/dev/null && IS_PORT_USED=true || IS_PORT_USED=false + # Check if port 80 or 443 is in use at all + local port80_used port443_used + lsof -i -P -n | grep ":80 (LISTEN)" &>/dev/null && port80_used=true || port80_used=false + lsof -i -P -n | grep ":443 (LISTEN)" &>/dev/null && port443_used=true || port443_used=false + + if [ "$port80_used" = false ] && [ "$port443_used" = false ]; then + IS_PORT_USED=false + return + fi + + # If either port is in use, check if it's our HTTPS container + if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^DAppNodeCore-https.dnp.dappnode.eth$"; then + # Port 80 or 443 is used by our HTTPS container, so we consider it "not used" for package determination + IS_PORT_USED=false + else + # Port 80 or 443 is used by something else + IS_PORT_USED=true + fi } # Determine packages to be installed From bcc05b2d7004e1dcfcdfbd89f4ec502821d97f8e Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:35:02 +0100 Subject: [PATCH 37/55] Add macOS compatibility for DAppNode profile and improve alias handling (#692) --- .dappnode_profile | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/.dappnode_profile b/.dappnode_profile index baefcefe..538e868f 100755 --- a/.dappnode_profile +++ b/.dappnode_profile @@ -18,31 +18,50 @@ export HTTPS_VERSION="${HTTPS:-0.2.2}" export DAPPNODE_DIR="/usr/src/dappnode" export DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" +# macOS host-mode helpers (this file is often sourced in a shell) +if [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then + export DISABLE_HOST_SCRIPTS="${DISABLE_HOST_SCRIPTS:-true}" + + for user_home in /Users/*; do + [ -d "$user_home" ] || continue + [ -d "$user_home/dappnode/DNCORE" ] || continue + export DAPPNODE_DIR="$user_home/dappnode" + export DAPPNODE_CORE_DIR="$user_home/dappnode/DNCORE" + break + done +fi + #!ISOBUILD Do not modify, variables above imported for ISO build -DNCORE_YMLS=$(find $DAPPNODE_CORE_DIR -name "docker-compose-*.yml" -printf "-f %p ") -# shellcheck disable=SC2207 -# shellcheck disable=SC2034 -DNCORE_YMLS_ARRAY=($(find /usr/src/dappnode/DNCORE -name "docker-compose-*.yml" | sort)) + +DNCORE_YMLS="" +if [ -d "$DAPPNODE_CORE_DIR" ]; then + DNCORE_YMLS=$(find "$DAPPNODE_CORE_DIR" -name "docker-compose-*.yml" -print | sort | sed 's|^|-f |' | tr '\n' ' ') +fi # Returns docker core containers status -alias dappnode_status='docker compose $DNCORE_YMLS ps' -# Stop docker core containers -alias dappnode_stop='docker compose $DNCORE_YMLS stop && docker stop $(docker container ls -a -q -f name=DAppNode*)' -# Start docker core containers -alias dappnode_start='docker compose $DNCORE_YMLS up -d && docker start $(docker container ls -a -q -f name=DAppNode*)' -# Remove docker core containers. This does not remove named volumes -alias dappnode_down='docker compose $DNCORE_YMLS down' +# NOTE: zsh does not word-split `$DNCORE_YMLS` by default, so use `${=DNCORE_YMLS}` there. +if [ -n "${ZSH_VERSION:-}" ]; then + alias dappnode_status='docker compose ${=DNCORE_YMLS} ps' + alias dappnode_stop='docker compose ${=DNCORE_YMLS} stop && docker stop $(docker container ls -a -q -f name=DAppNode*)' + alias dappnode_start='docker compose ${=DNCORE_YMLS} up -d && docker start $(docker container ls -a -q -f name=DAppNode*)' + alias dappnode_down='docker compose ${=DNCORE_YMLS} down' +else + alias dappnode_status='docker compose $DNCORE_YMLS ps' + alias dappnode_stop='docker compose $DNCORE_YMLS stop && docker stop $(docker container ls -a -q -f name=DAppNode*)' + alias dappnode_start='docker compose $DNCORE_YMLS up -d && docker start $(docker container ls -a -q -f name=DAppNode*)' + alias dappnode_down='docker compose $DNCORE_YMLS down' +fi # Return open-vpn credentials from a specific user. e.g: dappnode_get dappnode_admin alias dappnode_openvpn_get='docker exec -i DAppNodeCore-vpn.dnp.dappnode.eth vpncli get' # Return open-vpn admin credentials alias dappnode_openvpn='docker exec -i DAppNodeCore-vpn.dnp.dappnode.eth getAdminCredentials' # Return wifi credentials (ssid and password) -alias dappnode_wifi='cat /usr/src/dappnode/DNCORE/docker-compose-wifi.yml | grep "SSID\|WPA_PASSPHRASE"' +alias dappnode_wifi='cat "$DAPPNODE_CORE_DIR/docker-compose-wifi.yml" | grep "SSID\|WPA_PASSPHRASE"' # Return remote credentials in plain text. OPTIONS: # --qr (QR format). --local (local creds for NAT loopback issues) alias dappnode_wireguard='docker exec -i DAppNodeCore-api.wireguard.dnp.dappnode.eth getWireguardCredentials' # Execute access_credentials.sh script to check for connectivity methods -alias dappnode_connect='/usr/bin/bash /usr/src/dappnode/scripts/dappnode_access_credentials.sh' +alias dappnode_connect='/usr/bin/bash "$DAPPNODE_DIR/scripts/dappnode_access_credentials.sh"' # Return all available commands alias dappnode_help='echo -e "\n\tDAppNode commands available:\n\n\tdappnode_help\t\tprints out this message\n\n\tdappnode_wifi\t\tget wifi credentials (SSID and password)\n\n\tdappnode_openvpn\tget Open VPN credentials\n\n\tdappnode_wireguard\tget Wireguard VPN credentials (dappnode_wireguard --help for more info)\n\n\tdappnode_connect\tcheck connectivity methods available in DAppNode\n\n\tdappnode_status\t\tget status of dappnode containers\n\n\tdappnode_start\t\tstart dappnode containers\n\n\tdappnode_stop\t\tstop dappnode containers\n"' # Compose alias for backward compatibility From dcd2e8614d8626e6b22e9cc32cefbf9bbaa3e87a Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:17:37 +0100 Subject: [PATCH 38/55] Add linter CI to profile script (#693) * Add macOS compatibility for DAppNode profile and improve alias handling * Add shell compatibility checks for .dappnode_profile in CI workflow * Update actions/checkout to v6 in linter workflow --- .github/workflows/linter.yml | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 58b25b85..0307d510 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 @@ -33,3 +33,33 @@ jobs: FILTER_REGEX_EXCLUDE: .github/* DEFAULT_BRANCH: master GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + shell-compat: + name: Shell compatibility (.dappnode_profile) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Install zsh (Ubuntu) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y zsh + + - name: Parse check (bash) + run: bash -n .dappnode_profile + + - name: Parse check (zsh) + run: zsh -n .dappnode_profile + + - name: Source check (bash) + run: bash -lc 'set -euo pipefail; source ./.dappnode_profile' + + - name: Source check (zsh) + run: zsh -lc 'set -e; source ./.dappnode_profile; alias dappnode_status >/dev/null' From ce00ffae38297975c0b913c2b4af3e204ca38906 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Mon, 9 Mar 2026 09:19:05 +0100 Subject: [PATCH 39/55] Enhance macOS compatibility in installation script (#694) * Enhance macOS compatibility in installation script - Added checks to ensure the script is executed, not sourced. - Improved OS detection and handling for macOS and Linux. - Updated directory paths for macOS. - Introduced cross-platform helper functions for downloading files and modifying files. - Added functionality to patch the .dappnode_profile for macOS compatibility. - Enhanced user shell configuration to source the profile correctly. - Cleaned up rc.local for Linux installations. - Improved logging and user feedback during installation. * Add macOS support for installation scripts and update DAppNode core start function * Normalize component names to lowercase in download URL and file paths * Update macOS test script to install Docker using Homebrew * Normalize component names to lowercase in Docker image loading logic * Remove macOS test scripts from workflow configuration * Update IPFS endpoint and enhance logging in installation script * Refactor logging in installation script to remove color output and improve readability * uninstall script in macos (#695) * uninstall script in macos * comment reexec under bash * comment * remove colors logic --------- Co-authored-by: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> * Enhance installation script with improved error handling, logging, and CLI wrappers for VPN commands * Remove core CLI wrappers from installation script to streamline execution * Add macOS-specific environment variable injection for dappmanager compose * Fix DISABLE_HOST_SCRIPTS environment variable handling in macOS patch function * Initialize DNCORE_COMPOSE_ARGS array to prevent unbound variable errors * Refactor macOS patch function to handle environment variable insertion with temporary file for compatibility * Increase sleep duration to 30 seconds for VPN initialization in installation script * Implement wait_for_internal_ip function to ensure dappmanager publishes INTERNAL_IP before proceeding * Add macOS server detection and adjust package selection for always-on Macs * Add patch for macOS non-server to use remote IPFS services in maindb.json * Enhance wait_for_internal_ip function to check for HOSTNAME alongside INTERNAL_IP and improve error messaging; add wait for maindb.json file existence in macOS non-server patch function * Remove macOS non-server patch for remote IPFS services from installation script * Remove default PROFILE_BRANCH assignment from installation script * Add support for minimal installation mode and enhance argument parsing in installer script * Increase wait time for VPN initialization in installer script * Add function to print VPN access credentials after core startup * Refactor Linux setup steps to conditionally execute based on MINIMAL mode * Add support for Notifications and Premium packages in installation scripts (#696) * Add local profile path argument to DAppNode installation script * Add support for macOS in VPN access credential retrieval * Add support for custom package selection in installation script * Add interactive setup wizard to installation script * Add conditional output for VPN credentials based on selected packages * Remove interactive mode support from installation script * Add support for lite installation mode in the installation script * Refactor installation script by removing macOS-specific checks and unused functions * Improve Docker prerequisite checks in installation script * Remove outdated comment regarding patch_compose_paths function in installation script --------- Co-authored-by: Marc Font <36164126+Marketen@users.noreply.github.com> --- .dappnode_profile | 2 + .github/workflows/release.yml | 17 +- .github/workflows/test.yml | 4 +- scripts/dappnode_install.sh | 1084 ++++++++++++++++++++++++++------- scripts/dappnode_uninstall.sh | 111 +++- 5 files changed, 989 insertions(+), 229 deletions(-) diff --git a/.dappnode_profile b/.dappnode_profile index 538e868f..ece7e1bd 100755 --- a/.dappnode_profile +++ b/.dappnode_profile @@ -14,6 +14,8 @@ export DAPPMANAGER_VERSION="${DAPPMANAGER_VERSION:-0.2.99}" export WIFI_VERSION="${WIFI_VERSION:-0.2.9}" export WIREGUARD_VERSION="${WIREGUARD_VERSION:-0.1.3}" export HTTPS_VERSION="${HTTPS:-0.2.2}" +export NOTIFICATIONS_VERSION="/ipfs/QmQubxH4WgqEFxvFntef4H2DmuU6mxBRS6XeuShc3owNi9" +export PREMIUM_VERSION="/ipfs/QmXDddoa56HkrvtkGsa3mozpsn9SzQZtoVBWgagcW6SsHy" export DAPPNODE_DIR="/usr/src/dappnode" export DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 94223b52..ad7c934e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,12 @@ on: vpn: description: "Version of the OpenVPN Package. Only numbers" required: true + notifications: + description: "IPFS hash of the Notifications Package. Must start with /ipfs/" + required: true + premium: + description: "IPFS hash of the Premium Package. Must start with /ipfs/" + required: true jobs: set-versions: @@ -39,13 +45,16 @@ jobs: wireguard: ${{ steps.set_outputs.outputs.wireguard }} https: ${{ steps.set_outputs.outputs.https }} vpn: ${{ steps.set_outputs.outputs.vpn }} + notifications: ${{ steps.set_outputs.outputs.notifications }} + premium: ${{ steps.set_outputs.outputs.premium }} core: ${{ steps.set_outputs.outputs.core }} steps: - name: Check versions regex run: | [[ "${{ github.event.inputs.bind }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.ipfs }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.dappmanager }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ [[ "${{ github.event.inputs.wifi }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.wireguard }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.https }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ - [[ "${{ github.event.inputs.vpn }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.core }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "versions introduced in wrong format"; exit 1; } + [[ "${{ github.event.inputs.vpn }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "${{ github.event.inputs.core }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && \ + [[ "${{ github.event.inputs.notifications }}" =~ ^/ipfs/.+$ ]] && [[ "${{ github.event.inputs.premium }}" =~ ^/ipfs/.+$ ]] || { echo "versions introduced in wrong format"; exit 1; } - name: Checkout uses: actions/checkout@v4 - name: Set new versions @@ -56,7 +65,9 @@ jobs: sed -i -e "/DAPPMANAGER_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.dappmanager }}"/" .dappnode_profile sed -i -e "/WIFI_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.wifi }}"/" .dappnode_profile sed -i -e "/WIREGUARD_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.wireguard }}"/" .dappnode_profile - sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/"${{ github.event.inputs.https }}"/" .dappnode_profile + sed -i -e "/HTTPS_VERSION/s/[0-9]*\.[0-9]*\.[0-9]*/${{ github.event.inputs.https }}/" .dappnode_profile + sed -i -e "s|^export NOTIFICATIONS_VERSION=.*|export NOTIFICATIONS_VERSION=\"${{ github.event.inputs.notifications }}\"|" .dappnode_profile + sed -i -e "s|^export PREMIUM_VERSION=.*|export PREMIUM_VERSION=\"${{ github.event.inputs.premium }}\"|" .dappnode_profile cat .dappnode_profile - name: Create dappnode_profile.sh run: cp .dappnode_profile dappnode_profile.sh @@ -76,6 +87,8 @@ jobs: echo "wireguard=${{ github.event.inputs.wireguard }}" >> $GITHUB_OUTPUT echo "https=${{ github.event.inputs.https }}" >> $GITHUB_OUTPUT echo "vpn=${{ github.event.inputs.vpn }}" >> $GITHUB_OUTPUT + echo "notifications=${{ github.event.inputs.notifications }}" >> $GITHUB_OUTPUT + echo "premium=${{ github.event.inputs.premium }}" >> $GITHUB_OUTPUT build-debian-attended: name: Build Debian attended ISO diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7c85e1b..deb5465a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: sudo /bin/bash ./scripts/dappnode_install_pre.sh UPDATE - name: Install DAppNode run: | - sudo /bin/bash ./scripts/dappnode_install.sh + sudo /bin/bash ./scripts/dappnode_install.sh --local-profile-path "$PWD/.dappnode_profile" - name: Show installation logs run: | cat /usr/src/dappnode/logs/install.log @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 # Create Debian ISO - name: create Debian ISO diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index fc58ff17..0f6e4ab0 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -1,69 +1,540 @@ #!/bin/bash +# This installer is written for bash. It's safe to *run it from zsh* (it will execute via bash +# thanks to the shebang), but users sometimes invoke it as `zsh ./script.sh` or `source ./script.sh`. +# - If sourced, bail out (sourcing would pollute the current shell and can break it). +# - If invoked by a non-bash shell, re-exec with bash before hitting bash-specific builtins. +if (return 0 2>/dev/null); then + echo "This script must be executed, not sourced. Run: bash $0" + return 1 +fi + +if [ -z "${BASH_VERSION:-}" ]; then + exec /usr/bin/env bash "$0" "$@" +fi + +set -Eeuo pipefail + +# Optional env inputs (avoid unbound-variable errors under `set -u`) +: "${UPDATE:=false}" +: "${STATIC_IP:=}" +: "${LOCAL_PROFILE_PATH:=}" +: "${MINIMAL:=false}" +: "${LITE:=false}" +: "${PACKAGES:=}" + +# Enable alias expansion in non-interactive bash scripts. +# Required so commands like `dappnode_wireguard` (defined as aliases in `.dappnode_profile`) work. +shopt -s expand_aliases + +# Ensure array is always defined (avoid `set -u` edge cases) +DNCORE_COMPOSE_ARGS=() + +############################## +# Logging / Errors # +############################## + +log() { + # LOGFILE is created after dir bootstrap; until then we just print to stdout. + if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then + printf '%s\n' "$*" | tee -a "$LOGFILE" + else + printf '%s\n' "$*" + fi +} + +warn() { + log "[WARN] $*" +} + +die() { + log "[ERROR] $*" + exit 1 +} + +usage() { + cat <<'EOF' +Usage: dappnode_install.sh [options] + +Options: + --update Clean existing downloaded artifacts before installing (equivalent: UPDATE=true) + --static-ip Set a static IP (equivalent: STATIC_IP=...) + --local-profile-path Use a local .dappnode_profile instead of downloading (equivalent: LOCAL_PROFILE_PATH=...) + --ipfs-endpoint Override IPFS gateway endpoint (equivalent: IPFS_ENDPOINT=...) + --profile-url Override profile download URL (equivalent: PROFILE_URL=...) + --minimal Install only BIND DAPPMANAGER NOTIFICATIONS PREMIUM (equivalent: MINIMAL=true) + --lite Install reduced package set: BIND VPN WIREGUARD DAPPMANAGER NOTIFICATIONS PREMIUM (equivalent: LITE=true) + --packages Override package selection (comma or space separated), e.g. BIND,IPFS,VPN + -h, --help Show this help + +Environment variables (also supported): + UPDATE, STATIC_IP, LOCAL_PROFILE_PATH, IPFS_ENDPOINT, PROFILE_URL, MINIMAL, LITE, PACKAGES +EOF +} + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --update) + UPDATE=true + shift + ;; + --static-ip) + [[ $# -ge 2 ]] || die "--static-ip requires an IPv4 argument" + STATIC_IP="$2" + shift 2 + ;; + --local-profile-path) + [[ $# -ge 2 ]] || die "--local-profile-path requires a path argument" + LOCAL_PROFILE_PATH="$2" + shift 2 + ;; + --ipfs-endpoint) + [[ $# -ge 2 ]] || die "--ipfs-endpoint requires a URL argument" + IPFS_ENDPOINT="$2" + shift 2 + ;; + --profile-url) + [[ $# -ge 2 ]] || die "--profile-url requires a URL argument" + PROFILE_URL="$2" + shift 2 + ;; + --minimal) + MINIMAL=true + shift + ;; + --lite) + LITE=true + shift + ;; + --packages) + [[ $# -ge 2 ]] || die "--packages requires a package list argument" + PACKAGES="$2" + shift 2 + ;; + --packages=*) + PACKAGES="${1#*=}" + shift + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + break + ;; + *) + die "Unknown option: $1 (use --help)" + ;; + esac + done +} + +validate_install_mode() { + if [[ "${MINIMAL}" == "true" && "${LITE}" == "true" ]]; then + die "--minimal and --lite are mutually exclusive" + fi +} + +require_cmd() { + local cmd="$1" + command -v "$cmd" >/dev/null 2>&1 || die "Missing required command: $cmd" +} + +require_downloader() { + if command -v curl >/dev/null 2>&1; then + return 0 + fi + if command -v wget >/dev/null 2>&1; then + return 0 + fi + die "Missing required downloader: install curl or wget" +} + +check_prereqs() { + if ! command -v docker >/dev/null 2>&1; then + die "Docker is not installed. Install Docker first, then re-run this installer." + fi + + # Docker CLI may exist while the daemon is stopped/unreachable. + if ! docker info >/dev/null 2>&1; then + die "Docker is installed but not running (or not reachable). Start Docker and try again." + fi + + require_downloader + + # Ensure compose is available (Docker Desktop / modern docker engine) + if ! docker compose version >/dev/null 2>&1; then + die "Docker Compose not available (expected: 'docker compose'). Update Docker or install the compose plugin." + fi +} + +# Wait until dappmanager publishes INTERNAL_IP via its local HTTP endpoint. +# Runs the curl inside the provided container and exits with error on timeout. +# Usage: wait_for_internal_ip [timeout_seconds] [initial_sleep_seconds] +wait_for_internal_ip() { + local container_name="$1" + local timeout_seconds="${2:-120}" + local initial_sleep_seconds="${3:-10}" + local internal_ip_url="http://127.0.0.1/global-envs/INTERNAL_IP" + local hostname_url="http://127.0.0.1/global-envs/HOSTNAME" + + echo "Waiting for dappmanager to publish INTERNAL_IP and HOSTNAME..." + sleep "$initial_sleep_seconds" + + local start_seconds internal_http_code internal_value internal_result + local hostname_http_code hostname_value hostname_result + start_seconds=$SECONDS + internal_http_code="" + internal_value="" + hostname_http_code="" + hostname_value="" + + while true; do + if (( SECONDS - start_seconds >= timeout_seconds )); then + die "Timed out after ${timeout_seconds}s waiting for INTERNAL_IP and HOSTNAME from dappmanager (expected HTTP 200 with non-empty values). Last seen: INTERNAL_IP code=${internal_http_code:-?} value=${internal_value:-}; HOSTNAME code=${hostname_http_code:-?} value=${hostname_value:-}" + fi + + # Must be executed inside the dappmanager container. + # Return format is: + # \n + # Parse in bash (not inside container sh) to avoid shell portability issues. + + internal_result="$( + docker exec -i "$container_name" sh -lc "curl -sS -w '\n%{http_code}' '$internal_ip_url' 2>/dev/null || true" 2>/dev/null || true + )" + internal_http_code="$(printf '%s\n' "$internal_result" | tail -n 1 | tr -d '\r')" + internal_value="$(printf '%s\n' "$internal_result" | head -n 1 | tr -d '\r' | xargs)" + + hostname_result="$( + docker exec -i "$container_name" sh -lc "curl -sS -w '\n%{http_code}' '$hostname_url' 2>/dev/null || true" 2>/dev/null || true + )" + hostname_http_code="$(printf '%s\n' "$hostname_result" | tail -n 1 | tr -d '\r')" + hostname_value="$(printf '%s\n' "$hostname_result" | head -n 1 | tr -d '\r' | xargs)" + + if [[ "$internal_http_code" == "200" && -n "$internal_value" && "$internal_value" != "null" && "$hostname_http_code" == "200" && -n "$hostname_value" && "$hostname_value" != "null" ]]; then + sleep 2 # Extra buffer to ensure values are fully propagated before we proceed + echo "INTERNAL_IP is ready: $internal_value" + echo "HOSTNAME is ready: $hostname_value" + return 0 + fi + + echo "INTERNAL_IP/HOSTNAME not ready yet (INTERNAL_IP code=${internal_http_code:-?}, HOSTNAME code=${hostname_http_code:-?}). Retrying..." + sleep 2 + done +} + +# Print VPN access credentials (Wireguard + OpenVPN) after core has started. +# Works on both Linux and macOS as long as the relevant containers are running. +print_vpn_access_credentials() { + local localhost_flag=() + local has_wireguard=false + local has_vpn=false + local pkg + + if $IS_MACOS; then + localhost_flag=(--localhost) + fi + + for pkg in "${PKGS[@]}"; do + if [[ "$pkg" == "WIREGUARD" ]]; then + has_wireguard=true + elif [[ "$pkg" == "VPN" ]]; then + has_vpn=true + fi + done + + if [[ "$has_wireguard" != "true" && "$has_vpn" != "true" ]]; then + echo "" + echo "No VPN package selected (VPN/WIREGUARD). Skipping credentials output." + return 0 + fi + + echo "" + echo "Waiting for VPN initialization..." + wait_for_internal_ip "DAppNodeCore-dappmanager.dnp.dappnode.eth" 120 20 + + echo "" + echo "##############################################" + echo "# DAppNode VPN Access Credentials #" + echo "##############################################" + echo "" + echo "Your DAppNode is ready! Connect using your preferred VPN client." + echo "Choose either Wireguard (recommended) or OpenVPN and import the" + echo "credentials below into your VPN app to access your DAppNode." + echo "" + + if [[ "$has_wireguard" == "true" ]]; then + echo "--- Wireguard ---" + docker exec -i DAppNodeCore-api.wireguard.dnp.dappnode.eth getWireguardCredentials "${localhost_flag[@]}" 2>&1 || \ + echo "Wireguard credentials not yet available. Try later with: dappnode_wireguard${localhost_flag:+ ${localhost_flag[*]}}" + fi + + if [[ "$has_wireguard" == "true" && "$has_vpn" == "true" ]]; then + echo "" + fi + + if [[ "$has_vpn" == "true" ]]; then + echo "--- OpenVPN ---" + docker exec -i DAppNodeCore-vpn.dnp.dappnode.eth vpncli get dappnode_admin "${localhost_flag[@]}" 2>&1 || \ + echo "OpenVPN credentials not yet available. Try later with: dappnode_openvpn_get dappnode_admin${localhost_flag:+ ${localhost_flag[*]}}" + fi + + echo "" + echo "Import the configuration above into your VPN client of choice to access your DAppNode at http://my.dappnode" +} + +# Build docker compose "-f " args from downloaded compose files. +# This avoids depending on alias expansion or profile-generated strings. +build_dncore_compose_args() { + DNCORE_COMPOSE_ARGS=() + local file + while IFS= read -r file; do + [[ -n "$file" ]] || continue + DNCORE_COMPOSE_ARGS+=( -f "$file" ) + done < <(find "${DAPPNODE_CORE_DIR}" -name 'docker-compose-*.yml' -print 2>/dev/null | sort) +} + +################## +# OS DETECTION # +################## +OS_TYPE="$(uname -s)" +IS_MACOS=false +IS_LINUX=false +if [[ "$OS_TYPE" == "Darwin" ]]; then + IS_MACOS=true +elif [[ "$OS_TYPE" == "Linux" ]]; then + IS_LINUX=true +else + die "Unsupported operating system: $OS_TYPE" +fi + ############# # VARIABLES # ############# -# Dirs -DAPPNODE_DIR="/usr/src/dappnode" +# Dirs - macOS uses $HOME/dappnode, Linux uses /usr/src/dappnode +if $IS_MACOS; then + DAPPNODE_DIR="$HOME/dappnode" +else + DAPPNODE_DIR="/usr/src/dappnode" +fi DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" LOGS_DIR="$DAPPNODE_DIR/logs" # Files CONTENT_HASH_FILE="${DAPPNODE_CORE_DIR}/packages-content-hash.csv" LOGFILE="${LOGS_DIR}/dappnode_install.log" -MOTD_FILE="/etc/motd" -UPDATE_MOTD_DIR="/etc/update-motd.d" DAPPNODE_PROFILE="${DAPPNODE_CORE_DIR}/.dappnode_profile" +# Linux-only paths +if $IS_LINUX; then + MOTD_FILE="/etc/motd" + UPDATE_MOTD_DIR="/etc/update-motd.d" +fi # Get URLs -PROFILE_BRANCH=${PROFILE_BRANCH:-"master"} -IPFS_ENDPOINT=${IPFS_ENDPOINT:-"http://ipfs.io"} +IPFS_ENDPOINT=${IPFS_ENDPOINT:-"https://ipfs-gateway-dev.dappnode.net"} # PROFILE_URL env is used to fetch the core packages versions that will be used to build the release in script install method PROFILE_URL=${PROFILE_URL:-"https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_profile.sh"} DAPPNODE_ACCESS_CREDENTIALS="${DAPPNODE_DIR}/scripts/dappnode_access_credentials.sh" DAPPNODE_ACCESS_CREDENTIALS_URL="https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_access_credentials.sh" -WGET="wget -q --show-progress --progress=bar:force" -SWGET="wget -q -O-" # Other -CONTENT_HASH_PKGS=(geth besu nethermind erigon prysm teku lighthouse nimbus lodestar) -ARCH=$(dpkg --print-architecture) -WELCOME_MESSAGE="\nChoose a way to connect to your DAppNode, then go to \e[1mhttp://my.dappnode\e[0m\n\n\e[1m- Wifi\e[0m\t\tScan and connect to DAppNodeWIFI. Get wifi credentials with \e[32mdappnode_wifi\e[0m\n\n\e[1m- Local Proxy\e[0m\tConnect to the same router as your DAppNode. Then go to \e[1mhttp://dappnode.local\e[0m\n\n\e[1m- Wireguard\e[0m\tDownload Wireguard app on your device. Get your dappnode wireguard credentials with \e[32mdappnode_wireguard\e[0m\n\n\e[1m- Open VPN\e[0m\tDownload OPen VPN app on your device. Get your openVPN creds with \e[32mdappnode_openvpn\e[0m\n\n\nTo see a full list of commands available execute \e[32mdappnode_help\e[0m\n" - -# Clean if update -if [ "$UPDATE" = true ]; then - echo "Cleaning for update..." - rm -rf $LOGFILE - rm -rf ${DAPPNODE_CORE_DIR}/docker-compose-*.yml - rm -rf ${DAPPNODE_CORE_DIR}/dappnode_package-*.json - rm -rf ${DAPPNODE_CORE_DIR}/*.tar.xz - rm -rf ${DAPPNODE_CORE_DIR}/*.txz - rm -rf ${DAPPNODE_CORE_DIR}/.dappnode_profile - rm -rf ${CONTENT_HASH_FILE} + +# Architecture detection (cross-platform) +if $IS_MACOS; then + ARCH="$(uname -m)" + [[ "$ARCH" == "x86_64" ]] && ARCH="amd64" + # arm64 is already correct for Apple Silicon +else + ARCH="$(dpkg --print-architecture)" fi -# Create necessary directories -mkdir -p $DAPPNODE_DIR -mkdir -p $DAPPNODE_CORE_DIR -mkdir -p "${DAPPNODE_DIR}/scripts" -mkdir -p "${DAPPNODE_CORE_DIR}/scripts" -mkdir -p "${DAPPNODE_DIR}/config" -mkdir -p $LOGS_DIR - -# TEMPORARY: think a way to integrate flags instead of use files to detect installation type -is_iso_install() { - # Check old and new location of iso_install.log - if [ -f "${DAPPNODE_DIR}/iso_install.log" ] || [ -f "${DAPPNODE_DIR}/logs/iso_install.log" ]; then - IS_ISO_INSTALL=true +############################## +# Cross-platform Helpers # +############################## + +# Download a file: download_file +download_file() { + local dest="$1" + local url="$2" + log "Downloading from $url to $dest" + mkdir -p "$(dirname "$dest")" + if command -v curl >/dev/null 2>&1; then + curl -fsSL -o "$dest" "$url" + return + fi + wget -q --show-progress --progress=bar:force -O "$dest" "$url" +} + +# Download content to stdout: download_stdout +download_stdout() { + local url="$1" + if command -v curl >/dev/null 2>&1; then + curl -fsSL "$url" + return + fi + wget -q -O- "$url" +} + +# Normalize IPFS refs and (if needed) infer the missing : from dappnode_package.json +# Accepts: +# - /ipfs/: +# - /ipfs/ (version inferred) +# - ipfs/[:] (leading slash normalized) +normalize_ipfs_version_ref() { + local raw_ref="$1" + local comp="$2" + local ref="$raw_ref" + + if [[ "$ref" == ipfs/* ]]; then + ref="/$ref" + fi + + # If it already has :, we're done + if [[ "$ref" == /ipfs/*:* ]]; then + echo "$ref" + return 0 + fi + + # If it's an IPFS ref without a :, infer it from the manifest in the CID + if [[ "$ref" == /ipfs/* ]]; then + local cid_path="$ref" + local manifest_url="${IPFS_ENDPOINT%/}${cid_path}/dappnode_package.json" + local manifest + manifest="$(download_stdout "$manifest_url" 2>/dev/null || true)" + if [[ -z "$manifest" ]]; then + echo "[ERROR] Could not fetch IPFS manifest for ${comp} from: $manifest_url" 1>&2 + echo "[ERROR] Provide ${comp}_VERSION as /ipfs/: (example: /ipfs/Qm...:0.2.11)" 1>&2 + return 1 + fi + + local inferred_version + inferred_version="$( + echo "$manifest" | + tr -d '\r' | + grep -m1 '"version"' | + sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^\"]+)".*/\1/' + )" + + if [[ -z "$inferred_version" || "$inferred_version" == "$manifest" ]]; then + echo "[ERROR] Could not infer version for ${comp} from IPFS manifest: $manifest_url" 1>&2 + echo "[ERROR] Provide ${comp}_VERSION as /ipfs/:" 1>&2 + return 1 + fi + + echo "${cid_path}:${inferred_version}" + return 0 + fi + + # Not an IPFS ref; return as-is + echo "$raw_ref" +} + +# Cross-platform in-place sed (macOS requires '' after -i) +sed_inplace() { + if $IS_MACOS; then + sed -i '' "$@" else - IS_ISO_INSTALL=false + sed -i "$@" fi } +############################## +# Compose Patching Helpers # +############################## + +# Remove journald logging from compose files (not supported on macOS Docker Desktop) +remove_logging_section() { + local file="$1" + sed_inplace '/logging/d;/journald/d' "$file" +} + +# Replace Linux paths with macOS paths in compose files +patch_compose_paths() { + local file="$1" + sed_inplace "s|/usr/src/dappnode|${DAPPNODE_DIR}|g" "$file" +} + +# Patch dappmanager compose for macOS: inject env vars the container needs +# to know the host core-dir path and to skip host-only operations, +# and fix the DNCORE volume mount to use the macOS host path. +patch_dappmanager_compose_for_macos() { + local file="$1" + + # Replace the host side of the DNCORE volume mount with the actual DAPPNODE_CORE_DIR value + # e.g. /usr/src/dappnode/DNCORE/:/usr/src/app/DNCORE/ -> $HOME/dappnode/DNCORE/:/usr/src/app/DNCORE/ + sed_inplace "s|[^[:space:]]*:/usr/src/app/DNCORE/|${DAPPNODE_CORE_DIR}/:/usr/src/app/DNCORE/|" "$file" + + local envs_to_add=() + + # DAPPNODE_CORE_DIR: lets the container know the host's DNCORE path + if ! grep -q "DAPPNODE_CORE_DIR" "$file"; then + envs_to_add+=(" - DAPPNODE_CORE_DIR=${DAPPNODE_CORE_DIR}") + fi + + # DISABLE_HOST_SCRIPTS: tells the container to skip host-only scripts + if ! grep -q "DISABLE_HOST_SCRIPTS" "$file"; then + envs_to_add+=(" - DISABLE_HOST_SCRIPTS=${DISABLE_HOST_SCRIPTS}") + fi + + [[ ${#envs_to_add[@]} -gt 0 ]] || return 0 + + local tmp="${file}.tmp" + local insert_file="${file}.envinsert" + + # macOS ships BSD awk, which can error with "newline in string" if a -v argument contains + # literal newlines. Write the insertion block to a temp file and have awk read it. + printf '%s\n' "${envs_to_add[@]}" >"$insert_file" + + awk -v insfile="$insert_file" ' + /^[[:space:]]*environment:[[:space:]]*$/ { + print + while ((getline line < insfile) > 0) print line + close(insfile) + next + } + { print } + ' "$file" >"$tmp" && mv "$tmp" "$file" + + rm -f "$insert_file" || true +} + +bootstrap_filesystem() { + # Clean if update + if [[ "${UPDATE}" == "true" ]]; then + echo "Cleaning for update..." + rm -f "${LOGFILE}" || true + rm -f "${DAPPNODE_CORE_DIR}"/docker-compose-*.yml || true + rm -f "${DAPPNODE_CORE_DIR}"/dappnode_package-*.json || true + rm -f "${DAPPNODE_CORE_DIR}"/*.tar.xz || true + rm -f "${DAPPNODE_CORE_DIR}"/*.txz || true + rm -f "${DAPPNODE_CORE_DIR}/.dappnode_profile" || true + rm -f "${CONTENT_HASH_FILE}" || true + fi + + # Create necessary directories + mkdir -p "${DAPPNODE_DIR}" + mkdir -p "${DAPPNODE_CORE_DIR}" + mkdir -p "${DAPPNODE_DIR}/scripts" + mkdir -p "${DAPPNODE_CORE_DIR}/scripts" + mkdir -p "${DAPPNODE_DIR}/config" + mkdir -p "${LOGS_DIR}" + + # Ensure the log file path exists before first use by helpers. + touch "${LOGFILE}" || true +} + # Check if port 80 is in use (necessary for HTTPS) # Returns IS_PORT_USED=true only if port 80 or 443 is used by something OTHER than our HTTPS container is_port_used() { # Check if port 80 or 443 is in use at all local port80_used port443_used - lsof -i -P -n | grep ":80 (LISTEN)" &>/dev/null && port80_used=true || port80_used=false - lsof -i -P -n | grep ":443 (LISTEN)" &>/dev/null && port443_used=true || port443_used=false + if command -v lsof >/dev/null 2>&1; then + lsof -i -P -n | grep ":80 (LISTEN)" &>/dev/null && port80_used=true || port80_used=false + lsof -i -P -n | grep ":443 (LISTEN)" &>/dev/null && port443_used=true || port443_used=false + else + warn "lsof not found; assuming ports 80/443 are in use (HTTPS will be skipped)" + IS_PORT_USED=true + return + fi if [ "$port80_used" = false ] && [ "$port443_used" = false ]; then IS_PORT_USED=false @@ -82,98 +553,221 @@ is_port_used() { # Determine packages to be installed determine_packages() { - is_iso_install - is_port_used - if [ "$IS_ISO_INSTALL" == "false" ]; then - if [ "$IS_PORT_USED" == "true" ]; then - PKGS=(BIND IPFS VPN WIREGUARD DAPPMANAGER WIFI) - else - PKGS=(HTTPS BIND IPFS WIREGUARD DAPPMANAGER WIFI) + # Explicit package list override from flag/env always has top priority. + # It supersedes MINIMAL/LITE and any OS/port-based package determination. + if [[ -n "${PACKAGES//[[:space:],]/}" ]]; then + local raw token normalized + local custom_pkgs=() + + raw="${PACKAGES//,/ }" + for token in $raw; do + normalized="$(echo "$token" | tr '[:lower:]' '[:upper:]')" + case "$normalized" in + HTTPS|BIND|IPFS|VPN|WIREGUARD|DAPPMANAGER|WIFI|NOTIFICATIONS|PREMIUM) + ;; + *) + die "Unknown package in --packages/PACKAGES: '$token'. Allowed: HTTPS,BIND,IPFS,VPN,WIREGUARD,DAPPMANAGER,WIFI,NOTIFICATIONS,PREMIUM" + ;; + esac + + local exists=false + local pkg + for pkg in "${custom_pkgs[@]}"; do + if [[ "$pkg" == "$normalized" ]]; then + exists=true + break + fi + done + + if [[ "$exists" == "false" ]]; then + custom_pkgs+=("$normalized") + fi + done + + [[ ${#custom_pkgs[@]} -gt 0 ]] || die "--packages/PACKAGES was provided but no valid packages were found" + + # DAPPMANAGER is required for a functional install; ensure it's present on explicit overrides. + local has_dappmanager=false + local pkg + for pkg in "${custom_pkgs[@]}"; do + if [[ "$pkg" == "DAPPMANAGER" ]]; then + has_dappmanager=true + break + fi + done + if [[ "$has_dappmanager" == "false" ]]; then + custom_pkgs+=("DAPPMANAGER") + log "--packages/PACKAGES did not include DAPPMANAGER; appending it automatically" fi - else - if [ "$IS_PORT_USED" == "true" ]; then - PKGS=(BIND IPFS WIREGUARD DAPPMANAGER WIFI) - else - PKGS=(HTTPS BIND IPFS WIREGUARD DAPPMANAGER WIFI) + + if [[ "${MINIMAL}" == "true" || "${LITE}" == "true" ]]; then + log "Custom packages provided; overriding --minimal/--lite and MINIMAL/LITE" fi + MINIMAL=false + LITE=false + PKGS=("${custom_pkgs[@]}") + + log "Packages override enabled via --packages/PACKAGES" + log "Packages to be installed: ${PKGS[*]}" + log "PKGS: ${PKGS[*]}" + for comp in "${PKGS[@]}"; do + local ver_var + ver_var="${comp}_VERSION" + log "$ver_var = ${!ver_var-}" + done + return 0 fi - echo -e "\e[32mPackages to be installed: ${PKGS[*]}\e[0m" 2>&1 | tee -a $LOGFILE -} -function valid_ip() { - local ip=$1 - local stat=1 + # Global override: new minimal install, regardless of OS. + if [[ "${MINIMAL}" == "true" ]]; then + PKGS=(BIND DAPPMANAGER NOTIFICATIONS PREMIUM) + log "Minimal mode enabled; overriding packages" + log "Packages to be installed: ${PKGS[*]}" + log "PKGS: ${PKGS[*]}" + for comp in "${PKGS[@]}"; do + local ver_var + ver_var="${comp}_VERSION" + log "$ver_var = ${!ver_var-}" + done + return 0 + fi - if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - OIFS=$IFS - IFS='.' - ip=("$ip") - IFS=$OIFS - [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && - ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] - stat=$? + # Global override: lite install (former minimal behavior), regardless of OS. + if [[ "${LITE}" == "true" ]]; then + PKGS=(BIND VPN WIREGUARD DAPPMANAGER NOTIFICATIONS PREMIUM) + log "Lite mode enabled; overriding packages" + log "Packages to be installed: ${PKGS[*]}" + log "PKGS: ${PKGS[*]}" + for comp in "${PKGS[@]}"; do + local ver_var + ver_var="${comp}_VERSION" + log "$ver_var = ${!ver_var-}" + done + return 0 fi - return $stat + + # Default mode (no --packages/--minimal/--lite): install full package set. + # HTTPS is included only when ports 80/443 are available. + is_port_used + if [ "$IS_PORT_USED" == "true" ]; then + PKGS=(BIND IPFS VPN WIREGUARD DAPPMANAGER WIFI NOTIFICATIONS PREMIUM) + else + PKGS=(HTTPS BIND IPFS VPN WIREGUARD DAPPMANAGER WIFI NOTIFICATIONS PREMIUM) + fi + + log "Packages to be installed: ${PKGS[*]}" + + # Debug: print all PKGS and their version variables + log "PKGS: ${PKGS[*]}" + for comp in "${PKGS[@]}"; do + local ver_var + ver_var="${comp}_VERSION" + log "$ver_var = ${!ver_var-}" + done } -if [[ -n "$STATIC_IP" ]]; then +valid_ip() { + local ip="$1" + if [[ ! "$ip" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then + return 1 + fi + + local IFS='.' + # shellcheck disable=SC2206 + local octets=( $ip ) + [[ ${#octets[@]} -eq 4 ]] || return 1 + [[ ${octets[0]} -le 255 && ${octets[1]} -le 255 && ${octets[2]} -le 255 && ${octets[3]} -le 255 ]] +} + +configure_static_ip() { + if [[ -z "${STATIC_IP}" ]]; then + return 0 + fi + if valid_ip "$STATIC_IP"; then - echo "$STATIC_IP" >${DAPPNODE_DIR}/config/static_ip + echo "$STATIC_IP" >"${DAPPNODE_DIR}/config/static_ip" else - echo "The static IP provided: ${STATIC_IP} is not valid." - exit 1 + die "The static IP provided (${STATIC_IP}) is not valid." fi -fi +} -# Loads profile, if not exists it means it is script install so the versions will be fetched from the latest profile -[ -f $DAPPNODE_PROFILE ] || ${WGET} -O ${DAPPNODE_PROFILE} ${PROFILE_URL} -# shellcheck disable=SC1090 -source "${DAPPNODE_PROFILE}" - -# The indirect variable expansion used in ${!ver##*:} allows us to use versions like 'dev:development' -# If such variable with 'dev:'' suffix is used, then the component is built from specified branch or commit. -# you can also specify an IPFS version like /ipfs/QmWg8P2b9JKQ8thAVz49J8SbJbCoi2MwkHnUqMtpzDTtxR:0.2.7, it's important -# to include the exact version also in the IPFS hash format since it's needed to be able to download it -determine_packages -for comp in "${PKGS[@]}"; do - ver="${comp}_VERSION" - DOWNLOAD_URL="https://github.com/dappnode/DNP_${comp}/releases/download/v${!ver}" - if [[ ${!ver} == /ipfs/* ]]; then - DOWNLOAD_URL="${IPFS_ENDPOINT}/api/v0/cat?arg=${!ver%:*}" - fi - eval "${comp}_URL=\"${DOWNLOAD_URL}/${comp,,}.dnp.dappnode.eth_${!ver##*:}_linux-${ARCH}.txz\"" - eval "${comp}_YML=\"${DOWNLOAD_URL}/docker-compose.yml\"" - eval "${comp}_MANIFEST=\"${DOWNLOAD_URL}/dappnode_package.json\"" - eval "${comp}_YML_FILE=\"${DAPPNODE_CORE_DIR}/docker-compose-${comp,,}.yml\"" - eval "${comp}_FILE=\"${DAPPNODE_CORE_DIR}/${comp,,}.dnp.dappnode.eth_${!ver##*:}_linux-${ARCH}.txz\"" - eval "${comp}_MANIFEST_FILE=\"${DAPPNODE_CORE_DIR}/dappnode_package-${comp,,}.json\"" -done +ensure_profile_loaded() { + # If LOCAL_PROFILE_PATH is set, use it as the profile source instead of downloading + if [[ -n "${LOCAL_PROFILE_PATH}" ]]; then + log "Using local profile: ${LOCAL_PROFILE_PATH}" + cp "$LOCAL_PROFILE_PATH" "$DAPPNODE_PROFILE" + elif [[ ! -f "$DAPPNODE_PROFILE" ]]; then + download_file "${DAPPNODE_PROFILE}" "${PROFILE_URL}" + fi + + # shellcheck disable=SC1090 + source "${DAPPNODE_PROFILE}" +} + +resolve_packages() { + # The indirect variable expansion used in ${!ver##*:} allows us to use versions like 'dev:development' + # If such variable with 'dev:'' suffix is used, then the component is built from specified branch or commit. + # you can also specify an IPFS version like /ipfs/: (the exact version is required). + determine_packages + for comp in "${PKGS[@]}"; do + ver="${comp}_VERSION" + log "Processing $comp: ${!ver-}" + + raw_version_ref="${!ver-}" + if [[ "$raw_version_ref" == /ipfs/* || "$raw_version_ref" == ipfs/* ]]; then + resolved_ref="$(normalize_ipfs_version_ref "$raw_version_ref" "$comp")" || exit 1 + printf -v "${comp}_VERSION" '%s' "$resolved_ref" + raw_version_ref="$resolved_ref" + log "Using IPFS for ${comp}: ${raw_version_ref%:*} (version ${raw_version_ref##*:})" + DOWNLOAD_URL="${IPFS_ENDPOINT%/}${raw_version_ref%:*}" + version_for_filenames="${raw_version_ref##*:}" + else + version_for_filenames="${raw_version_ref##*:}" + DOWNLOAD_URL="https://github.com/dappnode/DNP_${comp}/releases/download/v${version_for_filenames}" + fi + comp_lower="$(echo "$comp" | tr '[:upper:]' '[:lower:]')" + printf -v "${comp}_URL" '%s' "${DOWNLOAD_URL}/${comp_lower}.dnp.dappnode.eth_${version_for_filenames}_linux-${ARCH}.txz" + printf -v "${comp}_YML" '%s' "${DOWNLOAD_URL}/docker-compose.yml" + printf -v "${comp}_MANIFEST" '%s' "${DOWNLOAD_URL}/dappnode_package.json" + printf -v "${comp}_YML_FILE" '%s' "${DAPPNODE_CORE_DIR}/docker-compose-${comp_lower}.yml" + printf -v "${comp}_FILE" '%s' "${DAPPNODE_CORE_DIR}/${comp_lower}.dnp.dappnode.eth_${version_for_filenames}_linux-${ARCH}.txz" + printf -v "${comp}_MANIFEST_FILE" '%s' "${DAPPNODE_CORE_DIR}/dappnode_package-${comp_lower}.json" + done +} dappnode_core_build() { for comp in "${PKGS[@]}"; do ver="${comp}_VERSION" if [[ ${!ver} == dev:* ]]; then + if $IS_MACOS; then + echo "Development builds (dev:*) are not supported on macOS." + exit 1 + fi echo "Cloning & building DNP_${comp}..." if ! dpkg -s git >/dev/null 2>&1; then apt-get install -y git fi - TMPDIR=$(mktemp -d) - pushd "$TMPDIR" || { + local tmpdir + tmpdir="$(mktemp -d)" + pushd "$tmpdir" >/dev/null || { echo "Error on pushd" exit 1 } git clone -b "${!ver##*:}" https://github.com/dappnode/DNP_"${comp}" # Change version in YAML to the custom one - DOCKER_VER=$(echo "${!ver##*:}" | sed 's/\//_/g') - sed -i "s~^\(\s*image\s*:\s*\).*~\1${comp,,}.dnp.dappnode.eth:${DOCKER_VER}~" DNP_"${comp}"/docker-compose.yml + local docker_ver comp_lower + docker_ver="$(echo "${!ver##*:}" | sed 's/\//_/g')" + comp_lower="$(echo "$comp" | tr '[:upper:]' '[:lower:]')" + sed_inplace "s~^\(\s*image\s*:\s*\).*~\1${comp_lower}.dnp.dappnode.eth:${docker_ver}~" "DNP_${comp}/docker-compose.yml" docker compose -f ./DNP_"${comp}"/docker-compose.yml build - cp ./DNP_"${comp}"/docker-compose.yml "${DAPPNODE_CORE_DIR}"/docker-compose-"${comp,,}".yml - cp ./DNP_"${comp}"/dappnode_package.json "${DAPPNODE_CORE_DIR}"/dappnode_package-"${comp,,}".json - rm -r ./DNP_"${comp}" - popd || { + cp "./DNP_${comp}/docker-compose.yml" "${DAPPNODE_CORE_DIR}/docker-compose-${comp_lower}.yml" + cp "./DNP_${comp}/dappnode_package.json" "${DAPPNODE_CORE_DIR}/dappnode_package-${comp_lower}.json" + rm -rf "./DNP_${comp}" + popd >/dev/null || { echo "Error on popd" exit 1 } + rm -rf "$tmpdir" fi done } @@ -182,15 +776,32 @@ dappnode_core_download() { for comp in "${PKGS[@]}"; do ver="${comp}_VERSION" if [[ ${!ver} != dev:* ]]; then - # Download DAppNode Core Images if it's needed + local file_var="${comp}_FILE" + local url_var="${comp}_URL" + local yml_file_var="${comp}_YML_FILE" + local yml_var="${comp}_YML" + local manifest_file_var="${comp}_MANIFEST_FILE" + local manifest_var="${comp}_MANIFEST" + + # Download DAppNode Core Images if needed echo "Downloading ${comp} tar..." - eval "[ -f \$${comp}_FILE ] || $WGET -O \$${comp}_FILE \$${comp}_URL || exit 1" - # Download DAppNode Core docker-compose yml files if it's needed + [ -f "${!file_var}" ] || download_file "${!file_var}" "${!url_var}" || exit 1 + # Download DAppNode Core docker-compose yml files if needed echo "Downloading ${comp} yml..." - eval "[ -f \$${comp}_YML_FILE ] || $WGET -O \$${comp}_YML_FILE \$${comp}_YML || exit 1" - # Download DAppNode Core manifest files if it's needed + [ -f "${!yml_file_var}" ] || download_file "${!yml_file_var}" "${!yml_var}" || exit 1 + # Download DAppNode Core manifest files if needed echo "Downloading ${comp} manifest..." - eval "[ -f \$${comp}_MANIFEST_FILE ] || $WGET -O \$${comp}_MANIFEST_FILE \$${comp}_MANIFEST || exit 1" + [ -f "${!manifest_file_var}" ] || download_file "${!manifest_file_var}" "${!manifest_var}" || exit 1 + + # macOS: patch compose files for Docker Desktop compatibility + if $IS_MACOS; then + remove_logging_section "${!yml_file_var}" + patch_compose_paths "${!yml_file_var}" + # Inject macOS-specific env vars into the dappmanager compose + if [[ "$comp" == "DAPPMANAGER" ]]; then + patch_dappmanager_compose_for_macos "${!yml_file_var}" + fi + fi fi done } @@ -199,13 +810,18 @@ dappnode_core_load() { for comp in "${PKGS[@]}"; do ver="${comp}_VERSION" if [[ ${!ver} != dev:* ]]; then - eval "[ ! -z \$(docker images -q ${comp,,}.dnp.dappnode.eth:${!ver##*:}) ] || docker load -i \$${comp}_FILE 2>&1 | tee -a \$LOGFILE" + local comp_lower image file_var + comp_lower="$(echo "$comp" | tr '[:upper:]' '[:lower:]')" + image="${comp_lower}.dnp.dappnode.eth:${!ver##*:}" + file_var="${comp}_FILE" + if [[ -z "$(docker images -q "$image" 2>/dev/null)" ]]; then + docker load -i "${!file_var}" 2>&1 | tee -a "$LOGFILE" + fi fi done } customMotd() { - generateMotdText if [ -d "${UPDATE_MOTD_DIR}" ]; then @@ -216,6 +832,8 @@ customMotd() { # Debian distros use /etc/motd plain text file generateMotdText() { + local welcome_message + # Check and create the MOTD file if it does not exist if [ ! -f "${MOTD_FILE}" ]; then touch "${MOTD_FILE}" @@ -229,11 +847,13 @@ generateMotdText() { |___/\__,_| .__/ .__/_||_\___/\__,_\___| |_| |_| EOF - echo -e "$WELCOME_MESSAGE" >>"${MOTD_FILE}" + welcome_message="\nChoose a way to connect to your DAppNode, then go to http://my.dappnode\n\n- Wifi\t\tScan and connect to DAppNodeWIFI. Get wifi credentials with dappnode_wifi\n\n- Local Proxy\tConnect to the same router as your DAppNode. Then go to http://dappnode.local\n\n- Wireguard\tDownload Wireguard app on your device. Get your dappnode wireguard credentials with dappnode_wireguard\n\n- Open VPN\tDownload Open VPN app on your device. Get your openVPN creds with dappnode_openvpn\n\n\nTo see a full list of commands available execute dappnode_help\n" + printf "%b" "$welcome_message" >>"${MOTD_FILE}" } # Ubuntu distros use /etc/update-motd.d/ to generate the motd modifyMotdGeneration() { + local disabled_motd_dir disabled_motd_dir="${UPDATE_MOTD_DIR}/disabled" mkdir -p "${disabled_motd_dir}" @@ -241,8 +861,9 @@ modifyMotdGeneration() { # Move all the files in /etc/update-motd.d/ to /etc/update-motd.d/disabled/ # Except for the files listed in "files_to_keep" files_to_keep="00-header 50-landscape-sysinfo 98-reboot-required" - for file in ${UPDATE_MOTD_DIR}/*; do - base_file=$(basename "${file}") + local file base_file + for file in "${UPDATE_MOTD_DIR}"/*; do + base_file="$(basename "${file}")" if [ -f "${file}" ] && ! echo "${files_to_keep}" | grep -qw "${base_file}"; then mv "${file}" "${disabled_motd_dir}/" fi @@ -255,81 +876,105 @@ addSwap() { # if not then create it if [ "$IS_SWAP" -eq 0 ]; then - echo -e '\e[32mSwap not found. Adding swapfile.\e[0m' + echo 'Swap not found. Adding swapfile.' #RAM=$(awk '/MemTotal/ {print $2}' /proc/meminfo) #SWAP=$(($RAM * 2)) SWAP=8388608 - fallocate -l ${SWAP}k /swapfile + fallocate -l "${SWAP}k" /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap defaults 0 0' >>/etc/fstab else - echo -e '\e[32mSwap found. No changes made.\e[0m' + echo 'Swap found. No changes made.' fi } -dappnode_start() { - echo -e "\e[32mDAppNode starting...\e[0m" 2>&1 | tee -a $LOGFILE - # shellcheck disable=SC1090 - source "${DAPPNODE_PROFILE}" >/dev/null 2>&1 +# Add .dappnode_profile sourcing to the user's default shell configuration +add_profile_to_shell() { + local user_home + local shell_configs - # Execute `compose-up` independently - # To execute `compose-up` against more than 1 compose, composes files must share compose file version (e.g 3.5) - for comp in "${DNCORE_YMLS_ARRAY[@]}"; do - docker compose -f "$comp" up -d 2>&1 | tee -a $LOGFILE - echo "${comp} started" 2>&1 | tee -a $LOGFILE - done - echo -e "\e[32mDAppNode started\e[0m" 2>&1 | tee -a $LOGFILE + if $IS_MACOS; then + user_home="$HOME" + # macOS defaults to zsh, but some users still run bash. + shell_configs=(".zshrc" ".zprofile" ".bashrc" ".bash_profile") + else + # Linux: determine user home from /etc/passwd + local user_name + user_name=$(grep 1000 /etc/passwd | cut -f 1 -d:) + if [ -n "$user_name" ]; then + user_home="/home/$user_name" + else + user_home="/root" + fi + shell_configs=(".profile" ".bashrc") + fi - # Show credentials to the user on login - USER=$(grep 1000 /etc/passwd | cut -f 1 -d:) - [ -n "$USER" ] && USER_HOME=/home/$USER || USER_HOME=/root + for config_file in "${shell_configs[@]}"; do + local config_path="${user_home}/${config_file}" + local source_line + + # .profile may be evaluated by /bin/sh (dash on Debian/Ubuntu) where `source` is not valid. + # Use POSIX '.' there; use `source` elsewhere (bash/zsh). + if [ "$config_file" = ".profile" ]; then + source_line="[ -f \"${DAPPNODE_PROFILE}\" ] && . \"${DAPPNODE_PROFILE}\"" + else + source_line="[ -f \"${DAPPNODE_PROFILE}\" ] && source \"${DAPPNODE_PROFILE}\"" + fi - # Add profile sourcing to both .profile and .bashrc for maximum compatibility - for config_file in .profile .bashrc; do - CONFIG_PATH="$USER_HOME/$config_file" - # Create config file if it doesn't exist - [ ! -f "$CONFIG_PATH" ] && touch "$CONFIG_PATH" - + [ ! -f "$config_path" ] && touch "$config_path" # Add profile sourcing if not already present - if ! grep -q "${DAPPNODE_PROFILE}" "$CONFIG_PATH"; then - echo "######## DAPPNODE PROFILE ########" >>"$CONFIG_PATH" - echo -e "source ${DAPPNODE_PROFILE}\n" >>"$CONFIG_PATH" + if ! grep -q "${DAPPNODE_PROFILE}" "$config_path"; then + echo "######## DAPPNODE PROFILE ########" >> "$config_path" + echo "$source_line" >> "$config_path" + echo "" >> "$config_path" fi done +} + +dappnode_core_start() { + echo "DAppNode starting..." 2>&1 | tee -a "$LOGFILE" + + if [[ ${#DNCORE_COMPOSE_ARGS[@]} -eq 0 ]]; then + build_dncore_compose_args + fi + [[ ${#DNCORE_COMPOSE_ARGS[@]} -gt 0 ]] || die "No docker-compose-*.yml files found in ${DAPPNODE_CORE_DIR}" + + docker compose "${DNCORE_COMPOSE_ARGS[@]}" up -d 2>&1 | tee -a "$LOGFILE" + echo "DAppNode started" 2>&1 | tee -a "$LOGFILE" + + # Add profile sourcing to user's shell configuration + add_profile_to_shell - # Remove return from profile - sed -i '/return/d' $DAPPNODE_PROFILE | tee -a $LOGFILE + # Remove return from profile so it can be sourced in login shells + sed_inplace '/return/d' "$DAPPNODE_PROFILE" # Download access_credentials script - [ -f $DAPPNODE_ACCESS_CREDENTIALS ] || ${WGET} -O ${DAPPNODE_ACCESS_CREDENTIALS} ${DAPPNODE_ACCESS_CREDENTIALS_URL} + [ -f "$DAPPNODE_ACCESS_CREDENTIALS" ] || download_file "${DAPPNODE_ACCESS_CREDENTIALS}" "${DAPPNODE_ACCESS_CREDENTIALS_URL}" - # Delete dappnode_install.sh execution from rc.local if exists, and is not the unattended firstboot - if [ -f "/etc/rc.local" ] && [ ! -f "/usr/src/dappnode/.firstboot" ]; then - sed -i '/\/usr\/src\/dappnode\/scripts\/dappnode_install.sh/d' /etc/rc.local 2>&1 | tee -a $LOGFILE + # Linux-only: clean up rc.local + if $IS_LINUX; then + if [ -f "/etc/rc.local" ] && [ ! -f "${DAPPNODE_DIR}/.firstboot" ]; then + sed_inplace '/\/usr\/src\/dappnode\/scripts\/dappnode_install.sh/d' /etc/rc.local 2>&1 | tee -a "$LOGFILE" + fi fi # Display help message to the user - echo -e "Execute \e[32mdappnode_help\e[0m to see a full list with commands available" -} - -installExtraDpkg() { - if [ -d "/usr/src/dappnode/extra_dpkg" ]; then - dpkg -i /usr/src/dappnode/iso/extra_dpkg/*.deb 2>&1 | tee -a $LOGFILE - fi + echo "Execute dappnode_help to see a full list with commands available" } grabContentHashes() { if [ ! -f "${CONTENT_HASH_FILE}" ]; then - for comp in "${CONTENT_HASH_PKGS[@]}"; do - CONTENT_HASH=$(eval "${SWGET}" https://github.com/dappnode/DAppNodePackage-"${comp}"/releases/latest/download/content-hash) + local content_hash_pkgs=(geth besu nethermind erigon prysm teku lighthouse nimbus lodestar) + for comp in "${content_hash_pkgs[@]}"; do + CONTENT_HASH=$(download_stdout "https://github.com/dappnode/DAppNodePackage-${comp}/releases/latest/download/content-hash") if [ -z "$CONTENT_HASH" ]; then - echo "ERROR! Failed to find content hash of ${comp}." 2>&1 | tee -a $LOGFILE + echo "ERROR! Failed to find content hash of ${comp}." 2>&1 | tee -a "$LOGFILE" exit 1 fi - echo "${comp}.dnp.dappnode.eth,${CONTENT_HASH}" >>${CONTENT_HASH_FILE} + echo "${comp}.dnp.dappnode.eth,${CONTENT_HASH}" >>"${CONTENT_HASH_FILE}" done fi } @@ -338,15 +983,15 @@ grabContentHashes() { installSgx() { if [ -d "/usr/src/dappnode/iso/sgx" ]; then # from sgx_linux_x64_driver_2.5.0_2605efa.bin - /usr/src/dappnode/iso/sgx/sgx_linux_x64_driver.bin 2>&1 | tee -a $LOGFILE - /usr/src/dappnode/iso/sgx/enable_sgx 2>&1 | tee -a $LOGFILE + /usr/src/dappnode/iso/sgx/sgx_linux_x64_driver.bin 2>&1 | tee -a "$LOGFILE" + /usr/src/dappnode/iso/sgx/enable_sgx 2>&1 | tee -a "$LOGFILE" fi } # /extra_dpkg will only be installed on ISO's dappnode not on standalone script installExtraDpkg() { if [ -d "/usr/src/dappnode/iso/extra_dpkg" ]; then - dpkg -i /usr/src/dappnode/extra_dpkg/*.deb 2>&1 | tee -a $LOGFILE + dpkg -i /usr/src/dappnode/iso/extra_dpkg/*.deb 2>&1 | tee -a "$LOGFILE" fi } @@ -354,81 +999,112 @@ installExtraDpkg() { # Explained in: https://docs.docker.com/engine/install/linux-postinstall/ addUserToDockerGroup() { # UID is provided to the first regular user created in the system - USER=$(grep 1000 "/etc/passwd" | cut -f 1 -d:) + local user + user=$(grep 1000 "/etc/passwd" | cut -f 1 -d:) # If USER is not found, warn the user and return - if [ -z "$USER" ]; then - echo -e "\e[33mWARN: Default user not found. Could not add it to the docker group.\e[0m" 2>&1 | tee -a $LOGFILE + if [ -z "$user" ]; then + echo "WARN: Default user not found. Could not add it to the docker group." 2>&1 | tee -a "$LOGFILE" return fi - if groups "$USER" | grep &>/dev/null '\bdocker\b'; then - echo -e "\e[32mUser $USER is already in the docker group\e[0m" 2>&1 | tee -a $LOGFILE + if groups "$user" | grep &>/dev/null '\bdocker\b'; then + echo "User $user is already in the docker group" 2>&1 | tee -a "$LOGFILE" return fi # This step is already done in the dappnode_install_pre.sh script, # but it's not working in the Ubuntu ISO because the late-commands in the autoinstall.yaml # file are executed before the user is created. - usermod -aG docker "$USER" - echo -e "\e[32mUser $USER added to the docker group\e[0m" 2>&1 | tee -a $LOGFILE + usermod -aG docker "$user" + echo "User $user added to the docker group" 2>&1 | tee -a "$LOGFILE" } ############################################## #### SCRIPT START #### ############################################## -echo -e "\e[32m\n##############################################\e[0m" 2>&1 | tee -a $LOGFILE -echo -e "\e[32m#### DAPPNODE INSTALLER ####\e[0m" 2>&1 | tee -a $LOGFILE -echo -e "\e[32m##############################################\e[0m" 2>&1 | tee -a $LOGFILE +main() { + parse_args "$@" + validate_install_mode -echo -e "\e[32mCreating swap memory...\e[0m" 2>&1 | tee -a $LOGFILE -addSwap + bootstrap_filesystem + check_prereqs + configure_static_ip + ensure_profile_loaded + resolve_packages -echo -e "\e[32mCustomizing login...\e[0m" 2>&1 | tee -a $LOGFILE -customMotd + echo "" 2>&1 | tee -a "$LOGFILE" + echo "##############################################" 2>&1 | tee -a "$LOGFILE" + echo "#### DAPPNODE INSTALLER ####" 2>&1 | tee -a "$LOGFILE" + echo "##############################################" 2>&1 | tee -a "$LOGFILE" -echo -e "\e[32mInstalling extra packages...\e[0m" 2>&1 | tee -a $LOGFILE -installExtraDpkg + # --- Linux-only setup steps --- + if $IS_LINUX; then + if [[ "${MINIMAL}" != "true" && "${LITE}" != "true" ]]; then + echo "Creating swap memory..." 2>&1 | tee -a "$LOGFILE" + addSwap -echo -e "\e[32mGrabbing latest content hashes...\e[0m" 2>&1 | tee -a $LOGFILE -grabContentHashes + echo "Customizing login..." 2>&1 | tee -a "$LOGFILE" + customMotd -if [ "$ARCH" == "amd64" ]; then - echo -e "\e[32mInstalling SGX modules...\e[0m" 2>&1 | tee -a $LOGFILE - installSgx + echo "Installing extra packages..." 2>&1 | tee -a "$LOGFILE" + installExtraDpkg - echo -e "\e[32mInstalling extra packages...\e[0m" 2>&1 | tee -a $LOGFILE - installExtraDpkg # TODO: Why is this being called twice? -fi + echo "Grabbing latest content hashes..." 2>&1 | tee -a "$LOGFILE" + grabContentHashes -echo -e "\e[32mAdding user to docker group...\e[0m" 2>&1 | tee -a $LOGFILE -addUserToDockerGroup + if [ "$ARCH" == "amd64" ]; then + echo "Installing SGX modules..." 2>&1 | tee -a "$LOGFILE" + installSgx -echo -e "\e[32mCreating dncore_network if needed...\e[0m" 2>&1 | tee -a $LOGFILE -docker network create --driver bridge --subnet 172.33.0.0/16 dncore_network 2>&1 | tee -a $LOGFILE + echo "Installing extra packages..." 2>&1 | tee -a "$LOGFILE" + installExtraDpkg # TODO: Why is this being called twice? + fi + fi -echo -e "\e[32mBuilding DAppNode Core if needed...\e[0m" 2>&1 | tee -a $LOGFILE -dappnode_core_build + echo "Adding user to docker group..." 2>&1 | tee -a "$LOGFILE" + addUserToDockerGroup + fi -echo -e "\e[32mDownloading DAppNode Core...\e[0m" 2>&1 | tee -a $LOGFILE -dappnode_core_download + # --- Common steps (Linux and macOS) --- + echo "Creating dncore_network if needed..." 2>&1 | tee -a "$LOGFILE" + docker network create --driver bridge --subnet 172.33.0.0/16 dncore_network 2>&1 | tee -a "$LOGFILE" || true -echo -e "\e[32mLoading DAppNode Core...\e[0m" 2>&1 | tee -a $LOGFILE -dappnode_core_load + echo "Building DAppNode Core if needed..." 2>&1 | tee -a "$LOGFILE" + dappnode_core_build -if [ ! -f "/usr/src/dappnode/.firstboot" ]; then - echo -e "\e[32mDAppNode installed\e[0m" 2>&1 | tee -a $LOGFILE - dappnode_start -fi + echo "Downloading DAppNode Core..." 2>&1 | tee -a "$LOGFILE" + dappnode_core_download -# Run test in interactive terminal -if [ -f "/usr/src/dappnode/.firstboot" ]; then - # ensure openvt is installed prior to using it - apt-get update - apt-get install -y kbd - openvt -s -w -- sudo -u root /usr/src/dappnode/scripts/dappnode_test_install.sh - exit 0 -fi + # Build compose args now that compose files exist + build_dncore_compose_args + + echo "Loading DAppNode Core..." 2>&1 | tee -a "$LOGFILE" + dappnode_core_load + + # --- Start DAppNode --- + if $IS_LINUX; then + if [ ! -f "${DAPPNODE_DIR}/.firstboot" ]; then + echo "DAppNode installed" 2>&1 | tee -a "$LOGFILE" + dappnode_core_start + print_vpn_access_credentials + fi + + # Run test in interactive terminal (first boot only) + if [ -f "${DAPPNODE_DIR}/.firstboot" ]; then + apt-get update + apt-get install -y kbd + openvt -s -w -- sudo -u root "${DAPPNODE_DIR}/scripts/dappnode_test_install.sh" + exit 0 + fi + fi + + if $IS_MACOS; then + echo "DAppNode installed" 2>&1 | tee -a "$LOGFILE" + dappnode_core_start + print_vpn_access_credentials + fi +} -exit 0 +main "$@" diff --git a/scripts/dappnode_uninstall.sh b/scripts/dappnode_uninstall.sh index 66bc9f35..29da4a5e 100755 --- a/scripts/dappnode_uninstall.sh +++ b/scripts/dappnode_uninstall.sh @@ -1,21 +1,72 @@ #!/usr/bin/env bash -DAPPNODE_DIR="/usr/src/dappnode" + +# This uninstaller is written for bash. It's safe to *run it from zsh* (it will execute via bash +# thanks to the shebang), but users sometimes invoke it as `zsh ./script.sh` or `source ./script.sh`. +# - If sourced, bail out (sourcing would pollute the current shell and can break it). +# - If invoked by a non-bash shell, re-exec with bash before hitting bash-specific builtins. +if (return 0 2>/dev/null); then + echo "This script must be executed, not sourced. Run: bash $0" + return 1 +fi + +if [ -z "${BASH_VERSION:-}" ]; then + exec /usr/bin/env bash "$0" "$@" +fi + +################## +# OS DETECTION # +################## +OS_TYPE="$(uname -s)" +IS_MACOS=false +IS_LINUX=false +if [[ "$OS_TYPE" == "Darwin" ]]; then + IS_MACOS=true +elif [[ "$OS_TYPE" == "Linux" ]]; then + IS_LINUX=true +else + echo "Unsupported operating system: $OS_TYPE" + exit 1 +fi + +############# +# VARIABLES # +############# +# Dirs — macOS uses $HOME/dappnode, Linux uses /usr/src/dappnode (mirrors install script) +if $IS_MACOS; then + DAPPNODE_DIR="$HOME/dappnode" +else + DAPPNODE_DIR="/usr/src/dappnode" +fi DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" PROFILE_FILE="${DAPPNODE_CORE_DIR}/.dappnode_profile" input=$1 # Allow to call script with argument (must be Y/N) -[ -f $PROFILE_FILE ] || ( - echo "Error: DAppNode profile does not exist." +############################## +# Cross-platform Helpers # +############################## + +# Cross-platform in-place sed (macOS requires '' after -i) +sed_inplace() { + if $IS_MACOS; then + sed -i '' "$@" + else + sed -i "$@" + fi +} + +[ -f "$PROFILE_FILE" ] || { + echo "Error: DAppNode profile does not exist at ${PROFILE_FILE}." exit 1 -) +} uninstall() { - echo -e "\e[32mUninstalling DAppNode\e[0m" + echo "Uninstalling DAppNode" # shellcheck disable=SC1090 source "${PROFILE_FILE}" &>/dev/null DAPPNODE_CONTAINERS="$(docker ps -a --format '{{.Names}}' | grep DAppNode)" - echo -e "\e[32mRemoving DAppNode containers: \e[0m\n${DAPPNODE_CONTAINERS}" + echo "Removing DAppNode containers: " + echo "${DAPPNODE_CONTAINERS}" for container in $DAPPNODE_CONTAINERS; do # Stop DAppNode container docker stop "$container" &>/dev/null @@ -24,40 +75,58 @@ uninstall() { done DAPPNODE_IMAGES="$(docker image ls -a | grep "dappnode")" - echo -e "\e[32mRemoving DAppNode images: \e[0m\n${DAPPNODE_IMAGES}" + echo "Removing DAppNode images: " + echo "${DAPPNODE_IMAGES}" for image in $DAPPNODE_IMAGES; do # Remove DAppNode images docker image rm "$image" &>/dev/null done DAPPNODE_VOLUMES="$(docker volume ls | grep "dappnode\|dncore")" - echo -e "\e[32mRemoving DAppNode volumes: \e[0m\n${DAPPNODE_VOLUMES}" + echo "Removing DAppNode volumes: " + echo "${DAPPNODE_VOLUMES}" for volume in $DAPPNODE_VOLUMES; do # Remove DAppNode volumes docker volume rm "$volume" &>/dev/null done # Remove dncore_network - echo -e "\e[32mRemoving docker dncore_network\e[0m" + echo "Removing docker dncore_network" docker network remove dncore_network || echo "dncore_network already removed" - # Remove dir - echo -e "\e[32mRemoving DAppNode directory\e[0m" - rm -rf /usr/src/dappnode + # Remove DAppNode directory + echo "Removing DAppNode directory: ${DAPPNODE_DIR}" + rm -rf "${DAPPNODE_DIR}" # Remove profile file references from shell config files - USER=$(grep 1000 /etc/passwd | cut -f 1 -d:) - [ -n "$USER" ] && USER_HOME=/home/$USER || USER_HOME=/root - - for config_file in .profile .bashrc; do - CONFIG_PATH="$USER_HOME/$config_file" - if [ -f "$CONFIG_PATH" ]; then - sed -i '/######## DAPPNODE PROFILE ########/d' "$CONFIG_PATH" - sed -i '/.*dappnode_profile/d' "$CONFIG_PATH" + local user_home + local shell_configs + + if $IS_MACOS; then + user_home="$HOME" + # macOS defaults to zsh — matches install script + shell_configs=(".zshrc" ".zprofile") + else + local user_name + user_name=$(grep 1000 /etc/passwd | cut -f 1 -d:) + if [ -n "$user_name" ]; then + user_home="/home/$user_name" + else + user_home="/root" + fi + shell_configs=(".profile" ".bashrc") + fi + + # Remove Dappnode profile references from shell config files + for config_file in "${shell_configs[@]}"; do + local config_path="${user_home}/${config_file}" + if [ -f "$config_path" ]; then + sed_inplace '/######## DAPPNODE PROFILE ########/d' "$config_path" + sed_inplace '/.*dappnode_profile/d' "$config_path" fi done - echo -e "\e[32mDAppNode uninstalled!\e[0m" + echo "DAppNode uninstalled!" } if [ $# -eq 0 ]; then From aa7e0e2e65e4e378e31574cc01f02c1578659e96 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Mon, 9 Mar 2026 09:57:32 +0100 Subject: [PATCH 40/55] Add notifications and premium package versions to CHANGELOG.md (#697) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad7c934e..f6cd00b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -241,7 +241,7 @@ jobs: SHASUM_DEBIAN_ATTENDED=$(cat SHASUM_DEBIAN_ATTENDED.txt) SHASUM_DEBIAN_UNATTENDED=$(cat SHASUM_DEBIAN_UNATTENDED.txt) SHASUM_UBUNTU_UNATTENDED=$(cat SHASUM_UBUNTU_UNATTENDED.txt) - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso\n$SHASUM_UBUNTU_UNATTENDED\n```\nUploaded at https://ubuntu.iso.dappnode.io\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md + echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n|notifications.dnp.dappnode.eth|${{ needs.set-versions.outputs.notifications }}|\n|premium.dnp.dappnode.eth|${{ needs.set-versions.outputs.premium }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso\n$SHASUM_UBUNTU_UNATTENDED\n```\nUploaded at https://ubuntu.iso.dappnode.io\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md cat CHANGELOG.md - name: Print images directory run: | From 50957c3a20969d5f3aa97f798882860f840994d2 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Tue, 17 Mar 2026 07:47:18 +0100 Subject: [PATCH 41/55] Add final sleep seconds parameter to wait_for_internal_ip function (#700) --- scripts/dappnode_install.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index 0f6e4ab0..32f82f95 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -172,11 +172,12 @@ check_prereqs() { # Wait until dappmanager publishes INTERNAL_IP via its local HTTP endpoint. # Runs the curl inside the provided container and exits with error on timeout. -# Usage: wait_for_internal_ip [timeout_seconds] [initial_sleep_seconds] +# Usage: wait_for_internal_ip [timeout_seconds] [initial_sleep_seconds] [final_sleep_seconds] wait_for_internal_ip() { local container_name="$1" local timeout_seconds="${2:-120}" local initial_sleep_seconds="${3:-10}" + local final_sleep_seconds="${4:-2}" local internal_ip_url="http://127.0.0.1/global-envs/INTERNAL_IP" local hostname_url="http://127.0.0.1/global-envs/HOSTNAME" @@ -214,7 +215,7 @@ wait_for_internal_ip() { hostname_value="$(printf '%s\n' "$hostname_result" | head -n 1 | tr -d '\r' | xargs)" if [[ "$internal_http_code" == "200" && -n "$internal_value" && "$internal_value" != "null" && "$hostname_http_code" == "200" && -n "$hostname_value" && "$hostname_value" != "null" ]]; then - sleep 2 # Extra buffer to ensure values are fully propagated before we proceed + sleep "$final_sleep_seconds" # Extra buffer to ensure values are fully propagated before we proceed echo "INTERNAL_IP is ready: $internal_value" echo "HOSTNAME is ready: $hostname_value" return 0 @@ -253,7 +254,7 @@ print_vpn_access_credentials() { echo "" echo "Waiting for VPN initialization..." - wait_for_internal_ip "DAppNodeCore-dappmanager.dnp.dappnode.eth" 120 20 + wait_for_internal_ip "DAppNodeCore-dappmanager.dnp.dappnode.eth" 120 20 10 echo "" echo "##############################################" From d00bc0b50c1649b0c5bb1ba0b758bf0167925d34 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Tue, 17 Mar 2026 12:25:45 +0100 Subject: [PATCH 42/55] Add port conflict checks for HTTPS and VPN in installer script (#701) * Add port conflict checks for HTTPS and VPN in installer script * Update notifications and premium package versions in .dappnode_profile * Refactor logging in dappnode_install.sh to use log function for consistency * Update package versions in .dappnode_profile for consistency * Enhance logging and retry mechanism in wait_for_internal_ip function; update warnings for credential availability * Update IPFS endpoint URL in dappnode_install.sh for stability * Update notifications and premium package versions in .dappnode_profile for consistency --- .dappnode_profile | 16 +-- scripts/dappnode_install.sh | 279 +++++++++++++++++++++++------------- 2 files changed, 184 insertions(+), 111 deletions(-) diff --git a/.dappnode_profile b/.dappnode_profile index ece7e1bd..4d4943b8 100755 --- a/.dappnode_profile +++ b/.dappnode_profile @@ -7,15 +7,15 @@ # - `/ipfs/QmRe6...` -> indicates the ipfs hash used to download the content # - `0.2.71` -> indicates the version. It must be the one uploaded to such IPFS hash -export BIND_VERSION="${BIND_VERSION:-0.2.11}" -export IPFS_VERSION="${IPFS_VERSION:-0.2.23}" -export VPN_VERSION="${VPN_VERSION:-0.2.10}" -export DAPPMANAGER_VERSION="${DAPPMANAGER_VERSION:-0.2.99}" -export WIFI_VERSION="${WIFI_VERSION:-0.2.9}" -export WIREGUARD_VERSION="${WIREGUARD_VERSION:-0.1.3}" +export BIND_VERSION="${BIND_VERSION:-0.2.13}" +export IPFS_VERSION="${IPFS_VERSION:-0.2.27}" +export VPN_VERSION="${VPN_VERSION:-0.2.11}" +export DAPPMANAGER_VERSION="${DAPPMANAGER_VERSION:-0.2.121}" +export WIFI_VERSION="${WIFI_VERSION:-0.2.11}" +export WIREGUARD_VERSION="${WIREGUARD_VERSION:-0.1.4}" export HTTPS_VERSION="${HTTPS:-0.2.2}" -export NOTIFICATIONS_VERSION="/ipfs/QmQubxH4WgqEFxvFntef4H2DmuU6mxBRS6XeuShc3owNi9" -export PREMIUM_VERSION="/ipfs/QmXDddoa56HkrvtkGsa3mozpsn9SzQZtoVBWgagcW6SsHy" +export NOTIFICATIONS_VERSION="/ipfs/QmW5CSZv8x8ZktiNodJ9P8M6ZSRNX93jmB8oU6RtGermBc" +export PREMIUM_VERSION="/ipfs/QmUEmjt1yXLyGjnqf3BCiVenQtDhFwt4eMkx1sDemeEidM" export DAPPNODE_DIR="/usr/src/dappnode" export DAPPNODE_CORE_DIR="${DAPPNODE_DIR}/DNCORE" diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index 32f82f95..0379827a 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -4,9 +4,56 @@ # thanks to the shebang), but users sometimes invoke it as `zsh ./script.sh` or `source ./script.sh`. # - If sourced, bail out (sourcing would pollute the current shell and can break it). # - If invoked by a non-bash shell, re-exec with bash before hitting bash-specific builtins. + +############################## +# Logging / Errors # +############################## +# Note: LOGFILE and LOGS_DIR are set during bootstrap_filesystem based on DAPPNODE_DIR +# Early definition allows these functions to be used throughout the script. + +log() { + # LOGFILE is created after dir bootstrap; until then we just print to stdout. + if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then + printf '%s\n' "[INFO] $*" | tee -a "$LOGFILE" + else + printf '%s\n' "[INFO] $*" + fi +} + +warn() { + # LOGFILE is created after dir bootstrap; until then we just print to stdout. + if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then + printf '%s\n' "[WARN] $*" | tee -a "$LOGFILE" + else + printf '%s\n' "[WARN] $*" + fi +} + +error() { + # LOGFILE is created after dir bootstrap; until then we just print to stdout. + if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then + printf '%s\n' "[ERROR] $*" | tee -a "$LOGFILE" + else + printf '%s\n' "[ERROR] $*" + fi +} + +die() { + # LOGFILE is created after dir bootstrap; until then we just print to stdout. + if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then + printf '%s\n' "[ERROR] $*" | tee -a "$LOGFILE" + else + printf '%s\n' "[ERROR] $*" + fi + exit 1 +} + +############################## +# Script Guards # +############################## + if (return 0 2>/dev/null); then - echo "This script must be executed, not sourced. Run: bash $0" - return 1 + die "This script must be executed, not sourced. Run: bash $0" fi if [ -z "${BASH_VERSION:-}" ]; then @@ -30,28 +77,6 @@ shopt -s expand_aliases # Ensure array is always defined (avoid `set -u` edge cases) DNCORE_COMPOSE_ARGS=() -############################## -# Logging / Errors # -############################## - -log() { - # LOGFILE is created after dir bootstrap; until then we just print to stdout. - if [[ -n "${LOGFILE:-}" && -d "${LOGS_DIR:-}" ]]; then - printf '%s\n' "$*" | tee -a "$LOGFILE" - else - printf '%s\n' "$*" - fi -} - -warn() { - log "[WARN] $*" -} - -die() { - log "[ERROR] $*" - exit 1 -} - usage() { cat <<'EOF' Usage: dappnode_install.sh [options] @@ -181,7 +206,7 @@ wait_for_internal_ip() { local internal_ip_url="http://127.0.0.1/global-envs/INTERNAL_IP" local hostname_url="http://127.0.0.1/global-envs/HOSTNAME" - echo "Waiting for dappmanager to publish INTERNAL_IP and HOSTNAME..." + log "Waiting for dappmanager to publish INTERNAL_IP and HOSTNAME..." sleep "$initial_sleep_seconds" local start_seconds internal_http_code internal_value internal_result @@ -191,6 +216,7 @@ wait_for_internal_ip() { internal_value="" hostname_http_code="" hostname_value="" + local retry_count=0 while true; do if (( SECONDS - start_seconds >= timeout_seconds )); then @@ -216,12 +242,15 @@ wait_for_internal_ip() { if [[ "$internal_http_code" == "200" && -n "$internal_value" && "$internal_value" != "null" && "$hostname_http_code" == "200" && -n "$hostname_value" && "$hostname_value" != "null" ]]; then sleep "$final_sleep_seconds" # Extra buffer to ensure values are fully propagated before we proceed - echo "INTERNAL_IP is ready: $internal_value" - echo "HOSTNAME is ready: $hostname_value" + log "INTERNAL_IP is ready: $internal_value" + log "HOSTNAME is ready: $hostname_value" return 0 fi - echo "INTERNAL_IP/HOSTNAME not ready yet (INTERNAL_IP code=${internal_http_code:-?}, HOSTNAME code=${hostname_http_code:-?}). Retrying..." + retry_count=$((retry_count + 1)) + if (( retry_count % 5 == 1 )); then + log "INTERNAL_IP/HOSTNAME not ready yet (INTERNAL_IP code=${internal_http_code:-?}, HOSTNAME code=${hostname_http_code:-?}). Retrying..." + fi sleep 2 done } @@ -247,43 +276,42 @@ print_vpn_access_credentials() { done if [[ "$has_wireguard" != "true" && "$has_vpn" != "true" ]]; then - echo "" - echo "No VPN package selected (VPN/WIREGUARD). Skipping credentials output." + log "No VPN package selected (VPN/WIREGUARD). Skipping credentials output." return 0 fi - echo "" - echo "Waiting for VPN initialization..." + log "" + log "Waiting for VPN initialization..." wait_for_internal_ip "DAppNodeCore-dappmanager.dnp.dappnode.eth" 120 20 10 - echo "" - echo "##############################################" - echo "# DAppNode VPN Access Credentials #" - echo "##############################################" - echo "" - echo "Your DAppNode is ready! Connect using your preferred VPN client." - echo "Choose either Wireguard (recommended) or OpenVPN and import the" - echo "credentials below into your VPN app to access your DAppNode." - echo "" + log "" + log "##############################################" + log "# DAppNode VPN Access Credentials #" + log "##############################################" + log "" + log "Your DAppNode is ready! Connect using your preferred VPN client." + log "Choose either Wireguard (recommended) or OpenVPN and import the" + log "credentials below into your VPN app to access your DAppNode." + log "" if [[ "$has_wireguard" == "true" ]]; then - echo "--- Wireguard ---" + log "--- Wireguard ---" docker exec -i DAppNodeCore-api.wireguard.dnp.dappnode.eth getWireguardCredentials "${localhost_flag[@]}" 2>&1 || \ - echo "Wireguard credentials not yet available. Try later with: dappnode_wireguard${localhost_flag:+ ${localhost_flag[*]}}" + warn "Wireguard credentials not yet available. Try later with: dappnode_wireguard${localhost_flag:+ ${localhost_flag[*]}}" fi if [[ "$has_wireguard" == "true" && "$has_vpn" == "true" ]]; then - echo "" + log "" fi if [[ "$has_vpn" == "true" ]]; then - echo "--- OpenVPN ---" + log "--- OpenVPN ---" docker exec -i DAppNodeCore-vpn.dnp.dappnode.eth vpncli get dappnode_admin "${localhost_flag[@]}" 2>&1 || \ - echo "OpenVPN credentials not yet available. Try later with: dappnode_openvpn_get dappnode_admin${localhost_flag:+ ${localhost_flag[*]}}" + warn "OpenVPN credentials not yet available. Try later with: dappnode_openvpn_get dappnode_admin${localhost_flag:+ ${localhost_flag[*]}}" fi - echo "" - echo "Import the configuration above into your VPN client of choice to access your DAppNode at http://my.dappnode" + log "" + log "Import the configuration above into your VPN client of choice to access your DAppNode at http://my.dappnode" } # Build docker compose "-f " args from downloaded compose files. @@ -332,7 +360,7 @@ if $IS_LINUX; then UPDATE_MOTD_DIR="/etc/update-motd.d" fi # Get URLs -IPFS_ENDPOINT=${IPFS_ENDPOINT:-"https://ipfs-gateway-dev.dappnode.net"} +IPFS_ENDPOINT=${IPFS_ENDPOINT:-"https://ipfs-gateway.dappnode.net"} # PROFILE_URL env is used to fetch the core packages versions that will be used to build the release in script install method PROFILE_URL=${PROFILE_URL:-"https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_profile.sh"} DAPPNODE_ACCESS_CREDENTIALS="${DAPPNODE_DIR}/scripts/dappnode_access_credentials.sh" @@ -402,8 +430,8 @@ normalize_ipfs_version_ref() { local manifest manifest="$(download_stdout "$manifest_url" 2>/dev/null || true)" if [[ -z "$manifest" ]]; then - echo "[ERROR] Could not fetch IPFS manifest for ${comp} from: $manifest_url" 1>&2 - echo "[ERROR] Provide ${comp}_VERSION as /ipfs/: (example: /ipfs/Qm...:0.2.11)" 1>&2 + error "Could not fetch IPFS manifest for ${comp} from: $manifest_url" + error "Provide ${comp}_VERSION as /ipfs/: (example: /ipfs/Qm...:0.2.11)" return 1 fi @@ -416,8 +444,8 @@ normalize_ipfs_version_ref() { )" if [[ -z "$inferred_version" || "$inferred_version" == "$manifest" ]]; then - echo "[ERROR] Could not infer version for ${comp} from IPFS manifest: $manifest_url" 1>&2 - echo "[ERROR] Provide ${comp}_VERSION as /ipfs/:" 1>&2 + error "Could not infer version for ${comp} from IPFS manifest: $manifest_url" + error "Provide ${comp}_VERSION as /ipfs/:" return 1 fi @@ -501,7 +529,7 @@ patch_dappmanager_compose_for_macos() { bootstrap_filesystem() { # Clean if update if [[ "${UPDATE}" == "true" ]]; then - echo "Cleaning for update..." + log "Cleaning for update..." rm -f "${LOGFILE}" || true rm -f "${DAPPNODE_CORE_DIR}"/docker-compose-*.yml || true rm -f "${DAPPNODE_CORE_DIR}"/dappnode_package-*.json || true @@ -523,35 +551,79 @@ bootstrap_filesystem() { touch "${LOGFILE}" || true } -# Check if port 80 is in use (necessary for HTTPS) -# Returns IS_PORT_USED=true only if port 80 or 443 is used by something OTHER than our HTTPS container -is_port_used() { - # Check if port 80 or 443 is in use at all - local port80_used port443_used - if command -v lsof >/dev/null 2>&1; then - lsof -i -P -n | grep ":80 (LISTEN)" &>/dev/null && port80_used=true || port80_used=false - lsof -i -P -n | grep ":443 (LISTEN)" &>/dev/null && port443_used=true || port443_used=false +# Generic helper: returns 0 if a process is bound to the given port, 1 if not. +# Usage: is_port_listening [tcp|udp] +# tcp (default): matches TCP sockets in LISTEN state +# udp: matches any process bound to the UDP port +is_port_listening() { + local port="$1" + local proto="${2:-tcp}" + if [[ "$proto" == "udp" ]]; then + lsof -i "udp:${port}" -P -n 2>/dev/null | grep -q . else + lsof -i "tcp:${port}" -P -n 2>/dev/null | grep -q "(LISTEN)" + fi +} + +# Check if ports 80/443 are occupied by something other than our own HTTPS container. +# Sets HTTPS_PORTS_BLOCKED=true/false. +check_https_ports_conflict() { + if ! command -v lsof >/dev/null 2>&1; then warn "lsof not found; assuming ports 80/443 are in use (HTTPS will be skipped)" - IS_PORT_USED=true + HTTPS_PORTS_BLOCKED=true return fi - if [ "$port80_used" = false ] && [ "$port443_used" = false ]; then - IS_PORT_USED=false + if ! is_port_listening 80 && ! is_port_listening 443; then + HTTPS_PORTS_BLOCKED=false return fi - # If either port is in use, check if it's our HTTPS container + # Port 80 or 443 is in use; check if it's our own HTTPS container if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^DAppNodeCore-https.dnp.dappnode.eth$"; then - # Port 80 or 443 is used by our HTTPS container, so we consider it "not used" for package determination - IS_PORT_USED=false + # Our own HTTPS container already holds the port — not a conflict + HTTPS_PORTS_BLOCKED=false else # Port 80 or 443 is used by something else - IS_PORT_USED=true + HTTPS_PORTS_BLOCKED=true fi } +# Check that ports required by VPN/Wireguard are not already in use by another process. +# Must be called after PKGS is populated. Exits with a helpful error on conflict. +check_vpn_ports_conflict() { + if ! command -v lsof >/dev/null 2>&1; then + return # cannot check; proceed and let the container report a bind error + fi + + local pkg + for pkg in "${PKGS[@]}"; do + case "$pkg" in + WIREGUARD) + if is_port_listening 51820 udp; then + error "Port 51820/UDP is already in use on this host." + error "This port is required by the Wireguard package and must be free before installing." + error "Free up port 51820 and re-run the installer, or — if you do not need VPN" + error "connectivity — consider using --minimal instead (advanced users only)." + exit 1 + fi + ;; + VPN) + local vpn_blocked=() + is_port_listening 1194 udp && vpn_blocked+=(1194/UDP) + is_port_listening 8092 tcp && vpn_blocked+=(8092/TCP) + if [[ ${#vpn_blocked[@]} -gt 0 ]]; then + error "Port(s) ${vpn_blocked[*]} are already in use on this host." + error "These ports are required by the OpenVPN package and must be free before installing." + error "Free up the port(s) and re-run the installer, or — if you do not need VPN" + error "connectivity — consider using --minimal instead (advanced users only)." + exit 1 + fi + ;; + esac + done +} + # Determine packages to be installed determine_packages() { # Explicit package list override from flag/env always has top priority. @@ -649,8 +721,8 @@ determine_packages() { # Default mode (no --packages/--minimal/--lite): install full package set. # HTTPS is included only when ports 80/443 are available. - is_port_used - if [ "$IS_PORT_USED" == "true" ]; then + check_https_ports_conflict + if [ "$HTTPS_PORTS_BLOCKED" == "true" ]; then PKGS=(BIND IPFS VPN WIREGUARD DAPPMANAGER WIFI NOTIFICATIONS PREMIUM) else PKGS=(HTTPS BIND IPFS VPN WIREGUARD DAPPMANAGER WIFI NOTIFICATIONS PREMIUM) @@ -710,6 +782,7 @@ resolve_packages() { # If such variable with 'dev:'' suffix is used, then the component is built from specified branch or commit. # you can also specify an IPFS version like /ipfs/: (the exact version is required). determine_packages + check_vpn_ports_conflict for comp in "${PKGS[@]}"; do ver="${comp}_VERSION" log "Processing $comp: ${!ver-}" @@ -741,17 +814,17 @@ dappnode_core_build() { ver="${comp}_VERSION" if [[ ${!ver} == dev:* ]]; then if $IS_MACOS; then - echo "Development builds (dev:*) are not supported on macOS." + error "Development builds (dev:*) are not supported on macOS." exit 1 fi - echo "Cloning & building DNP_${comp}..." + log "Cloning & building DNP_${comp}..." if ! dpkg -s git >/dev/null 2>&1; then apt-get install -y git fi local tmpdir tmpdir="$(mktemp -d)" pushd "$tmpdir" >/dev/null || { - echo "Error on pushd" + error "Error on pushd" exit 1 } git clone -b "${!ver##*:}" https://github.com/dappnode/DNP_"${comp}" @@ -765,7 +838,7 @@ dappnode_core_build() { cp "./DNP_${comp}/dappnode_package.json" "${DAPPNODE_CORE_DIR}/dappnode_package-${comp_lower}.json" rm -rf "./DNP_${comp}" popd >/dev/null || { - echo "Error on popd" + error "Error on popd" exit 1 } rm -rf "$tmpdir" @@ -785,13 +858,13 @@ dappnode_core_download() { local manifest_var="${comp}_MANIFEST" # Download DAppNode Core Images if needed - echo "Downloading ${comp} tar..." + log "Downloading ${comp} tar..." [ -f "${!file_var}" ] || download_file "${!file_var}" "${!url_var}" || exit 1 # Download DAppNode Core docker-compose yml files if needed - echo "Downloading ${comp} yml..." + log "Downloading ${comp} yml..." [ -f "${!yml_file_var}" ] || download_file "${!yml_file_var}" "${!yml_var}" || exit 1 # Download DAppNode Core manifest files if needed - echo "Downloading ${comp} manifest..." + log "Downloading ${comp} manifest..." [ -f "${!manifest_file_var}" ] || download_file "${!manifest_file_var}" "${!manifest_var}" || exit 1 # macOS: patch compose files for Docker Desktop compatibility @@ -877,7 +950,7 @@ addSwap() { # if not then create it if [ "$IS_SWAP" -eq 0 ]; then - echo 'Swap not found. Adding swapfile.' + log 'Swap not found. Adding swapfile.' #RAM=$(awk '/MemTotal/ {print $2}' /proc/meminfo) #SWAP=$(($RAM * 2)) SWAP=8388608 @@ -887,7 +960,7 @@ addSwap() { swapon /swapfile echo '/swapfile none swap defaults 0 0' >>/etc/fstab else - echo 'Swap found. No changes made.' + log 'Swap found. No changes made.' fi } @@ -936,7 +1009,7 @@ add_profile_to_shell() { } dappnode_core_start() { - echo "DAppNode starting..." 2>&1 | tee -a "$LOGFILE" + log "DAppNode starting..." if [[ ${#DNCORE_COMPOSE_ARGS[@]} -eq 0 ]]; then build_dncore_compose_args @@ -944,7 +1017,7 @@ dappnode_core_start() { [[ ${#DNCORE_COMPOSE_ARGS[@]} -gt 0 ]] || die "No docker-compose-*.yml files found in ${DAPPNODE_CORE_DIR}" docker compose "${DNCORE_COMPOSE_ARGS[@]}" up -d 2>&1 | tee -a "$LOGFILE" - echo "DAppNode started" 2>&1 | tee -a "$LOGFILE" + log "DAppNode started" # Add profile sourcing to user's shell configuration add_profile_to_shell @@ -963,7 +1036,7 @@ dappnode_core_start() { fi # Display help message to the user - echo "Execute dappnode_help to see a full list with commands available" + log "Execute dappnode_help to see a full list with commands available" } grabContentHashes() { @@ -972,7 +1045,7 @@ grabContentHashes() { for comp in "${content_hash_pkgs[@]}"; do CONTENT_HASH=$(download_stdout "https://github.com/dappnode/DAppNodePackage-${comp}/releases/latest/download/content-hash") if [ -z "$CONTENT_HASH" ]; then - echo "ERROR! Failed to find content hash of ${comp}." 2>&1 | tee -a "$LOGFILE" + error "Failed to find content hash of ${comp}." exit 1 fi echo "${comp}.dnp.dappnode.eth,${CONTENT_HASH}" >>"${CONTENT_HASH_FILE}" @@ -1005,12 +1078,12 @@ addUserToDockerGroup() { # If USER is not found, warn the user and return if [ -z "$user" ]; then - echo "WARN: Default user not found. Could not add it to the docker group." 2>&1 | tee -a "$LOGFILE" + warn "Default user not found. Could not add it to the docker group." return fi if groups "$user" | grep &>/dev/null '\bdocker\b'; then - echo "User $user is already in the docker group" 2>&1 | tee -a "$LOGFILE" + log "User $user is already in the docker group" return fi @@ -1018,7 +1091,7 @@ addUserToDockerGroup() { # but it's not working in the Ubuntu ISO because the late-commands in the autoinstall.yaml # file are executed before the user is created. usermod -aG docker "$user" - echo "User $user added to the docker group" 2>&1 | tee -a "$LOGFILE" + log "User $user added to the docker group" } ############################################## @@ -1036,58 +1109,58 @@ main() { resolve_packages echo "" 2>&1 | tee -a "$LOGFILE" - echo "##############################################" 2>&1 | tee -a "$LOGFILE" - echo "#### DAPPNODE INSTALLER ####" 2>&1 | tee -a "$LOGFILE" - echo "##############################################" 2>&1 | tee -a "$LOGFILE" + log "##############################################" + log "#### DAPPNODE INSTALLER ####" + log "##############################################" # --- Linux-only setup steps --- if $IS_LINUX; then if [[ "${MINIMAL}" != "true" && "${LITE}" != "true" ]]; then - echo "Creating swap memory..." 2>&1 | tee -a "$LOGFILE" + log "Creating swap memory..." addSwap - echo "Customizing login..." 2>&1 | tee -a "$LOGFILE" + log "Customizing login..." customMotd - echo "Installing extra packages..." 2>&1 | tee -a "$LOGFILE" + log "Installing extra packages..." installExtraDpkg - echo "Grabbing latest content hashes..." 2>&1 | tee -a "$LOGFILE" + log "Grabbing latest content hashes..." grabContentHashes if [ "$ARCH" == "amd64" ]; then - echo "Installing SGX modules..." 2>&1 | tee -a "$LOGFILE" + log "Installing SGX modules..." installSgx - echo "Installing extra packages..." 2>&1 | tee -a "$LOGFILE" + log "Installing extra packages..." installExtraDpkg # TODO: Why is this being called twice? fi fi - echo "Adding user to docker group..." 2>&1 | tee -a "$LOGFILE" + log "Adding user to docker group..." addUserToDockerGroup fi # --- Common steps (Linux and macOS) --- - echo "Creating dncore_network if needed..." 2>&1 | tee -a "$LOGFILE" + log "Creating dncore_network if needed..." docker network create --driver bridge --subnet 172.33.0.0/16 dncore_network 2>&1 | tee -a "$LOGFILE" || true - echo "Building DAppNode Core if needed..." 2>&1 | tee -a "$LOGFILE" + log "Building DAppNode Core if needed..." dappnode_core_build - echo "Downloading DAppNode Core..." 2>&1 | tee -a "$LOGFILE" + log "Downloading DAppNode Core..." dappnode_core_download # Build compose args now that compose files exist build_dncore_compose_args - echo "Loading DAppNode Core..." 2>&1 | tee -a "$LOGFILE" + log "Loading DAppNode Core..." dappnode_core_load # --- Start DAppNode --- if $IS_LINUX; then if [ ! -f "${DAPPNODE_DIR}/.firstboot" ]; then - echo "DAppNode installed" 2>&1 | tee -a "$LOGFILE" + log "DAppNode installed" dappnode_core_start print_vpn_access_credentials fi @@ -1102,7 +1175,7 @@ main() { fi if $IS_MACOS; then - echo "DAppNode installed" 2>&1 | tee -a "$LOGFILE" + log "DAppNode installed" dappnode_core_start print_vpn_access_credentials fi From 548fd516d91adb1954b13cccec7fed992ca1abb3 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Wed, 18 Mar 2026 08:06:41 +0100 Subject: [PATCH 43/55] Update Debian ISO version to 13.4.0 in generate_dappnode_iso_debian.sh (#699) --- iso/scripts/generate_dappnode_iso_debian.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index 201e0082..64fb0a05 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -5,11 +5,11 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -# Source = https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso -BASE_ISO_NAME="debian-12.11.0-amd64-netinst.iso" +# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.4.0-amd64-netinst.iso +BASE_ISO_NAME="debian-13.4.0-amd64-netinst.iso" BASE_ISO_PATH="/images/${BASE_ISO_NAME}" -BASE_ISO_URL="https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/${BASE_ISO_NAME}" -BASE_ISO_SHASUM="30ca12a15cae6a1033e03ad59eb7f66a6d5a258dcf27acd115c2bd42d22640e8 ${BASE_ISO_PATH}" +BASE_ISO_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${BASE_ISO_NAME}" +BASE_ISO_SHASUM="0b813535dd76f2ea96eff908c65e8521512c92a0631fd41c95756ffd7d4896dc ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" From ef5338ef6ecbdc5d07080ef96ce5e13fa4987018 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Wed, 18 Mar 2026 08:06:49 +0100 Subject: [PATCH 44/55] Update Ubuntu base ISO to version 24.04.4 and correct SHA256 checksum (#698) --- iso/scripts/generate_dappnode_iso_ubuntu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iso/scripts/generate_dappnode_iso_ubuntu.sh b/iso/scripts/generate_dappnode_iso_ubuntu.sh index c1c1a270..50a96933 100755 --- a/iso/scripts/generate_dappnode_iso_ubuntu.sh +++ b/iso/scripts/generate_dappnode_iso_ubuntu.sh @@ -5,10 +5,10 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -BASE_ISO_NAME=ubuntu-24.04.3-live-server-amd64.iso +BASE_ISO_NAME=ubuntu-24.04.4-live-server-amd64.iso BASE_ISO_PATH="/images/${BASE_ISO_NAME}" BASE_ISO_URL="https://releases.ubuntu.com/24.04/${BASE_ISO_NAME}" -BASE_ISO_SHASUM="c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b ${BASE_ISO_PATH}" +BASE_ISO_SHASUM="e907d92eeec9df64163a7e454cbc8d7755e8ddc7ed42f99dbc80c40f1a138433 ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" From e74b6c5e5782d3dcec3245e1ad88ef2dd76f7343 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:07:52 +0100 Subject: [PATCH 45/55] Enable use of mirror in preseed configuration (#703) --- iso/preseeds/preseed_unattended.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iso/preseeds/preseed_unattended.cfg b/iso/preseeds/preseed_unattended.cfg index be31dba6..cf7b58d4 100644 --- a/iso/preseeds/preseed_unattended.cfg +++ b/iso/preseeds/preseed_unattended.cfg @@ -57,7 +57,7 @@ d-i grub-installer/bootdev string default ### Package selection tasksel tasksel/first multiselect standard d-i pkgsel/include string openssh-server vim sudo build-essential linux-headers-$(uname -r) iw iwd wpasupplicant intel-microcode iucode-tool firmware-misc-nonfree firmware-iwlwifi avahi-utils iptables -d-i apt-setup/use_mirror boolean false +d-i apt-setup/use_mirror boolean true d-i mirror/country string manual d-i mirror/http/hostname string deb.debian.org d-i mirror/http/directory string /debian From 36652dbd0b362c95c80453a09f14b7419318fde2 Mon Sep 17 00:00:00 2001 From: hcastc00 Date: Wed, 6 May 2026 15:59:55 +0200 Subject: [PATCH 46/55] fix: defer --update cleanup until after preflight checks pass --- scripts/dappnode_install.sh | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index 0379827a..13713c21 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -527,16 +527,14 @@ patch_dappmanager_compose_for_macos() { } bootstrap_filesystem() { - # Clean if update + # Clean if update — only the logfile and profile are removed here. + # Removing the profile early forces ensure_profile_loaded to re-download + # the latest one (so resolved package versions match the new release). + # Composes/manifests/archives are removed later by clean_for_update, + # AFTER preflight passes — see comment in main(). if [[ "${UPDATE}" == "true" ]]; then - log "Cleaning for update..." rm -f "${LOGFILE}" || true - rm -f "${DAPPNODE_CORE_DIR}"/docker-compose-*.yml || true - rm -f "${DAPPNODE_CORE_DIR}"/dappnode_package-*.json || true - rm -f "${DAPPNODE_CORE_DIR}"/*.tar.xz || true - rm -f "${DAPPNODE_CORE_DIR}"/*.txz || true rm -f "${DAPPNODE_CORE_DIR}/.dappnode_profile" || true - rm -f "${CONTENT_HASH_FILE}" || true fi # Create necessary directories @@ -551,6 +549,22 @@ bootstrap_filesystem() { touch "${LOGFILE}" || true } +# Destructive: remove on-disk artifacts from the previous install so fresh +# downloads take their place. Must only run AFTER preflight checks have passed — +# otherwise a failing preflight (e.g. port conflict) leaves the host with no +# compose files on disk while running containers continue to hold the ports. +clean_for_update() { + if [[ "${UPDATE}" != "true" ]]; then + return 0 + fi + log "Cleaning for update..." + rm -f "${DAPPNODE_CORE_DIR}"/docker-compose-*.yml || true + rm -f "${DAPPNODE_CORE_DIR}"/dappnode_package-*.json || true + rm -f "${DAPPNODE_CORE_DIR}"/*.tar.xz || true + rm -f "${DAPPNODE_CORE_DIR}"/*.txz || true + rm -f "${CONTENT_HASH_FILE}" || true +} + # Generic helper: returns 0 if a process is bound to the given port, 1 if not. # Usage: is_port_listening [tcp|udp] # tcp (default): matches TCP sockets in LISTEN state @@ -1107,6 +1121,10 @@ main() { configure_static_ip ensure_profile_loaded resolve_packages + # Destructive cleanup runs only after preflight (resolve_packages -> check_vpn_ports_conflict) + # has passed; otherwise a failing port check would wipe the on-disk composes while the + # running containers still hold the ports, leaving the node un-restartable. + clean_for_update echo "" 2>&1 | tee -a "$LOGFILE" log "##############################################" From 877fbe818cfef2c3c605a603962f5d8cac5925ea Mon Sep 17 00:00:00 2001 From: hcastc00 Date: Wed, 6 May 2026 16:42:34 +0200 Subject: [PATCH 47/55] fix: enhance VPN port conflict checks to allow updates on running containers --- scripts/dappnode_install.sh | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/scripts/dappnode_install.sh b/scripts/dappnode_install.sh index 13713c21..49ecf3f2 100755 --- a/scripts/dappnode_install.sh +++ b/scripts/dappnode_install.sh @@ -605,6 +605,8 @@ check_https_ports_conflict() { # Check that ports required by VPN/Wireguard are not already in use by another process. # Must be called after PKGS is populated. Exits with a helpful error on conflict. +# Ports held by our own dappnode core VPN/Wireguard containers are not conflicts — +# the upcoming compose-up will replace them. check_vpn_ports_conflict() { if ! command -v lsof >/dev/null 2>&1; then return # cannot check; proceed and let the container report a bind error @@ -615,11 +617,16 @@ check_vpn_ports_conflict() { case "$pkg" in WIREGUARD) if is_port_listening 51820 udp; then - error "Port 51820/UDP is already in use on this host." - error "This port is required by the Wireguard package and must be free before installing." - error "Free up port 51820 and re-run the installer, or — if you do not need VPN" - error "connectivity — consider using --minimal instead (advanced users only)." - exit 1 + # Port 51820 is in use; check if it's our own Wireguard container + if docker ps --format '{{.Names}}' 2>/dev/null | grep -qE "^DAppNodeCore-.*wireguard.*\.dnp\.dappnode\.eth$"; then + log "Port 51820/UDP is held by the existing DAppNode Wireguard container; it will be replaced." + else + error "Port 51820/UDP is already in use on this host." + error "This port is required by the Wireguard package and must be free before installing." + error "Free up port 51820 and re-run the installer, or — if you do not need VPN" + error "connectivity — consider using --minimal instead (advanced users only)." + exit 1 + fi fi ;; VPN) @@ -627,11 +634,16 @@ check_vpn_ports_conflict() { is_port_listening 1194 udp && vpn_blocked+=(1194/UDP) is_port_listening 8092 tcp && vpn_blocked+=(8092/TCP) if [[ ${#vpn_blocked[@]} -gt 0 ]]; then - error "Port(s) ${vpn_blocked[*]} are already in use on this host." - error "These ports are required by the OpenVPN package and must be free before installing." - error "Free up the port(s) and re-run the installer, or — if you do not need VPN" - error "connectivity — consider using --minimal instead (advanced users only)." - exit 1 + # Port(s) in use; check if held by our own OpenVPN container + if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^DAppNodeCore-vpn.dnp.dappnode.eth$"; then + log "Port(s) ${vpn_blocked[*]} are held by the existing DAppNode VPN container; it will be replaced." + else + error "Port(s) ${vpn_blocked[*]} are already in use on this host." + error "These ports are required by the OpenVPN package and must be free before installing." + error "Free up the port(s) and re-run the installer, or — if you do not need VPN" + error "connectivity — consider using --minimal instead (advanced users only)." + exit 1 + fi fi ;; esac From 4e156d71804a5abf158f7a53fc3029489994a84a Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 16:02:36 +0200 Subject: [PATCH 48/55] Add daily workflow to auto-update Ubuntu and Debian base ISOs --- .github/workflows/update-base-isos.yml | 157 +++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 .github/workflows/update-base-isos.yml diff --git a/.github/workflows/update-base-isos.yml b/.github/workflows/update-base-isos.yml new file mode 100644 index 00000000..eab37e14 --- /dev/null +++ b/.github/workflows/update-base-isos.yml @@ -0,0 +1,157 @@ +name: Update Base ISOs + +on: + schedule: + # Run daily at 08:00 UTC + - cron: "0 8 * * *" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-ubuntu-iso: + name: Check for Ubuntu ISO updates + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Check for new Ubuntu ISO version + id: ubuntu + run: | + SCRIPT="iso/scripts/generate_dappnode_iso_ubuntu.sh" + + # Get current version from script + CURRENT_ISO=$(grep -oP 'BASE_ISO_NAME=\K.*' "$SCRIPT") + echo "Current Ubuntu ISO: $CURRENT_ISO" + + # Fetch the SHA256SUMS file from Ubuntu releases + SHA256SUMS=$(curl -fsSL "https://releases.ubuntu.com/24.04/SHA256SUMS") + + # Find the latest live-server ISO entry + LATEST_LINE=$(echo "$SHA256SUMS" | grep 'live-server-amd64.iso' | head -1) + if [ -z "$LATEST_LINE" ]; then + echo "Could not find live-server ISO in SHA256SUMS" + exit 0 + fi + + LATEST_SHA=$(echo "$LATEST_LINE" | awk '{print $1}') + LATEST_ISO=$(echo "$LATEST_LINE" | awk '{print $2}' | sed 's|^\*||') + # Remove any leading path (e.g., "./" or directory prefix) + LATEST_ISO=$(basename "$LATEST_ISO") + + echo "Latest Ubuntu ISO: $LATEST_ISO (sha256: $LATEST_SHA)" + + if [ "$CURRENT_ISO" = "$LATEST_ISO" ]; then + echo "Ubuntu ISO is already up to date." + echo "updated=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Update the script + CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^"]*' "$SCRIPT" | awk '{print $1}') + sed -i "s|${CURRENT_ISO}|${LATEST_ISO}|g" "$SCRIPT" + sed -i "s|${CURRENT_SHA}|${LATEST_SHA}|" "$SCRIPT" + + echo "updated=true" >> "$GITHUB_OUTPUT" + echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" + echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" + + - name: Create Pull Request for Ubuntu ISO update + if: steps.ubuntu.outputs.updated == 'true' + uses: peter-evans/create-pull-request@v7 + with: + commit-message: "Update Ubuntu base ISO to ${{ steps.ubuntu.outputs.latest_iso }}" + branch: auto/update-ubuntu-iso + delete-branch: true + title: "Update Ubuntu base ISO to ${{ steps.ubuntu.outputs.latest_iso }}" + body: | + Automated update of the Ubuntu base ISO. + + - **Previous**: `${{ steps.ubuntu.outputs.current_iso }}` + - **New**: `${{ steps.ubuntu.outputs.latest_iso }}` + + This PR was created automatically by the `update-base-isos` workflow. + labels: automated + + update-debian-iso: + name: Check for Debian ISO updates + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Check for new Debian ISO version + id: debian + run: | + SCRIPT="iso/scripts/generate_dappnode_iso_debian.sh" + + # Get current version from script + CURRENT_ISO=$(grep -oP 'BASE_ISO_NAME="\K[^"]*' "$SCRIPT") + echo "Current Debian ISO: $CURRENT_ISO" + + # Fetch the SHA256SUMS file from Debian current release + SHA256SUMS=$(curl -fsSL "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS") + + # Find the latest netinst ISO entry + LATEST_LINE=$(echo "$SHA256SUMS" | grep 'amd64-netinst.iso' | head -1) + if [ -z "$LATEST_LINE" ]; then + echo "Could not find netinst ISO in SHA256SUMS" + exit 0 + fi + + LATEST_SHA=$(echo "$LATEST_LINE" | awk '{print $1}') + LATEST_ISO=$(echo "$LATEST_LINE" | awk '{print $2}' | sed 's|^\*||') + LATEST_ISO=$(basename "$LATEST_ISO") + + echo "Latest Debian ISO: $LATEST_ISO (sha256: $LATEST_SHA)" + + if [ "$CURRENT_ISO" = "$LATEST_ISO" ]; then + echo "Debian ISO is already up to date." + echo "updated=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Extract version numbers for URL update + CURRENT_VERSION=$(echo "$CURRENT_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') + LATEST_VERSION=$(echo "$LATEST_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') + + # Update the script + CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^ ]*' "$SCRIPT") + sed -i "s|${CURRENT_ISO}|${LATEST_ISO}|g" "$SCRIPT" + sed -i "s|${CURRENT_SHA}|${LATEST_SHA}|" "$SCRIPT" + + # Update the source comment and URL if the major version changed + CURRENT_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1) + LATEST_MAJOR=$(echo "$LATEST_VERSION" | cut -d. -f1) + + if [ "$CURRENT_MAJOR" != "$LATEST_MAJOR" ]; then + # If major version changes, update any archive URL to current + sed -i "s|cdimage.debian.org/mirror/cdimage/archive/${CURRENT_VERSION}|cdimage.debian.org/debian-cd/current|" "$SCRIPT" + fi + + # Update version in the source comment + sed -i "s|${CURRENT_VERSION}|${LATEST_VERSION}|g" "$SCRIPT" + + echo "updated=true" >> "$GITHUB_OUTPUT" + echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" + echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" + + - name: Create Pull Request for Debian ISO update + if: steps.debian.outputs.updated == 'true' + uses: peter-evans/create-pull-request@v7 + with: + commit-message: "Update Debian base ISO to ${{ steps.debian.outputs.latest_iso }}" + branch: auto/update-debian-iso + delete-branch: true + title: "Update Debian base ISO to ${{ steps.debian.outputs.latest_iso }}" + body: | + Automated update of the Debian base ISO. + + - **Previous**: `${{ steps.debian.outputs.current_iso }}` + - **New**: `${{ steps.debian.outputs.latest_iso }}` + + This PR was created automatically by the `update-base-isos` workflow. + labels: automated From faa8a8f6584edb4ee76fb242d07f7ca712d2e775 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 16:08:43 +0200 Subject: [PATCH 49/55] Add stale PR handling and use GitHub App token for ISO update workflow --- .github/workflows/update-base-isos.yml | 38 +++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/.github/workflows/update-base-isos.yml b/.github/workflows/update-base-isos.yml index eab37e14..5b260ee5 100644 --- a/.github/workflows/update-base-isos.yml +++ b/.github/workflows/update-base-isos.yml @@ -6,15 +6,17 @@ on: - cron: "0 8 * * *" workflow_dispatch: -permissions: - contents: write - pull-requests: write - jobs: update-ubuntu-iso: name: Check for Ubuntu ISO updates runs-on: ubuntu-latest steps: + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.TROPI_APP_ID }} + private-key: ${{ secrets.TROPI_APP_PRIVATE_KEY }} + - name: Checkout Code uses: actions/checkout@v6 @@ -59,10 +61,21 @@ jobs: echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" + - name: Close outdated Ubuntu ISO PR + if: steps.ubuntu.outputs.updated == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + EXISTING_PR=$(gh pr list --head auto/update-ubuntu-iso --state open --json number --jq '.[0].number') + if [ -n "$EXISTING_PR" ]; then + gh pr close "$EXISTING_PR" --comment "Superseded by a newer Ubuntu ISO version (${{ steps.ubuntu.outputs.latest_iso }})." --delete-branch + fi + - name: Create Pull Request for Ubuntu ISO update if: steps.ubuntu.outputs.updated == 'true' uses: peter-evans/create-pull-request@v7 with: + token: ${{ steps.app-token.outputs.token }} commit-message: "Update Ubuntu base ISO to ${{ steps.ubuntu.outputs.latest_iso }}" branch: auto/update-ubuntu-iso delete-branch: true @@ -80,6 +93,12 @@ jobs: name: Check for Debian ISO updates runs-on: ubuntu-latest steps: + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.TROPI_APP_ID }} + private-key: ${{ secrets.TROPI_APP_PRIVATE_KEY }} + - name: Checkout Code uses: actions/checkout@v6 @@ -139,10 +158,21 @@ jobs: echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" + - name: Close outdated Debian ISO PR + if: steps.debian.outputs.updated == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + EXISTING_PR=$(gh pr list --head auto/update-debian-iso --state open --json number --jq '.[0].number') + if [ -n "$EXISTING_PR" ]; then + gh pr close "$EXISTING_PR" --comment "Superseded by a newer Debian ISO version (${{ steps.debian.outputs.latest_iso }})." --delete-branch + fi + - name: Create Pull Request for Debian ISO update if: steps.debian.outputs.updated == 'true' uses: peter-evans/create-pull-request@v7 with: + token: ${{ steps.app-token.outputs.token }} commit-message: "Update Debian base ISO to ${{ steps.debian.outputs.latest_iso }}" branch: auto/update-debian-iso delete-branch: true From 6ab2c4b4fc481b46fba5b8feb1cda6f869f07ccb Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 14:10:02 +0000 Subject: [PATCH 50/55] Update Ubuntu base ISO to ubuntu-24.04.3-live-server-amd64.iso --- iso/scripts/generate_dappnode_iso_ubuntu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iso/scripts/generate_dappnode_iso_ubuntu.sh b/iso/scripts/generate_dappnode_iso_ubuntu.sh index 50a96933..c1c1a270 100755 --- a/iso/scripts/generate_dappnode_iso_ubuntu.sh +++ b/iso/scripts/generate_dappnode_iso_ubuntu.sh @@ -5,10 +5,10 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -BASE_ISO_NAME=ubuntu-24.04.4-live-server-amd64.iso +BASE_ISO_NAME=ubuntu-24.04.3-live-server-amd64.iso BASE_ISO_PATH="/images/${BASE_ISO_NAME}" BASE_ISO_URL="https://releases.ubuntu.com/24.04/${BASE_ISO_NAME}" -BASE_ISO_SHASUM="e907d92eeec9df64163a7e454cbc8d7755e8ddc7ed42f99dbc80c40f1a138433 ${BASE_ISO_PATH}" +BASE_ISO_SHASUM="c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" From 02fd181383bfa2403ff39898e95fb0a1c9c42c9f Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 14:10:06 +0000 Subject: [PATCH 51/55] Update Debian base ISO to debian-13.5.0-amd64-netinst.iso --- iso/scripts/generate_dappnode_iso_debian.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index 64fb0a05..75e940ee 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -5,11 +5,11 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.4.0-amd64-netinst.iso -BASE_ISO_NAME="debian-13.4.0-amd64-netinst.iso" +# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.5.0-amd64-netinst.iso +BASE_ISO_NAME="debian-13.5.0-amd64-netinst.iso" BASE_ISO_PATH="/images/${BASE_ISO_NAME}" BASE_ISO_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${BASE_ISO_NAME}" -BASE_ISO_SHASUM="0b813535dd76f2ea96eff908c65e8521512c92a0631fd41c95756ffd7d4896dc ${BASE_ISO_PATH}" +BASE_ISO_SHASUM="95838884f5ea6c82421dfe6baaa5a639dbbe6756c1e380f9fe7a7cb0c1949d2a ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" DAPPNODE_ISO_PATH="/images/${DAPPNODE_ISO_NAME}" From 08f51b36b32182d7bd3ab19313710d30a407c8c7 Mon Sep 17 00:00:00 2001 From: hcastc00 Date: Thu, 11 Jun 2026 16:04:05 +0200 Subject: [PATCH 52/55] fix: generate release changelog from built ISO artifacts --- .github/workflows/release.yml | 62 ++++++++++++++++++++++++++++++++--- README.md | 2 +- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6cd00b7..74ad8bf8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -238,10 +238,64 @@ jobs: mv artifacts/dappnode_profile/* . - name: Write release content run: | - SHASUM_DEBIAN_ATTENDED=$(cat SHASUM_DEBIAN_ATTENDED.txt) - SHASUM_DEBIAN_UNATTENDED=$(cat SHASUM_DEBIAN_UNATTENDED.txt) - SHASUM_UBUNTU_UNATTENDED=$(cat SHASUM_UBUNTU_UNATTENDED.txt) - echo -en "# Versions\n| Package | Version |\n|---|---|\nbind.dnp.dappnode.eth|${{ needs.set-versions.outputs.bind }}|\n|ipfs.dnp.dappnode.eth|${{ needs.set-versions.outputs.ipfs }}|\n|vpn.dnp.dappnode.eth |${{ needs.set-versions.outputs.vpn }}|\n|dappmanager.dnp.dappnode.eth|${{ needs.set-versions.outputs.dappmanager }}|\n|wifi.dnp.dappnode.eth|${{ needs.set-versions.outputs.wifi }}|\n|https.dnp.dappnode.eth|${{ needs.set-versions.outputs.https }}|\n|wireguard.dnp.dappnode.eth|${{ needs.set-versions.outputs.wireguard }}|\n|notifications.dnp.dappnode.eth|${{ needs.set-versions.outputs.notifications }}|\n|premium.dnp.dappnode.eth|${{ needs.set-versions.outputs.premium }}|\n# Changes\nChanges implemented in release ${{ needs.set-versions.outputs.core }}\n# Debian Attended version\nInstall and customize DAppNode using the attended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64.iso\n$SHASUM_DEBIAN_ATTENDED\n```\n# Debian Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso**\nDo a reboot right after the installation\n:warning: **Warning**: This ISO will install Dappnode automatically, deleting all existing partitions on the disk\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-debian-bookworm-amd64-unattended.iso\n$SHASUM_DEBIAN_UNATTENDED\n```\n# Ubuntu Unattended version\nInstall DAppNode easily using the unattended ISO: **DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso**\n\n## ISO SHA-256 Checksum\n```\nshasum -a 256 DAppNode-${{ needs.set-versions.outputs.core }}-ubuntu-bookworm-amd64-unattended.iso\n$SHASUM_UBUNTU_UNATTENDED\n```\nUploaded at https://ubuntu.iso.dappnode.io\n# DAppNode for Raspberry Pi 4 64bit\n[Instructions](https://github.com/dappnode/DAppNode/wiki/DAppNodeARM-Installation-Guide)\n\ndefault login data:\n - **__user__**: dappnode\n - **__password__**: dappnodepi" > CHANGELOG.md + DEBIAN_ATTENDED_ISO=$(basename "$(find images/ -type f -name '*-debian-*-attended.iso' -print -quit)") + DEBIAN_UNATTENDED_ISO=$(basename "$(find images/ -type f -name '*-debian-*-unattended.iso' -print -quit)") + UBUNTU_UNATTENDED_ISO=$(basename "$(awk '{print $2}' SHASUM_UBUNTU_UNATTENDED.txt)") + SHASUM_DEBIAN_ATTENDED=$(sed "s#images/##g" SHASUM_DEBIAN_ATTENDED.txt) + SHASUM_DEBIAN_UNATTENDED=$(sed "s#images/##g" SHASUM_DEBIAN_UNATTENDED.txt) + SHASUM_UBUNTU_UNATTENDED=$(sed "s#images/##g" SHASUM_UBUNTU_UNATTENDED.txt) + cat > CHANGELOG.md < Date: Mon, 20 Jul 2026 10:21:59 +0200 Subject: [PATCH 53/55] Simplify base ISO update workflow --- .github/workflows/update-base-isos.yml | 97 +++++++++++++++----------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/.github/workflows/update-base-isos.yml b/.github/workflows/update-base-isos.yml index 5b260ee5..ffc2bba9 100644 --- a/.github/workflows/update-base-isos.yml +++ b/.github/workflows/update-base-isos.yml @@ -25,18 +25,19 @@ jobs: run: | SCRIPT="iso/scripts/generate_dappnode_iso_ubuntu.sh" - # Get current version from script + # Get the current ISO and checksum from the script CURRENT_ISO=$(grep -oP 'BASE_ISO_NAME=\K.*' "$SCRIPT") + CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^" ]*' "$SCRIPT") echo "Current Ubuntu ISO: $CURRENT_ISO" # Fetch the SHA256SUMS file from Ubuntu releases SHA256SUMS=$(curl -fsSL "https://releases.ubuntu.com/24.04/SHA256SUMS") # Find the latest live-server ISO entry - LATEST_LINE=$(echo "$SHA256SUMS" | grep 'live-server-amd64.iso' | head -1) + LATEST_LINE=$(echo "$SHA256SUMS" | grep 'live-server-amd64.iso' | head -1 || true) if [ -z "$LATEST_LINE" ]; then echo "Could not find live-server ISO in SHA256SUMS" - exit 0 + exit 1 fi LATEST_SHA=$(echo "$LATEST_LINE" | awk '{print $1}') @@ -44,16 +45,22 @@ jobs: # Remove any leading path (e.g., "./" or directory prefix) LATEST_ISO=$(basename "$LATEST_ISO") + if [[ ! "$LATEST_SHA" =~ ^[0-9a-f]{64}$ ]] || + [[ ! "$LATEST_ISO" =~ ^ubuntu-24\.04(\.[0-9]+)?-live-server-amd64\.iso$ ]]; then + echo "Ubuntu SHA256SUMS contains an invalid ISO entry" + exit 1 + fi + echo "Latest Ubuntu ISO: $LATEST_ISO (sha256: $LATEST_SHA)" - if [ "$CURRENT_ISO" = "$LATEST_ISO" ]; then + # Nothing to do only when both the filename and checksum match + if [ "$CURRENT_ISO" = "$LATEST_ISO" ] && [ "$CURRENT_SHA" = "$LATEST_SHA" ]; then echo "Ubuntu ISO is already up to date." echo "updated=false" >> "$GITHUB_OUTPUT" exit 0 fi # Update the script - CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^"]*' "$SCRIPT" | awk '{print $1}') sed -i "s|${CURRENT_ISO}|${LATEST_ISO}|g" "$SCRIPT" sed -i "s|${CURRENT_SHA}|${LATEST_SHA}|" "$SCRIPT" @@ -61,24 +68,14 @@ jobs: echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" - - name: Close outdated Ubuntu ISO PR - if: steps.ubuntu.outputs.updated == 'true' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - EXISTING_PR=$(gh pr list --head auto/update-ubuntu-iso --state open --json number --jq '.[0].number') - if [ -n "$EXISTING_PR" ]; then - gh pr close "$EXISTING_PR" --comment "Superseded by a newer Ubuntu ISO version (${{ steps.ubuntu.outputs.latest_iso }})." --delete-branch - fi - - - name: Create Pull Request for Ubuntu ISO update + - name: Create or update Pull Request for Ubuntu ISO if: steps.ubuntu.outputs.updated == 'true' + id: ubuntu-pr uses: peter-evans/create-pull-request@v7 with: token: ${{ steps.app-token.outputs.token }} commit-message: "Update Ubuntu base ISO to ${{ steps.ubuntu.outputs.latest_iso }}" branch: auto/update-ubuntu-iso - delete-branch: true title: "Update Ubuntu base ISO to ${{ steps.ubuntu.outputs.latest_iso }}" body: | Automated update of the Ubuntu base ISO. @@ -89,6 +86,19 @@ jobs: This PR was created automatically by the `update-base-isos` workflow. labels: automated + - name: Sync PR title and body on subsequent runs + if: steps.ubuntu-pr.outputs.pull-request-operation == 'updated' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PR_NUMBER: ${{ steps.ubuntu-pr.outputs.pull-request-number }} + CURRENT_ISO: ${{ steps.ubuntu.outputs.current_iso }} + LATEST_ISO: ${{ steps.ubuntu.outputs.latest_iso }} + run: | + BODY=$(printf 'Automated update of the Ubuntu base ISO.\n\n- **Previous**: `%s`\n- **New**: `%s`\n\nThis PR was created automatically by the `update-base-isos` workflow.' "$CURRENT_ISO" "$LATEST_ISO") + gh pr edit "$PR_NUMBER" \ + --title "Update Ubuntu base ISO to $LATEST_ISO" \ + --body "$BODY" + update-debian-iso: name: Check for Debian ISO updates runs-on: ubuntu-latest @@ -107,27 +117,35 @@ jobs: run: | SCRIPT="iso/scripts/generate_dappnode_iso_debian.sh" - # Get current version from script + # Get the current ISO and checksum from the script CURRENT_ISO=$(grep -oP 'BASE_ISO_NAME="\K[^"]*' "$SCRIPT") + CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^" ]*' "$SCRIPT") echo "Current Debian ISO: $CURRENT_ISO" # Fetch the SHA256SUMS file from Debian current release SHA256SUMS=$(curl -fsSL "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS") # Find the latest netinst ISO entry - LATEST_LINE=$(echo "$SHA256SUMS" | grep 'amd64-netinst.iso' | head -1) + LATEST_LINE=$(echo "$SHA256SUMS" | grep 'amd64-netinst.iso' | head -1 || true) if [ -z "$LATEST_LINE" ]; then echo "Could not find netinst ISO in SHA256SUMS" - exit 0 + exit 1 fi LATEST_SHA=$(echo "$LATEST_LINE" | awk '{print $1}') LATEST_ISO=$(echo "$LATEST_LINE" | awk '{print $2}' | sed 's|^\*||') LATEST_ISO=$(basename "$LATEST_ISO") + if [[ ! "$LATEST_SHA" =~ ^[0-9a-f]{64}$ ]] || + [[ ! "$LATEST_ISO" =~ ^debian-[0-9]+\.[0-9]+\.[0-9]+-amd64-netinst\.iso$ ]]; then + echo "Debian SHA256SUMS contains an invalid ISO entry" + exit 1 + fi + echo "Latest Debian ISO: $LATEST_ISO (sha256: $LATEST_SHA)" - if [ "$CURRENT_ISO" = "$LATEST_ISO" ]; then + # Nothing to do only when both the filename and checksum match + if [ "$CURRENT_ISO" = "$LATEST_ISO" ] && [ "$CURRENT_SHA" = "$LATEST_SHA" ]; then echo "Debian ISO is already up to date." echo "updated=false" >> "$GITHUB_OUTPUT" exit 0 @@ -136,46 +154,30 @@ jobs: # Extract version numbers for URL update CURRENT_VERSION=$(echo "$CURRENT_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') LATEST_VERSION=$(echo "$LATEST_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') + CURRENT_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1) + LATEST_MAJOR=$(echo "$LATEST_VERSION" | cut -d. -f1) # Update the script - CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^ ]*' "$SCRIPT") sed -i "s|${CURRENT_ISO}|${LATEST_ISO}|g" "$SCRIPT" sed -i "s|${CURRENT_SHA}|${LATEST_SHA}|" "$SCRIPT" - - # Update the source comment and URL if the major version changed - CURRENT_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1) - LATEST_MAJOR=$(echo "$LATEST_VERSION" | cut -d. -f1) - if [ "$CURRENT_MAJOR" != "$LATEST_MAJOR" ]; then # If major version changes, update any archive URL to current sed -i "s|cdimage.debian.org/mirror/cdimage/archive/${CURRENT_VERSION}|cdimage.debian.org/debian-cd/current|" "$SCRIPT" fi - - # Update version in the source comment sed -i "s|${CURRENT_VERSION}|${LATEST_VERSION}|g" "$SCRIPT" echo "updated=true" >> "$GITHUB_OUTPUT" echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" echo "latest_iso=$LATEST_ISO" >> "$GITHUB_OUTPUT" - - name: Close outdated Debian ISO PR - if: steps.debian.outputs.updated == 'true' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - EXISTING_PR=$(gh pr list --head auto/update-debian-iso --state open --json number --jq '.[0].number') - if [ -n "$EXISTING_PR" ]; then - gh pr close "$EXISTING_PR" --comment "Superseded by a newer Debian ISO version (${{ steps.debian.outputs.latest_iso }})." --delete-branch - fi - - - name: Create Pull Request for Debian ISO update + - name: Create or update Pull Request for Debian ISO if: steps.debian.outputs.updated == 'true' + id: debian-pr uses: peter-evans/create-pull-request@v7 with: token: ${{ steps.app-token.outputs.token }} commit-message: "Update Debian base ISO to ${{ steps.debian.outputs.latest_iso }}" branch: auto/update-debian-iso - delete-branch: true title: "Update Debian base ISO to ${{ steps.debian.outputs.latest_iso }}" body: | Automated update of the Debian base ISO. @@ -185,3 +187,16 @@ jobs: This PR was created automatically by the `update-base-isos` workflow. labels: automated + + - name: Sync PR title and body on subsequent runs + if: steps.debian-pr.outputs.pull-request-operation == 'updated' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PR_NUMBER: ${{ steps.debian-pr.outputs.pull-request-number }} + CURRENT_ISO: ${{ steps.debian.outputs.current_iso }} + LATEST_ISO: ${{ steps.debian.outputs.latest_iso }} + run: | + BODY=$(printf 'Automated update of the Debian base ISO.\n\n- **Previous**: `%s`\n- **New**: `%s`\n\nThis PR was created automatically by the `update-base-isos` workflow.' "$CURRENT_ISO" "$LATEST_ISO") + gh pr edit "$PR_NUMBER" \ + --title "Update Debian base ISO to $LATEST_ISO" \ + --body "$BODY" From 0848c1bed80c40dd68e774bd92f3dde8147ef2b7 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:00:10 +0200 Subject: [PATCH 54/55] Make ISO updates version independent --- .github/workflows/update-base-isos.yml | 37 +++++++++++---------- iso/scripts/generate_dappnode_iso_debian.sh | 5 +-- iso/scripts/generate_dappnode_iso_ubuntu.sh | 5 ++- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/.github/workflows/update-base-isos.yml b/.github/workflows/update-base-isos.yml index ffc2bba9..8d355fa0 100644 --- a/.github/workflows/update-base-isos.yml +++ b/.github/workflows/update-base-isos.yml @@ -30,11 +30,21 @@ jobs: CURRENT_SHA=$(grep -oP 'BASE_ISO_SHASUM="\K[^" ]*' "$SCRIPT") echo "Current Ubuntu ISO: $CURRENT_ISO" - # Fetch the SHA256SUMS file from Ubuntu releases - SHA256SUMS=$(curl -fsSL "https://releases.ubuntu.com/24.04/SHA256SUMS") + # Discover the newest Ubuntu LTS series, then fetch its checksums + LATEST_LTS_VERSION=$(curl -fsSL "https://changelogs.ubuntu.com/meta-release-lts" | + awk '/^Version:/ { version=$2 } END { print version }') + LATEST_LTS_SERIES=$(echo "$LATEST_LTS_VERSION" | cut -d. -f1,2) + if [[ ! "$LATEST_LTS_SERIES" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo "Could not determine the latest Ubuntu LTS series" + exit 1 + fi + + SHA256SUMS=$(curl -fsSL "https://releases.ubuntu.com/${LATEST_LTS_SERIES}/SHA256SUMS") - # Find the latest live-server ISO entry - LATEST_LINE=$(echo "$SHA256SUMS" | grep 'live-server-amd64.iso' | head -1 || true) + # Find the highest live-server point release in that LTS series + LATEST_LINE=$(echo "$SHA256SUMS" | + grep -E "[[:space:]]\\*?ubuntu-${LATEST_LTS_SERIES//./\\.}(\\.[0-9]+)?-live-server-amd64\\.iso$" | + sort -V -k2 | tail -1 || true) if [ -z "$LATEST_LINE" ]; then echo "Could not find live-server ISO in SHA256SUMS" exit 1 @@ -46,7 +56,7 @@ jobs: LATEST_ISO=$(basename "$LATEST_ISO") if [[ ! "$LATEST_SHA" =~ ^[0-9a-f]{64}$ ]] || - [[ ! "$LATEST_ISO" =~ ^ubuntu-24\.04(\.[0-9]+)?-live-server-amd64\.iso$ ]]; then + [[ ! "$LATEST_ISO" =~ ^ubuntu-[0-9]+\.[0-9]+(\.[0-9]+)?-live-server-amd64\.iso$ ]]; then echo "Ubuntu SHA256SUMS contains an invalid ISO entry" exit 1 fi @@ -125,8 +135,10 @@ jobs: # Fetch the SHA256SUMS file from Debian current release SHA256SUMS=$(curl -fsSL "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS") - # Find the latest netinst ISO entry - LATEST_LINE=$(echo "$SHA256SUMS" | grep 'amd64-netinst.iso' | head -1 || true) + # Find the standard netinst ISO, excluding the Edu and Mac variants + LATEST_LINE=$(echo "$SHA256SUMS" | + grep -E '[[:space:]]\*?debian-[0-9]+\.[0-9]+\.[0-9]+-amd64-netinst\.iso$' | + sort -V -k2 | tail -1 || true) if [ -z "$LATEST_LINE" ]; then echo "Could not find netinst ISO in SHA256SUMS" exit 1 @@ -151,20 +163,9 @@ jobs: exit 0 fi - # Extract version numbers for URL update - CURRENT_VERSION=$(echo "$CURRENT_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') - LATEST_VERSION=$(echo "$LATEST_ISO" | grep -oP 'debian-\K[0-9]+\.[0-9]+\.[0-9]+') - CURRENT_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1) - LATEST_MAJOR=$(echo "$LATEST_VERSION" | cut -d. -f1) - # Update the script sed -i "s|${CURRENT_ISO}|${LATEST_ISO}|g" "$SCRIPT" sed -i "s|${CURRENT_SHA}|${LATEST_SHA}|" "$SCRIPT" - if [ "$CURRENT_MAJOR" != "$LATEST_MAJOR" ]; then - # If major version changes, update any archive URL to current - sed -i "s|cdimage.debian.org/mirror/cdimage/archive/${CURRENT_VERSION}|cdimage.debian.org/debian-cd/current|" "$SCRIPT" - fi - sed -i "s|${CURRENT_VERSION}|${LATEST_VERSION}|g" "$SCRIPT" echo "updated=true" >> "$GITHUB_OUTPUT" echo "current_iso=$CURRENT_ISO" >> "$GITHUB_OUTPUT" diff --git a/iso/scripts/generate_dappnode_iso_debian.sh b/iso/scripts/generate_dappnode_iso_debian.sh index 75e940ee..4ec4a93d 100755 --- a/iso/scripts/generate_dappnode_iso_debian.sh +++ b/iso/scripts/generate_dappnode_iso_debian.sh @@ -5,10 +5,11 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh -# Source = https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.5.0-amd64-netinst.iso BASE_ISO_NAME="debian-13.5.0-amd64-netinst.iso" +BASE_ISO_VERSION="${BASE_ISO_NAME#debian-}" +BASE_ISO_VERSION="${BASE_ISO_VERSION%-amd64-netinst.iso}" BASE_ISO_PATH="/images/${BASE_ISO_NAME}" -BASE_ISO_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${BASE_ISO_NAME}" +BASE_ISO_URL="https://cdimage.debian.org/mirror/cdimage/archive/${BASE_ISO_VERSION}/amd64/iso-cd/${BASE_ISO_NAME}" BASE_ISO_SHASUM="95838884f5ea6c82421dfe6baaa5a639dbbe6756c1e380f9fe7a7cb0c1949d2a ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" diff --git a/iso/scripts/generate_dappnode_iso_ubuntu.sh b/iso/scripts/generate_dappnode_iso_ubuntu.sh index c1c1a270..efd0f3fa 100755 --- a/iso/scripts/generate_dappnode_iso_ubuntu.sh +++ b/iso/scripts/generate_dappnode_iso_ubuntu.sh @@ -6,8 +6,11 @@ SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") source ${SCRIPTS_DIR}/common_iso_generation.sh BASE_ISO_NAME=ubuntu-24.04.3-live-server-amd64.iso +BASE_ISO_VERSION="${BASE_ISO_NAME#ubuntu-}" +BASE_ISO_VERSION="${BASE_ISO_VERSION%-live-server-amd64.iso}" +BASE_ISO_SERIES=$(echo "$BASE_ISO_VERSION" | cut -d. -f1,2) BASE_ISO_PATH="/images/${BASE_ISO_NAME}" -BASE_ISO_URL="https://releases.ubuntu.com/24.04/${BASE_ISO_NAME}" +BASE_ISO_URL="https://releases.ubuntu.com/${BASE_ISO_SERIES}/${BASE_ISO_NAME}" BASE_ISO_SHASUM="c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b ${BASE_ISO_PATH}" DAPPNODE_ISO_NAME="${DAPPNODE_ISO_PREFIX}${BASE_ISO_NAME}" From 25ce162126bd5236fa95d67ad13a6496c3e3fdc3 Mon Sep 17 00:00:00 2001 From: Marketen Date: Thu, 20 Aug 2026 10:28:03 +0200 Subject: [PATCH 55/55] use trixie --- iso/preseeds/preseed.cfg | 4 ++-- iso/preseeds/preseed_unattended.cfg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iso/preseeds/preseed.cfg b/iso/preseeds/preseed.cfg index 761f5075..1bd38005 100644 --- a/iso/preseeds/preseed.cfg +++ b/iso/preseeds/preseed.cfg @@ -1,7 +1,7 @@ # Preseed-example: https://www.debian.org/releases/stable/example-preseed.txt # Buster preseed example: https://www.debian.org/releases/buster/example-preseed.txt # Bullseye preseed example: https://www.debian.org/releases/testing/example-preseed.txt -# Bookworm preseed example: https://www.debian.org/releases/bookworm/example-preseed.txt +# Trixie preseed example: https://www.debian.org/releases/trixie/example-preseed.txt ### Network configuration d-i hw-detect/load_firmware boolean true d-i netcfg/choose_interface select auto @@ -25,7 +25,7 @@ d-i mirror/country string manual d-i mirror/http/hostname string deb.debian.org d-i mirror/http/directory string /debian d-i mirror/http/proxy string -d-i apt-setup/local0/repository string http://deb.debian.org/debian/ bookworm main contrib non-free-firmware +d-i apt-setup/local0/repository string http://deb.debian.org/debian/ trixie main contrib non-free-firmware d-i apt-setup/cdrom/set-first boolean false d-i apt-setup/cdrom/set-next boolean false d-i apt-setup/cdrom/set-failed boolean false diff --git a/iso/preseeds/preseed_unattended.cfg b/iso/preseeds/preseed_unattended.cfg index cf7b58d4..8316fd7c 100644 --- a/iso/preseeds/preseed_unattended.cfg +++ b/iso/preseeds/preseed_unattended.cfg @@ -1,7 +1,7 @@ # Preseed-example: https://www.debian.org/releases/stable/example-preseed.txt # Buster preseed example: https://www.debian.org/releases/buster/example-preseed.txt # Bullseye preseed example: https://www.debian.org/releases/testing/example-preseed.txt -# Bookworm preseed example: https://www.debian.org/releases/bookworm/example-preseed.txt +# Trixie preseed example: https://www.debian.org/releases/trixie/example-preseed.txt ### Localization d-i debian-installer/locale string en_US.UTF-8 d-i debian-installer/keymap select us @@ -62,7 +62,7 @@ d-i mirror/country string manual d-i mirror/http/hostname string deb.debian.org d-i mirror/http/directory string /debian d-i mirror/http/proxy string -d-i apt-setup/local0/repository string http://deb.debian.org/debian/ bookworm main contrib non-free-firmware +d-i apt-setup/local0/repository string http://deb.debian.org/debian/ trixie main contrib non-free-firmware d-i apt-setup/cdrom/set-first boolean false d-i apt-setup/cdrom/set-next boolean false d-i apt-setup/cdrom/set-failed boolean false