fix(apps): repair netbird login and iframe focus
This commit is contained in:
parent
eeb08fc78f
commit
bd69ef41d5
@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## v1.7.74-alpha (2026-05-19)
|
||||
|
||||
- App-session right panels now re-focus the iframe after load and when the frame area is activated, so wheel/touch scrolling works immediately after switching tabs or selecting an app on shorter screens.
|
||||
- NetBird now launches through a unified local origin on port `8087` that proxies the dashboard plus `/oauth2`, `/api`, relay, WebSocket, and gRPC routes to `netbird-server`, fixing the embedded login flow that previously ended in `Unauthenticated` or `404 page not found` after logout.
|
||||
- Existing NetBird installs are repaired on adopt/start by rewriting `config.yaml`, `dashboard.env`, and the local nginx proxy config, then creating the missing `netbird-dashboard` and `netbird` proxy containers when needed while preserving NetBird data.
|
||||
- Saleor is still pending and is not included in this release; its registry/installer work remains local until it can be validated separately.
|
||||
- Validation passed with catalog JSON 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.73-alpha (2026-05-19)
|
||||
|
||||
- Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.
|
||||
|
||||
2
core/Cargo.lock
generated
2
core/Cargo.lock
generated
@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "archipelago"
|
||||
version = "1.7.72-alpha"
|
||||
version = "1.7.74-alpha"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"archipelago-container",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "archipelago"
|
||||
version = "1.7.73-alpha"
|
||||
version = "1.7.74-alpha"
|
||||
edition = "2021"
|
||||
description = "Archipelago Bitcoin Node OS - Native backend"
|
||||
authors = ["Archipelago Team"]
|
||||
|
||||
@ -495,7 +495,11 @@ pub(super) fn all_container_names(package_id: &str) -> Vec<String> {
|
||||
"indeedhub-ffmpeg".into(),
|
||||
"indeedhub".into(),
|
||||
],
|
||||
"netbird" => vec!["netbird".into(), "netbird-server".into()],
|
||||
"netbird" => vec![
|
||||
"netbird".into(),
|
||||
"netbird-dashboard".into(),
|
||||
"netbird-server".into(),
|
||||
],
|
||||
"nostr-vpn" => vec![
|
||||
"nostr-vpn".into(),
|
||||
"archy-nostr-vpn".into(),
|
||||
|
||||
@ -288,7 +288,7 @@ pub(super) fn startup_order(package_id: &str) -> &'static [&'static str] {
|
||||
"btcpay-server" | "btcpayserver" | "btcpay" => {
|
||||
&["archy-btcpay-db", "archy-nbxplorer", "btcpay-server"]
|
||||
}
|
||||
"netbird" => &["netbird-server", "netbird"],
|
||||
"netbird" => &["netbird-server", "netbird-dashboard", "netbird"],
|
||||
"penpot" | "penpot-frontend" => &[
|
||||
"penpot-postgres",
|
||||
"penpot-valkey",
|
||||
@ -392,7 +392,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn netbird_start_order_starts_server_before_dashboard() {
|
||||
assert_eq!(startup_order("netbird"), &["netbird-server", "netbird"]);
|
||||
assert_eq!(
|
||||
startup_order("netbird"),
|
||||
&["netbird-server", "netbird-dashboard", "netbird"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -98,6 +98,7 @@ async fn repair_stack_before_adopt(stack_name: &str) {
|
||||
}
|
||||
}
|
||||
"indeedhub" => repair_indeedhub_network_aliases().await,
|
||||
"netbird" => repair_netbird_unified_origin().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -144,6 +145,73 @@ pub(in crate::api::rpc::package) async fn repair_indeedhub_network_aliases() {
|
||||
}
|
||||
}
|
||||
|
||||
async fn repair_netbird_unified_origin() {
|
||||
let host_ip = detect_netbird_public_host_ip()
|
||||
.await
|
||||
.unwrap_or_else(|| "127.0.0.1".to_string());
|
||||
let _ = write_netbird_config_files(&host_ip).await;
|
||||
|
||||
let names = tokio::process::Command::new("podman")
|
||||
.args(["ps", "-a", "--format", "{{.Names}}"])
|
||||
.output()
|
||||
.await
|
||||
.ok()
|
||||
.map(|o| String::from_utf8_lossy(&o.stdout).to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let has_proxy = names.lines().any(|n| n.trim() == "netbird");
|
||||
let has_dashboard = names.lines().any(|n| n.trim() == "netbird-dashboard");
|
||||
if has_proxy && has_dashboard {
|
||||
return;
|
||||
}
|
||||
|
||||
if has_proxy && !has_dashboard {
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args(["rm", "-f", "netbird"])
|
||||
.output()
|
||||
.await;
|
||||
}
|
||||
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args(["network", "create", "netbird-net"])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args([
|
||||
"run",
|
||||
"-d",
|
||||
"--name",
|
||||
"netbird-dashboard",
|
||||
"--network",
|
||||
"netbird-net",
|
||||
"--restart=unless-stopped",
|
||||
"--env-file",
|
||||
"/var/lib/archipelago/netbird/dashboard.env",
|
||||
NETBIRD_DASHBOARD_IMAGE,
|
||||
])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args([
|
||||
"run",
|
||||
"-d",
|
||||
"--name",
|
||||
"netbird",
|
||||
"--network",
|
||||
"netbird-net",
|
||||
"--restart=unless-stopped",
|
||||
"-p",
|
||||
"8087:80",
|
||||
"-v",
|
||||
"/var/lib/archipelago/netbird/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
|
||||
NETBIRD_PROXY_IMAGE,
|
||||
])
|
||||
.output()
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn run_required_stack_command(
|
||||
stack_name: &str,
|
||||
label: &str,
|
||||
@ -313,6 +381,7 @@ const REGISTRY: &str = "146.59.87.168:3000/lfg2025";
|
||||
|
||||
const NETBIRD_DASHBOARD_IMAGE: &str = "docker.io/netbirdio/dashboard:v2.38.0";
|
||||
const NETBIRD_SERVER_IMAGE: &str = "docker.io/netbirdio/netbird-server:0.71.2";
|
||||
const NETBIRD_PROXY_IMAGE: &str = "docker.io/library/nginx:1.27-alpine";
|
||||
|
||||
/// Pull an image with retry and exponential backoff (3 attempts).
|
||||
async fn pull_image_with_retry(image: &str) -> Result<()> {
|
||||
@ -1364,8 +1433,12 @@ impl RpcHandler {
|
||||
|
||||
/// Install self-hosted NetBird (dashboard + combined management/signal/relay server).
|
||||
pub(super) async fn install_netbird_stack(&self) -> Result<serde_json::Value> {
|
||||
if let Some(adopted) =
|
||||
adopt_stack_if_exists("netbird", "netbird", &["netbird", "netbird-server"]).await?
|
||||
if let Some(adopted) = adopt_stack_if_exists(
|
||||
"netbird",
|
||||
"netbird",
|
||||
&["netbird-server", "netbird-dashboard", "netbird"],
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(adopted);
|
||||
}
|
||||
@ -1375,18 +1448,22 @@ impl RpcHandler {
|
||||
|
||||
self.set_install_phase("netbird", InstallPhase::PullingImage)
|
||||
.await;
|
||||
for (i, image) in [NETBIRD_DASHBOARD_IMAGE, NETBIRD_SERVER_IMAGE]
|
||||
for (i, image) in [
|
||||
NETBIRD_DASHBOARD_IMAGE,
|
||||
NETBIRD_SERVER_IMAGE,
|
||||
NETBIRD_PROXY_IMAGE,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
self.set_install_progress("netbird", i as u64, 2).await;
|
||||
self.set_install_progress("netbird", i as u64, 3).await;
|
||||
pull_image_with_retry(image)
|
||||
.await
|
||||
.with_context(|| format!("Failed to pull NetBird image: {}", image))?;
|
||||
}
|
||||
self.set_install_progress("netbird", 2, 2).await;
|
||||
self.set_install_progress("netbird", 3, 3).await;
|
||||
|
||||
for name in ["netbird", "netbird-server"] {
|
||||
for name in ["netbird", "netbird-dashboard", "netbird-server"] {
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args(["rm", "-f", name])
|
||||
.status()
|
||||
@ -1407,58 +1484,7 @@ impl RpcHandler {
|
||||
let host_ip = detect_netbird_public_host_ip()
|
||||
.await
|
||||
.unwrap_or_else(|| self.config.host_ip.clone());
|
||||
let dashboard_origin = format!("http://{}:8087", host_ip);
|
||||
let mgmt_origin = format!("http://{}:8086", host_ip);
|
||||
let relay_secret = read_or_generate_b64_secret("netbird-relay-auth-secret").await;
|
||||
let encryption_key = read_or_generate_b64_secret("netbird-store-encryption-key").await;
|
||||
let config = format!(
|
||||
r#"server:
|
||||
listenAddress: ":80"
|
||||
exposedAddress: "{mgmt_origin}"
|
||||
stunPorts:
|
||||
- 3478
|
||||
metricsPort: 9090
|
||||
healthcheckAddress: ":9000"
|
||||
logLevel: "info"
|
||||
logFile: "console"
|
||||
authSecret: "{relay_secret}"
|
||||
dataDir: "/var/lib/netbird"
|
||||
auth:
|
||||
issuer: "{mgmt_origin}/oauth2"
|
||||
localAuthDisabled: false
|
||||
signKeyRefreshEnabled: true
|
||||
dashboardRedirectURIs:
|
||||
- "{dashboard_origin}/nb-auth"
|
||||
- "{dashboard_origin}/nb-silent-auth"
|
||||
cliRedirectURIs:
|
||||
- "http://localhost:53000/"
|
||||
store:
|
||||
engine: "sqlite"
|
||||
encryptionKey: "{encryption_key}"
|
||||
"#
|
||||
);
|
||||
tokio::fs::write("/var/lib/archipelago/netbird/config.yaml", config)
|
||||
.await
|
||||
.context("Failed to write NetBird config.yaml")?;
|
||||
|
||||
let dashboard_env = format!(
|
||||
r#"NETBIRD_MGMT_API_ENDPOINT={mgmt_origin}
|
||||
NETBIRD_MGMT_GRPC_API_ENDPOINT={mgmt_origin}
|
||||
AUTH_AUDIENCE=netbird-dashboard
|
||||
AUTH_CLIENT_ID=netbird-dashboard
|
||||
AUTH_CLIENT_SECRET=
|
||||
AUTH_AUTHORITY={mgmt_origin}/oauth2
|
||||
USE_AUTH0=false
|
||||
AUTH_SUPPORTED_SCOPES=openid profile email groups
|
||||
AUTH_REDIRECT_URI=/nb-auth
|
||||
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
||||
NGINX_SSL_PORT=443
|
||||
LETSENCRYPT_DOMAIN=none
|
||||
"#
|
||||
);
|
||||
tokio::fs::write("/var/lib/archipelago/netbird/dashboard.env", dashboard_env)
|
||||
.await
|
||||
.context("Failed to write NetBird dashboard.env")?;
|
||||
write_netbird_config_files(&host_ip).await?;
|
||||
|
||||
let _ = tokio::process::Command::new("podman")
|
||||
.args(["network", "create", "netbird-net"])
|
||||
@ -1499,19 +1525,39 @@ LETSENCRYPT_DOMAIN=none
|
||||
"run",
|
||||
"-d",
|
||||
"--name",
|
||||
"netbird",
|
||||
"netbird-dashboard",
|
||||
"--network",
|
||||
"netbird-net",
|
||||
"--restart=unless-stopped",
|
||||
"-p",
|
||||
"8087:80",
|
||||
"--env-file",
|
||||
"/var/lib/archipelago/netbird/dashboard.env",
|
||||
NETBIRD_DASHBOARD_IMAGE,
|
||||
]);
|
||||
run_required_stack_command("netbird", "create dashboard", &mut dashboard_cmd).await?;
|
||||
|
||||
wait_for_stack_containers("netbird", &["netbird-server", "netbird"], 60).await?;
|
||||
let mut proxy_cmd = tokio::process::Command::new("podman");
|
||||
proxy_cmd.args([
|
||||
"run",
|
||||
"-d",
|
||||
"--name",
|
||||
"netbird",
|
||||
"--network",
|
||||
"netbird-net",
|
||||
"--restart=unless-stopped",
|
||||
"-p",
|
||||
"8087:80",
|
||||
"-v",
|
||||
"/var/lib/archipelago/netbird/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
|
||||
NETBIRD_PROXY_IMAGE,
|
||||
]);
|
||||
run_required_stack_command("netbird", "create unified proxy", &mut proxy_cmd).await?;
|
||||
|
||||
wait_for_stack_containers(
|
||||
"netbird",
|
||||
&["netbird-server", "netbird-dashboard", "netbird"],
|
||||
60,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.set_install_phase("netbird", InstallPhase::WaitingHealthy)
|
||||
.await;
|
||||
@ -1546,6 +1592,104 @@ async fn read_or_generate_b64_secret(name: &str) -> String {
|
||||
secret
|
||||
}
|
||||
|
||||
async fn write_netbird_config_files(host_ip: &str) -> Result<()> {
|
||||
let public_origin = format!("http://{}:8087", host_ip);
|
||||
let server_origin = format!("http://{}:8086", host_ip);
|
||||
let relay_secret = read_or_generate_b64_secret("netbird-relay-auth-secret").await;
|
||||
let encryption_key = read_or_generate_b64_secret("netbird-store-encryption-key").await;
|
||||
let config = format!(
|
||||
r#"server:
|
||||
listenAddress: ":80"
|
||||
exposedAddress: "{public_origin}"
|
||||
stunPorts:
|
||||
- 3478
|
||||
metricsPort: 9090
|
||||
healthcheckAddress: ":9000"
|
||||
logLevel: "info"
|
||||
logFile: "console"
|
||||
authSecret: "{relay_secret}"
|
||||
dataDir: "/var/lib/netbird"
|
||||
auth:
|
||||
issuer: "{public_origin}/oauth2"
|
||||
localAuthDisabled: false
|
||||
signKeyRefreshEnabled: true
|
||||
dashboardRedirectURIs:
|
||||
- "{public_origin}/nb-auth"
|
||||
- "{public_origin}/nb-silent-auth"
|
||||
cliRedirectURIs:
|
||||
- "http://localhost:53000/"
|
||||
store:
|
||||
engine: "sqlite"
|
||||
encryptionKey: "{encryption_key}"
|
||||
"#
|
||||
);
|
||||
tokio::fs::write("/var/lib/archipelago/netbird/config.yaml", config)
|
||||
.await
|
||||
.context("Failed to write NetBird config.yaml")?;
|
||||
|
||||
let dashboard_env = format!(
|
||||
r#"NETBIRD_MGMT_API_ENDPOINT={public_origin}
|
||||
NETBIRD_MGMT_GRPC_API_ENDPOINT={public_origin}
|
||||
AUTH_AUDIENCE=netbird-dashboard
|
||||
AUTH_CLIENT_ID=netbird-dashboard
|
||||
AUTH_CLIENT_SECRET=
|
||||
AUTH_AUTHORITY={public_origin}/oauth2
|
||||
USE_AUTH0=false
|
||||
AUTH_SUPPORTED_SCOPES=openid profile email groups
|
||||
AUTH_REDIRECT_URI=/nb-auth
|
||||
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
||||
NETBIRD_TOKEN_SOURCE=accessToken
|
||||
NGINX_SSL_PORT=443
|
||||
LETSENCRYPT_DOMAIN=none
|
||||
"#
|
||||
);
|
||||
tokio::fs::write("/var/lib/archipelago/netbird/dashboard.env", dashboard_env)
|
||||
.await
|
||||
.context("Failed to write NetBird dashboard.env")?;
|
||||
|
||||
let nginx_conf = format!(
|
||||
r#"server {{
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
location ~ ^/(relay|ws-proxy/) {{
|
||||
proxy_pass http://netbird-server:80;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 1d;
|
||||
}}
|
||||
|
||||
location ~ ^/(api|oauth2)/ {{
|
||||
proxy_pass http://netbird-server:80;
|
||||
}}
|
||||
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {{
|
||||
grpc_pass grpc://netbird-server:80;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
}}
|
||||
|
||||
location / {{
|
||||
proxy_pass http://netbird-dashboard:80;
|
||||
}}
|
||||
}}
|
||||
|
||||
# Direct server remains available for diagnostics at {server_origin}.
|
||||
"#
|
||||
);
|
||||
tokio::fs::write("/var/lib/archipelago/netbird/nginx.conf", nginx_conf)
|
||||
.await
|
||||
.context("Failed to write NetBird nginx.conf")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn detect_netbird_public_host_ip() -> Option<String> {
|
||||
let output = tokio::process::Command::new("hostname")
|
||||
.args(["-I"])
|
||||
|
||||
@ -62,6 +62,7 @@ impl DockerPackageScanner {
|
||||
"indeedhub-build_relay_1",
|
||||
"indeedhub-build_ffmpeg-worker_1",
|
||||
"netbird-server",
|
||||
"netbird-dashboard",
|
||||
"buildx_buildkit_default",
|
||||
];
|
||||
|
||||
|
||||
@ -169,6 +169,7 @@ fn image_var_for_app(app_id: &str) -> Option<&'static str> {
|
||||
"portainer" => Some("PORTAINER_IMAGE"),
|
||||
"tailscale" => Some("TAILSCALE_IMAGE"),
|
||||
"netbird" => Some("NETBIRD_DASHBOARD_IMAGE"),
|
||||
"netbird-dashboard" => Some("NETBIRD_DASHBOARD_IMAGE"),
|
||||
"netbird-server" => Some("NETBIRD_SERVER_IMAGE"),
|
||||
|
||||
// Fedimint
|
||||
@ -302,7 +303,8 @@ pub fn containers_for_stack(app_id: &str) -> Vec<(&'static str, &'static str)> {
|
||||
("penpot-frontend", "PENPOT_FRONTEND_IMAGE"),
|
||||
],
|
||||
"netbird" => vec![
|
||||
("netbird", "NETBIRD_DASHBOARD_IMAGE"),
|
||||
("netbird", "NETBIRD_PROXY_IMAGE"),
|
||||
("netbird-dashboard", "NETBIRD_DASHBOARD_IMAGE"),
|
||||
("netbird-server", "NETBIRD_SERVER_IMAGE"),
|
||||
],
|
||||
_ => vec![],
|
||||
|
||||
4
neode-ui/package-lock.json
generated
4
neode-ui/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "neode-ui",
|
||||
"version": "1.7.73-alpha",
|
||||
"version": "1.7.74-alpha",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "neode-ui",
|
||||
"version": "1.7.73-alpha",
|
||||
"version": "1.7.74-alpha",
|
||||
"dependencies": {
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "neode-ui",
|
||||
"private": true,
|
||||
"version": "1.7.73-alpha",
|
||||
"version": "1.7.74-alpha",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "./start-dev.sh",
|
||||
|
||||
@ -9,7 +9,13 @@
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<div v-if="appUrl && !iframeBlocked" class="absolute inset-0 app-session-frame-scroll-host">
|
||||
<div
|
||||
v-if="appUrl && !iframeBlocked"
|
||||
class="absolute inset-0 app-session-frame-scroll-host"
|
||||
tabindex="-1"
|
||||
@pointerdown="focusIframe"
|
||||
@focusin="focusIframe"
|
||||
>
|
||||
<iframe
|
||||
ref="iframeRef"
|
||||
:key="refreshKey"
|
||||
@ -17,7 +23,7 @@
|
||||
class="w-full h-full border-0 iframe-scrollbar-hide"
|
||||
title="App content"
|
||||
tabindex="0"
|
||||
@load="$emit('iframeLoad')"
|
||||
@load="handleIframeLoad"
|
||||
@error="$emit('iframeError')"
|
||||
/>
|
||||
</div>
|
||||
@ -84,7 +90,7 @@ const props = defineProps<{
|
||||
refreshKey: number
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
const emit = defineEmits<{
|
||||
iframeLoad: []
|
||||
iframeError: []
|
||||
refresh: []
|
||||
@ -93,10 +99,20 @@ defineEmits<{
|
||||
|
||||
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
||||
|
||||
function focusIframe() {
|
||||
iframeRef.value?.focus({ preventScroll: true })
|
||||
}
|
||||
|
||||
async function handleIframeLoad() {
|
||||
emit('iframeLoad')
|
||||
await nextTick()
|
||||
requestAnimationFrame(focusIframe)
|
||||
}
|
||||
|
||||
watch(() => [props.appUrl, props.refreshKey, props.iframeBlocked], async () => {
|
||||
if (!props.appUrl || props.iframeBlocked) return
|
||||
await nextTick()
|
||||
iframeRef.value?.focus({ preventScroll: true })
|
||||
requestAnimationFrame(focusIframe)
|
||||
}, { immediate: true })
|
||||
|
||||
defineExpose({ iframeRef })
|
||||
|
||||
@ -180,6 +180,31 @@ init()
|
||||
</button>
|
||||
</div>
|
||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||
<!-- v1.7.74-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.74-alpha</span>
|
||||
<span class="text-xs text-white/40">May 19, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>App-session right panels now re-focus the iframe after load and when the frame area is activated, so scrolling works immediately after selecting an app or switching tabs on shorter screens.</p>
|
||||
<p>NetBird now uses a unified local launch origin on port 8087 that serves the dashboard and proxies auth/API routes to the server, fixing the Unauthenticated and 404 logout/login loop.</p>
|
||||
<p>Existing NetBird installs are repaired during adopt/start by rewriting the config files and creating the missing dashboard/proxy containers while preserving data.</p>
|
||||
<p>Saleor is not in this release yet; it remains pending for separate validation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.73-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.73-alpha</span>
|
||||
<span class="text-xs text-white/40">May 19, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Mobile apps that block iframe embedding now open directly in a browser tab instead of first landing in a broken in-shell webview.</p>
|
||||
<p>App Store search covers all apps while searching, My Apps search can surface matching installable App Store entries, and mobile My Apps/Websites tab switching updates the view reliably.</p>
|
||||
<p>NetBird installs prefer a 100.x tailnet address when available, and app sessions gained iframe auto-focus plus a scroll host for right-frame scrolling.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.72-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
|
||||
@ -50,6 +50,7 @@ PORTAINER_IMAGE="$ARCHY_REGISTRY/portainer:latest"
|
||||
TAILSCALE_IMAGE="$ARCHY_REGISTRY/tailscale:stable"
|
||||
NETBIRD_DASHBOARD_IMAGE="docker.io/netbirdio/dashboard:v2.38.0"
|
||||
NETBIRD_SERVER_IMAGE="docker.io/netbirdio/netbird-server:0.71.2"
|
||||
NETBIRD_PROXY_IMAGE="docker.io/library/nginx:1.27-alpine"
|
||||
ALPINE_TOR_IMAGE="$ARCHY_REGISTRY/alpine-tor:0.4.8.13"
|
||||
ADGUARDHOME_IMAGE="$ARCHY_REGISTRY/adguardhome:v0.107.55"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user