Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85417de952 | ||
|
|
b8d084368e |
Generated
+1
-1
@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "archipelago"
|
||||
version = "1.7.37-alpha"
|
||||
version = "1.7.40-alpha"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"archipelago-container",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "archipelago"
|
||||
version = "1.7.37-alpha"
|
||||
version = "1.7.40-alpha"
|
||||
edition = "2021"
|
||||
description = "Archipelago Bitcoin Node OS - Native backend"
|
||||
authors = ["Archipelago Team"]
|
||||
|
||||
@@ -86,6 +86,36 @@ async fn main() -> Result<()> {
|
||||
|
||||
info!("Starting Archipelago Bitcoin Node OS");
|
||||
|
||||
// Self-heal web-ui permissions. The OTA updater in <=v1.7.38 left
|
||||
// /opt/archipelago/web-ui as drwx------ (700) after the atomic
|
||||
// swap — nginx (www-data) then returned 500/403 on every request
|
||||
// until someone shelled in and chmod'd it. Check on every boot
|
||||
// and repair if needed so a node auto-recovers after the next
|
||||
// service restart that follows a broken OTA.
|
||||
tokio::spawn(async move {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let web_ui = std::path::Path::new("/opt/archipelago/web-ui");
|
||||
if let Ok(meta) = tokio::fs::metadata(web_ui).await {
|
||||
let mode = meta.permissions().mode() & 0o777;
|
||||
if mode & 0o005 != 0o005 {
|
||||
tracing::warn!(
|
||||
"web-ui perms {:o} not world-readable — self-healing",
|
||||
mode
|
||||
);
|
||||
let _ = tokio::process::Command::new("sudo")
|
||||
.args([
|
||||
"-n",
|
||||
"chmod",
|
||||
"-R",
|
||||
"u=rwX,go=rX",
|
||||
"/opt/archipelago/web-ui",
|
||||
])
|
||||
.status()
|
||||
.await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Load configuration
|
||||
let config = Config::load().await?;
|
||||
info!("📁 Data directory: {}", config.data_dir.display());
|
||||
|
||||
@@ -914,6 +914,21 @@ pub async fn apply_update(data_dir: &Path) -> Result<()> {
|
||||
])
|
||||
.await;
|
||||
|
||||
// Set world-readable perms so nginx (runs as www-data)
|
||||
// can stat + serve the files. Without this, the tar
|
||||
// extraction inherits the staging-dir's 700 mode and
|
||||
// nginx returns 403/500 for every request after the
|
||||
// swap — exactly what bit .116 on the v1.7.38 rollout.
|
||||
let _ = host_sudo(&["chmod", "755", &staging_new]).await;
|
||||
let _ = host_sudo(&[
|
||||
"find", &staging_new, "-type", "d", "-exec", "chmod", "755", "{}", "+",
|
||||
])
|
||||
.await;
|
||||
let _ = host_sudo(&[
|
||||
"find", &staging_new, "-type", "f", "-exec", "chmod", "644", "{}", "+",
|
||||
])
|
||||
.await;
|
||||
|
||||
// Preserve paths that are installed outside the Vue build
|
||||
// (baked in by the ISO or sibling installers) and so
|
||||
// aren't in the new tarball. Without this copy, every OTA
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "neode-ui",
|
||||
"private": true,
|
||||
"version": "1.7.38-alpha",
|
||||
"version": "1.7.40-alpha",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "./start-dev.sh",
|
||||
|
||||
@@ -180,6 +180,26 @@ init()
|
||||
</button>
|
||||
</div>
|
||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||
<!-- v1.7.40-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.40-alpha</span>
|
||||
<span class="text-xs text-white/40">Apr 22, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Proper fix for the 500 / Internal Server Error after update. The v1.7.38 and v1.7.39 frontend archives had the wrong permissions baked into the archive itself — the tarball's root directory entry was private, so every node that extracted it ended up with a web UI directory nginx couldn't read. v1.7.40 packages the archive with correct world-readable permissions from the start, so no node ever sees the 500 again.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.39-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.39-alpha</span>
|
||||
<span class="text-xs text-white/40">Apr 22, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Hotfix for v1.7.38 — on some nodes the update landed with the web UI directory set to private file permissions, so nginx returned a 500 / "Internal Server Error" on every page. This release fixes the updater to set world-readable permissions on the new frontend, and the node also now self-heals on boot if it ever finds the UI directory in that state again.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.38-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
|
||||
@@ -87,8 +87,39 @@ if [ -z "$FRONTEND_ARCHIVE" ]; then
|
||||
echo " Including AIUI from demo/aiui/"
|
||||
cp -r "$PROJECT_ROOT/demo/aiui" "$STAGING_DIR/aiui"
|
||||
fi
|
||||
# Force world-readable perms on every entry BEFORE tar, so the
|
||||
# archive's internal mode bits are 755/644 regardless of what
|
||||
# the staging dir's umask gave us. Without this, mktemp -d
|
||||
# creates the staging dir at 700, that 700 gets baked into the
|
||||
# tarball's root `./` entry, and every node that extracts the
|
||||
# archive ends up with /opt/archipelago/web-ui at 700 — which
|
||||
# causes nginx (www-data) to return 500 "permission denied" on
|
||||
# every page. Bit us on the v1.7.38 + v1.7.39 rollouts.
|
||||
chmod 755 "$STAGING_DIR"
|
||||
find "$STAGING_DIR" -type d -exec chmod 755 {} +
|
||||
find "$STAGING_DIR" -type f -exec chmod 644 {} +
|
||||
echo "Creating frontend archive $FRONTEND_ARCHIVE..."
|
||||
tar -czf "$FRONTEND_ARCHIVE" -C "$STAGING_DIR" .
|
||||
# --mode is a belt-and-braces in case a file's on-disk perms
|
||||
# drift again; forces 755 dir / 644 file in the archive too.
|
||||
tar --owner=0 --group=0 \
|
||||
--mode='u=rwX,go=rX' \
|
||||
-czf "$FRONTEND_ARCHIVE" \
|
||||
-C "$STAGING_DIR" .
|
||||
# Verify the archive root entry is world-readable before we
|
||||
# declare success — catches regressions in tar-flag handling
|
||||
# (BSD tar, busybox tar) that might silently drop --mode.
|
||||
root_mode=$(tar tvzf "$FRONTEND_ARCHIVE" | head -1 | awk '{print $1}')
|
||||
case "$root_mode" in
|
||||
drwxr-xr-x|drwxr-x*x*)
|
||||
echo " Tarball root perms OK: $root_mode"
|
||||
;;
|
||||
*)
|
||||
echo " ERROR: tarball root perms are $root_mode (want drwxr-xr-x) — aborting release"
|
||||
rm -f "$FRONTEND_ARCHIVE"
|
||||
rm -rf "$STAGING_DIR"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rm -rf "$STAGING_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user