From 87be717f40b9d8f71ddaa1449dcf33ddd9d27c1a Mon Sep 17 00:00:00 2001 From: archipelago Date: Tue, 19 May 2026 14:29:20 -0400 Subject: [PATCH] fix(apps): keep slow installs visible --- CHANGELOG.md | 11 +++++++++++ app-catalog/catalog.json | 17 +++++++++++++++++ core/archipelago/src/api/rpc/package/config.rs | 6 ++++-- core/archipelago/src/api/rpc/package/install.rs | 5 +++++ .../src/container/docker_packages.rs | 9 ++++++++- .../archipelago/src/container/image_versions.rs | 1 + .../_archived/build-auto-installer-iso.sh | 1 + .../archipelago-scripts/install-to-disk.sh | 1 + .../public/assets/img/app-icons/netbird.svg | 12 ++++++++++++ neode-ui/public/catalog.json | 17 +++++++++++++++++ neode-ui/src/api/rpc-client.ts | 3 +-- neode-ui/src/views/Apps.vue | 2 +- neode-ui/src/views/Discover.vue | 6 +++--- neode-ui/src/views/Marketplace.vue | 4 ++-- neode-ui/src/views/MarketplaceAppDetails.vue | 4 ++-- neode-ui/src/views/appDetails/appDetailsData.ts | 1 + neode-ui/src/views/apps/AppCard.vue | 2 +- neode-ui/src/views/apps/appsConfig.ts | 4 ++-- neode-ui/src/views/discover/curatedApps.ts | 4 +++- .../src/views/marketplace/marketplaceData.ts | 16 ++++++++++++++-- scripts/image-versions.sh | 1 + scripts/self-update.sh | 9 +++++++++ 22 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 neode-ui/public/assets/img/app-icons/netbird.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index a3417ac6..5780a258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.7.69-alpha (2026-05-19) + +- App installs now allow up to 10 minutes for the initial `package.install` RPC to return, matching slow container image pulls and preventing apps from disappearing from My Apps while the backend is still pulling or retrying mirrors. +- Live diagnostics on `100.70.96.88` confirmed the Gitea install did not fail; the primary registry pull timed out after 300 seconds, the fallback mirror succeeded, and Gitea came up healthy on `3001` while the frontend had already timed out at 15 seconds. +- Gitea and other Docker-image app installs now stay visible during slow registry pulls instead of being marked as failed by the browser before backend install progress can complete. +- Gitea is now categorized as a known Data app in My Apps, so a running Gitea container appears with installed apps instead of being filtered into the Websites/Services split. +- NetBird `0.71.2` is now available in the app catalog and fallback marketplace data as a recommended networking app using the official `docker.io/netbirdio/netbird:0.71.2` image. +- NetBird installs get persistent state under `/var/lib/archipelago/netbird`, `NET_ADMIN`/`NET_RAW`, `/dev/net/tun`, `slirp4netns`, image-version pinning, backend metadata, and health checks through `netbird status`. +- The Archipelago terminal now includes `nano` on new disk installs and ISO builds, and self-update installs it on existing nodes if it is missing. +- Validation passed with catalog JSON checks, shell syntax checks, `npm run type-check`, `cargo fmt --all --check --manifest-path core/Cargo.toml`, and `cargo check -p archipelago --manifest-path core/Cargo.toml`. + ## v1.7.68-alpha (2026-05-19) - BTCPay Server now ships on the official `docker.io/btcpayserver/btcpayserver:2.3.9` image, fixing the plugin catalog crash caused by newer plugin dependency version metadata while preserving existing datadirs and Postgres databases. diff --git a/app-catalog/catalog.json b/app-catalog/catalog.json index 61904087..6f29dc99 100644 --- a/app-catalog/catalog.json +++ b/app-catalog/catalog.json @@ -275,6 +275,23 @@ "args": ["sh", "-c", "tailscaled --tun=userspace-networking & sleep 2; tailscale web --listen 0.0.0.0:8240 & wait"] } }, + { + "id": "netbird", + "title": "NetBird", + "version": "0.71.2", + "description": "WireGuard mesh VPN client for secure remote access through NetBird Cloud or a self-hosted management server.", + "icon": "/assets/img/app-icons/netbird.svg", + "author": "NetBird", + "category": "networking", + "tier": "recommended", + "dockerImage": "docker.io/netbirdio/netbird:0.71.2", + "repoUrl": "https://github.com/netbirdio/netbird", + "containerConfig": { + "volumes": ["/var/lib/archipelago/netbird:/var/lib/netbird"], + "env": ["NB_SETUP_KEY=", "NB_MANAGEMENT_URL="], + "args": ["up"] + } + }, { "id": "uptime-kuma", "title": "Uptime Kuma", diff --git a/core/archipelago/src/api/rpc/package/config.rs b/core/archipelago/src/api/rpc/package/config.rs index cbc25897..5aaa7b93 100644 --- a/core/archipelago/src/api/rpc/package/config.rs +++ b/core/archipelago/src/api/rpc/package/config.rs @@ -217,9 +217,9 @@ pub(super) fn get_app_capabilities(app_id: &str) -> Vec { "--cap-add=DAC_OVERRIDE".to_string(), "--cap-add=NET_BIND_SERVICE".to_string(), ], - // Nostr VPN and FIPS: mesh networking daemons need TUN + NET_ADMIN + // VPN/mesh daemons need TUN + NET_ADMIN. // Note: --device=/dev/net/tun is added separately in install.rs - "nostr-vpn" | "fips" => vec![ + "nostr-vpn" | "fips" | "netbird" => vec![ "--cap-add=NET_ADMIN".to_string(), "--cap-add=NET_RAW".to_string(), ], @@ -329,6 +329,7 @@ pub(super) fn get_health_check_args(app_id: &str, _rpc_pass: &str) -> Vec ("nvpn status || exit 1", "30s", "3"), + "netbird" => ("netbird status || exit 1", "30s", "3"), "fips" => ("fipsctl status || exit 1", "30s", "3"), _ => return vec![], }; @@ -389,6 +390,7 @@ pub(super) fn get_memory_limit(app_id: &str) -> &'static str { "nostr-rs-relay" | "nostr-relay" => "256m", "routstr" => "512m", "nostr-vpn" => "256m", + "netbird" => "256m", "fips" => "256m", "nginx-proxy-manager" => "256m", // Databases diff --git a/core/archipelago/src/api/rpc/package/install.rs b/core/archipelago/src/api/rpc/package/install.rs index 6dece47e..e95901ba 100644 --- a/core/archipelago/src/api/rpc/package/install.rs +++ b/core/archipelago/src/api/rpc/package/install.rs @@ -552,6 +552,7 @@ impl RpcHandler { "uptime-kuma" | "gitea" | "tailscale" + | "netbird" | "vaultwarden" | "homeassistant" | "home-assistant" @@ -626,6 +627,10 @@ impl RpcHandler { run_args.push("--tmpfs=/tmp:rw,exec,size=256m"); } + if package_id == "netbird" { + run_args.push("--device=/dev/net/tun:/dev/net/tun"); + } + // Create data directories (mkdir only — chown happens AFTER config files are written) for volume in &volumes { if let Some(host_path) = volume.split(':').next() { diff --git a/core/archipelago/src/container/docker_packages.rs b/core/archipelago/src/container/docker_packages.rs index 8bba3618..5ccad96d 100644 --- a/core/archipelago/src/container/docker_packages.rs +++ b/core/archipelago/src/container/docker_packages.rs @@ -281,7 +281,7 @@ fn get_app_tier(app_id: &str) -> &'static str { "uptime-kuma" => "recommended", "grafana" => "recommended", "searxng" => "recommended", - "tailscale" => "recommended", + "tailscale" | "netbird" => "recommended", "portainer" => "recommended", // Optional: everything else _ => "optional", @@ -479,6 +479,13 @@ fn get_app_metadata(app_id: &str) -> AppMetadata { repo: "https://github.com/tailscale/tailscale".to_string(), tier: "", }, + "netbird" => AppMetadata { + title: "NetBird".to_string(), + description: "WireGuard mesh VPN client for secure remote access".to_string(), + icon: "/assets/img/app-icons/netbird.svg".to_string(), + repo: "https://github.com/netbirdio/netbird".to_string(), + tier: "", + }, "indeedhub" | "indeehub" => AppMetadata { title: "IndeedHub".to_string(), description: "Decentralized media streaming platform".to_string(), diff --git a/core/archipelago/src/container/image_versions.rs b/core/archipelago/src/container/image_versions.rs index 27826d0d..8f6bbb9c 100644 --- a/core/archipelago/src/container/image_versions.rs +++ b/core/archipelago/src/container/image_versions.rs @@ -168,6 +168,7 @@ fn image_var_for_app(app_id: &str) -> Option<&'static str> { "nginx-proxy-manager" => Some("NPM_IMAGE"), "portainer" => Some("PORTAINER_IMAGE"), "tailscale" => Some("TAILSCALE_IMAGE"), + "netbird" => Some("NETBIRD_IMAGE"), // Fedimint "fedimint" | "fedimintd" => Some("FEDIMINT_IMAGE"), diff --git a/image-recipe/_archived/build-auto-installer-iso.sh b/image-recipe/_archived/build-auto-installer-iso.sh index f1e8efcf..f05d37c4 100755 --- a/image-recipe/_archived/build-auto-installer-iso.sh +++ b/image-recipe/_archived/build-auto-installer-iso.sh @@ -337,6 +337,7 @@ RUN apt-get update && apt-get -y full-upgrade && apt-get install -y --no-install curl \ git \ vim-tiny \ + nano \ ca-certificates \ openssl \ chrony \ diff --git a/image-recipe/archipelago-scripts/install-to-disk.sh b/image-recipe/archipelago-scripts/install-to-disk.sh index 0aef2524..9fdc26d4 100755 --- a/image-recipe/archipelago-scripts/install-to-disk.sh +++ b/image-recipe/archipelago-scripts/install-to-disk.sh @@ -179,6 +179,7 @@ chroot /mnt/archipelago apt-get install -y \ wget \ htop \ vim-tiny \ + nano \ ca-certificates \ chrony diff --git a/neode-ui/public/assets/img/app-icons/netbird.svg b/neode-ui/public/assets/img/app-icons/netbird.svg new file mode 100644 index 00000000..7323ced4 --- /dev/null +++ b/neode-ui/public/assets/img/app-icons/netbird.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/neode-ui/public/catalog.json b/neode-ui/public/catalog.json index 61904087..6f29dc99 100644 --- a/neode-ui/public/catalog.json +++ b/neode-ui/public/catalog.json @@ -275,6 +275,23 @@ "args": ["sh", "-c", "tailscaled --tun=userspace-networking & sleep 2; tailscale web --listen 0.0.0.0:8240 & wait"] } }, + { + "id": "netbird", + "title": "NetBird", + "version": "0.71.2", + "description": "WireGuard mesh VPN client for secure remote access through NetBird Cloud or a self-hosted management server.", + "icon": "/assets/img/app-icons/netbird.svg", + "author": "NetBird", + "category": "networking", + "tier": "recommended", + "dockerImage": "docker.io/netbirdio/netbird:0.71.2", + "repoUrl": "https://github.com/netbirdio/netbird", + "containerConfig": { + "volumes": ["/var/lib/archipelago/netbird:/var/lib/netbird"], + "env": ["NB_SETUP_KEY=", "NB_MANAGEMENT_URL="], + "args": ["up"] + } + }, { "id": "uptime-kuma", "title": "Uptime Kuma", diff --git a/neode-ui/src/api/rpc-client.ts b/neode-ui/src/api/rpc-client.ts index 0aadf022..27442ff5 100644 --- a/neode-ui/src/api/rpc-client.ts +++ b/neode-ui/src/api/rpc-client.ts @@ -532,7 +532,7 @@ class RPCClient { return this.call({ method: 'package.install', params: { id, 'marketplace-url': marketplaceUrl, version }, - timeout: 15000, + timeout: 600000, }) } @@ -940,4 +940,3 @@ class RPCClient { } export const rpcClient = new RPCClient() - diff --git a/neode-ui/src/views/Apps.vue b/neode-ui/src/views/Apps.vue index 51ee2f6f..a7a4bd75 100644 --- a/neode-ui/src/views/Apps.vue +++ b/neode-ui/src/views/Apps.vue @@ -464,7 +464,7 @@ async function submitSideload() { version: 'sideload', containerConfig, }, - timeout: 15000, + timeout: 600000, }) closeSideload() sideloadForm.value = { id: '', image: '', title: '', port: '', description: '' } diff --git a/neode-ui/src/views/Discover.vue b/neode-ui/src/views/Discover.vue index 7809d29f..3554ad85 100644 --- a/neode-ui/src/views/Discover.vue +++ b/neode-ui/src/views/Discover.vue @@ -383,7 +383,7 @@ function isStartingUp(appId: string): boolean { function getAppTier(appId: string): string { const core = ['bitcoin-knots', 'bitcoin', 'lnd', 'mempool', 'btcpay-server', 'dwn', 'filebrowser'] - const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'portainer'] + const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'netbird', 'portainer'] if (core.includes(appId)) return 'core' if (recommended.includes(appId)) return 'recommended' return 'optional' @@ -487,7 +487,7 @@ async function installApp(app: MarketplaceApp) { router.push('/dashboard/apps').catch(() => {}) try { const installUrl = app.url || app.manifestUrl || app.s9pkUrl - await rpcClient.call({ method: 'package.install', params: { id: app.id, url: installUrl, version: app.version }, timeout: 15000 }) + await rpcClient.call({ method: 'package.install', params: { id: app.id, url: installUrl, version: app.version }, timeout: 600000 }) } catch (err) { if (import.meta.env.DEV) console.error('Installation failed:', err) failInstall(app, err) @@ -504,7 +504,7 @@ async function installCommunityApp(app: MarketplaceApp) { if ((app as Record).containerConfig) { installParams.containerConfig = (app as Record).containerConfig } - await rpcClient.call({ method: 'package.install', params: installParams, timeout: 15000 }) + await rpcClient.call({ method: 'package.install', params: installParams, timeout: 600000 }) } catch (err) { if (import.meta.env.DEV) console.error('[Discover] Installation failed:', err) failInstall(app, err) diff --git a/neode-ui/src/views/Marketplace.vue b/neode-ui/src/views/Marketplace.vue index 98045a27..6ccc4932 100644 --- a/neode-ui/src/views/Marketplace.vue +++ b/neode-ui/src/views/Marketplace.vue @@ -415,7 +415,7 @@ async function installApp(app: MarketplaceApp) { await rpcClient.call({ method: 'package.install', params: { id: app.id, url: installUrl, version: app.version }, - timeout: 15000, + timeout: 600000, }) } catch (err) { if (import.meta.env.DEV) console.error('Installation failed:', err) @@ -441,7 +441,7 @@ async function installCommunityApp(app: MarketplaceApp) { await rpcClient.call({ method: 'package.install', params: installParams, - timeout: 15000, + timeout: 600000, }) } catch (err) { if (import.meta.env.DEV) console.error('[Marketplace] Installation failed:', err) diff --git a/neode-ui/src/views/MarketplaceAppDetails.vue b/neode-ui/src/views/MarketplaceAppDetails.vue index 7a5a856a..aa860f84 100644 --- a/neode-ui/src/views/MarketplaceAppDetails.vue +++ b/neode-ui/src/views/MarketplaceAppDetails.vue @@ -616,7 +616,7 @@ async function installApp() { await rpcClient.call({ method: 'package.install', params: installParams, - timeout: 15000, + timeout: 600000, }) } else { // Package-based installation @@ -628,7 +628,7 @@ async function installApp() { url: installUrl, version: app.value.version, }, - timeout: 15000, + timeout: 600000, }) } diff --git a/neode-ui/src/views/appDetails/appDetailsData.ts b/neode-ui/src/views/appDetails/appDetailsData.ts index a3b8a32d..8712ae9e 100644 --- a/neode-ui/src/views/appDetails/appDetailsData.ts +++ b/neode-ui/src/views/appDetails/appDetailsData.ts @@ -44,6 +44,7 @@ export const ROUTE_TO_PACKAGE_KEY: Record = { portainer: 'portainer', 'uptime-kuma': 'uptime-kuma', tailscale: 'tailscale', + netbird: 'netbird', } /** Backend may register under variant container names */ diff --git a/neode-ui/src/views/apps/AppCard.vue b/neode-ui/src/views/apps/AppCard.vue index 40a99fb3..c962fe89 100644 --- a/neode-ui/src/views/apps/AppCard.vue +++ b/neode-ui/src/views/apps/AppCard.vue @@ -266,7 +266,7 @@ const tier = computed(() => { const t = props.pkg.manifest?.tier if (t && t !== '') return t const core = ['bitcoin-knots', 'bitcoin', 'lnd', 'mempool', 'btcpay-server', 'dwn', 'filebrowser'] - const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'portainer'] + const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'netbird', 'portainer'] if (core.includes(props.id)) return 'core' if (recommended.includes(props.id)) return 'recommended' return 'optional' diff --git a/neode-ui/src/views/apps/appsConfig.ts b/neode-ui/src/views/apps/appsConfig.ts index 334336b4..88997022 100644 --- a/neode-ui/src/views/apps/appsConfig.ts +++ b/neode-ui/src/views/apps/appsConfig.ts @@ -55,9 +55,9 @@ export const APP_CATEGORY_MAP: Record = { 'indeedhub': 'media', 'jellyfin': 'media', 'photoprism': 'media', 'immich': 'media', 'nextcloud': 'data', 'vaultwarden': 'data', 'filebrowser': 'data', 'cryptpad': 'data', 'homeassistant': 'home', 'lorabell': 'home', 'endurain': 'home', - 'searxng': 'community', 'ollama': 'community', 'grafana': 'data', + 'searxng': 'community', 'ollama': 'community', 'grafana': 'data', 'gitea': 'data', 'nostrudel': 'nostr', - 'tailscale': 'networking', 'nginx-proxy-manager': 'networking', 'portainer': 'networking', + 'tailscale': 'networking', 'netbird': 'networking', 'nginx-proxy-manager': 'networking', 'portainer': 'networking', 'uptime-kuma': 'networking', 'dwn': 'data', 'botfights': 'community', 'nwnn': 'l484', '484-kitchen': 'l484', 'call-the-operator': 'l484', 'syntropy-institute': 'l484', 't-zero': 'l484', diff --git a/neode-ui/src/views/discover/curatedApps.ts b/neode-ui/src/views/discover/curatedApps.ts index ffb1cac4..5de587e5 100644 --- a/neode-ui/src/views/discover/curatedApps.ts +++ b/neode-ui/src/views/discover/curatedApps.ts @@ -96,6 +96,7 @@ export function getCuratedAppList(): MarketplaceApp[] { { id: 'portainer', title: 'Portainer', version: '2.19.4', description: 'Container management UI. Manage your containerized services through the web.', icon: '/assets/img/app-icons/portainer.webp', author: 'Portainer', dockerImage: `${R}/portainer:latest`, repoUrl: 'https://github.com/portainer/portainer' }, { id: 'uptime-kuma', title: 'Uptime Kuma', version: '1.23.0', description: 'Self-hosted uptime monitoring. Track HTTP, TCP, DNS, and more.', icon: '/assets/img/app-icons/uptime-kuma.webp', author: 'Uptime Kuma', dockerImage: `${R}/uptime-kuma:1`, repoUrl: 'https://github.com/louislam/uptime-kuma' }, { id: 'tailscale', title: 'Tailscale', version: '1.78.0', description: 'Zero-config VPN. Secure remote access with WireGuard mesh networking.', icon: '/assets/img/app-icons/tailscale.webp', author: 'Tailscale', dockerImage: `${R}/tailscale:stable`, repoUrl: 'https://github.com/tailscale/tailscale' }, + { id: 'netbird', title: 'NetBird', version: '0.71.2', description: 'WireGuard mesh VPN client. Connect this node through NetBird Cloud or your own NetBird management server.', icon: '/assets/img/app-icons/netbird.svg', author: 'NetBird', dockerImage: 'docker.io/netbirdio/netbird:0.71.2', repoUrl: 'https://github.com/netbirdio/netbird' }, { id: 'electrumx', title: 'ElectrumX', version: '1.18.0', description: 'Electrum protocol server. Index the blockchain for fast wallet lookups, privately.', icon: '/assets/img/app-icons/electrumx.png', author: 'Luke Childs', dockerImage: `${R}/electrumx:v1.18.0`, repoUrl: 'https://github.com/spesmilo/electrumx' }, { id: 'fedimint', title: 'Fedimint', version: '0.10.0', description: 'Federated Bitcoin mint. Private, scalable Bitcoin through federated guardians.', icon: '/assets/img/app-icons/fedimint.png', author: 'Fedimint', dockerImage: `${R}/fedimintd:v0.10.0`, repoUrl: 'https://github.com/fedimint/fedimint' }, { id: 'indeedhub', title: 'Indeehub', version: '1.0.0', description: 'Bitcoin documentary streaming with Nostr identity. Stream sovereignty content.', icon: '/assets/img/app-icons/indeedhub.png', author: 'Indeehub Team', dockerImage: `${R}/indeedhub:1.0.0`, repoUrl: 'https://github.com/indeedhub/indeedhub' }, @@ -132,6 +133,7 @@ export const INSTALLED_ALIASES: Record = { lnd: ['lnd'], filebrowser: ['filebrowser'], tailscale: ['tailscale'], + netbird: ['netbird'], ollama: ['ollama'], indeedhub: ['indeedhub'], botfights: ['botfights'], @@ -191,7 +193,7 @@ export function categorizeCommunityApp(app: MarketplaceApp): string { if (id.includes('cloud') || id.includes('nextcloud') || id.includes('storage') || id.includes('file') || id.includes('photo') || id.includes('immich') || id.includes('jellyfin') || id.includes('media') || id.includes('vault') || combined.includes('password manager')) return 'data' if (id.includes('home-assistant') || id.includes('homeassistant') || combined.includes('home automation')) return 'home' if (id.includes('nostr') || combined.includes('nostr relay')) return 'nostr' - if (id.includes('vpn') || id.includes('wireguard') || id.includes('tailscale') || id.includes('proxy') || id.includes('dns') || id.includes('tor') || combined.includes('network')) return 'networking' + if (id.includes('vpn') || id.includes('wireguard') || id.includes('tailscale') || id.includes('netbird') || id.includes('proxy') || id.includes('dns') || id.includes('tor') || combined.includes('network')) return 'networking' if (id.includes('matrix') || id.includes('mastodon') || id.includes('chat') || id.includes('social') || combined.includes('messaging')) return 'community' return 'other' } diff --git a/neode-ui/src/views/marketplace/marketplaceData.ts b/neode-ui/src/views/marketplace/marketplaceData.ts index 4f766341..98f9b482 100644 --- a/neode-ui/src/views/marketplace/marketplaceData.ts +++ b/neode-ui/src/views/marketplace/marketplaceData.ts @@ -60,13 +60,14 @@ export const INSTALLED_ALIASES: Record = { lnd: ['lnd', 'archy-lnd-ui'], filebrowser: ['filebrowser'], tailscale: ['tailscale'], + netbird: ['netbird'], ollama: ['ollama'], } /** Get app tier classification (matches backend get_app_tier) */ export function getAppTier(appId: string): string { const core = ['bitcoin-knots', 'bitcoin', 'lnd', 'mempool', 'btcpay-server', 'dwn', 'filebrowser'] - const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'portainer'] + const recommended = ['fedimint', 'thunderhub', 'vaultwarden', 'uptime-kuma', 'grafana', 'searxng', 'tailscale', 'netbird', 'portainer'] if (core.includes(appId)) return 'core' if (recommended.includes(appId)) return 'recommended' return 'optional' @@ -113,7 +114,7 @@ export function categorizeCommunityApp(app: MarketplaceApp): string { return 'nostr' } - if (id.includes('vpn') || id.includes('wireguard') || id.includes('tailscale') || + if (id.includes('vpn') || id.includes('wireguard') || id.includes('tailscale') || id.includes('netbird') || id.includes('proxy') || id.includes('dns') || id.includes('pihole') || id.includes('adguard') || id.includes('nginx') || id.includes('tor') || combined.includes('network') || combined.includes('firewall')) { @@ -365,6 +366,17 @@ export function getCuratedAppList(): MarketplaceApp[] { manifestUrl: undefined, repoUrl: 'https://github.com/tailscale/tailscale' }, + { + id: 'netbird', + title: 'NetBird', + version: '0.71.2', + description: 'WireGuard mesh VPN client. Connect this node through NetBird Cloud or a self-hosted management server.', + icon: '/assets/img/app-icons/netbird.svg', + author: 'NetBird', + dockerImage: 'docker.io/netbirdio/netbird:0.71.2', + manifestUrl: undefined, + repoUrl: 'https://github.com/netbirdio/netbird' + }, { id: 'fedimint', title: 'Fedimint', diff --git a/scripts/image-versions.sh b/scripts/image-versions.sh index 45955771..8468b86c 100644 --- a/scripts/image-versions.sh +++ b/scripts/image-versions.sh @@ -48,6 +48,7 @@ PORTAINER_IMAGE="$ARCHY_REGISTRY/portainer:latest" # Networking TAILSCALE_IMAGE="$ARCHY_REGISTRY/tailscale:stable" +NETBIRD_IMAGE="docker.io/netbirdio/netbird:0.71.2" ALPINE_TOR_IMAGE="$ARCHY_REGISTRY/alpine-tor:0.4.8.13" ADGUARDHOME_IMAGE="$ARCHY_REGISTRY/adguardhome:v0.107.55" diff --git a/scripts/self-update.sh b/scripts/self-update.sh index fd7e91ab..bee1207e 100755 --- a/scripts/self-update.sh +++ b/scripts/self-update.sh @@ -75,6 +75,15 @@ fi cd "$REPO_DIR" +if ! command -v nano >/dev/null 2>&1; then + log "Installing nano for Archipelago terminal..." + if sudo apt-get update -qq 2>>"$LOG_FILE" && sudo apt-get install -y -qq nano 2>>"$LOG_FILE"; then + ok "nano installed" + else + warn "Unable to install nano automatically; continuing update" + fi +fi + # Fetch latest log "Fetching from origin..." git fetch origin main --quiet 2>>"$LOG_FILE"