Compare commits

...
19 changed files with 329 additions and 63 deletions
+27
View File
@@ -1,5 +1,32 @@
# Changelog
## v1.7.82-alpha (2026-05-22)
- Saleor storefront proxying now forwards `X-Forwarded-Host`, fixing Next.js Server Actions requests that compared the browser origin with the internal `storefront-app:3000` upstream host.
- Saleor storefront media now routes `/thumbnail/` and `/media/` through the same `9011` proxy to the Saleor API, fixing product image optimizer failures caused by `localhost:8000` media URLs.
- The Saleor storefront container receives an explicit internal media origin so rewritten media URLs resolve inside the Podman network without exposing private API ports to browsers.
- Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for storefront HTML, static assets, GraphQL, media redirects, and optimized product images.
## v1.7.81-alpha (2026-05-21)
- Saleor storefront installs now use the prebuilt registry image instead of building the Next.js app on-device, avoiding Podman build failures during stack installation.
- Existing Saleor stacks are repaired on adoption by recreating missing storefront containers, forcing the storefront app to bind `0.0.0.0:3000`, and resolving nginx upstreams dynamically after container restarts.
- The shipped Saleor storefront image now includes public assets and omits Vercel-only Speed Insights injection, fixing broken static asset responses and the local `/_vercel/speed-insights/script.js` browser warning.
- Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for `9011` storefront, static assets, and proxied GraphQL.
## v1.7.80-alpha (2026-05-21)
- Saleor storefront proxying now falls back to the direct request scheme when no forwarded protocol header is present, fixing direct `http://node:9011` launches that could generate an invalid same-origin GraphQL URL.
- The Saleor storefront release path keeps public proxy support intact by still honoring forwarded HTTPS headers for Nginx Proxy Manager domains while repairing local/direct port launches.
- Validation passed with `cargo fmt --check` and `cargo check` for the Archipelago backend before release staging.
## v1.7.79-alpha (2026-05-20)
- Saleor now installs the official Saleor Storefront as part of the stack, built from the pinned `saleor/storefront` source and served as the customer-facing shop on port `9011`.
- Saleor app launches now open the storefront while the admin dashboard remains available on port `9010` with the generated `admin@example.com` credentials shown in Archipelago.
- Public Nginx Proxy Manager hosts forwarding to the Saleor storefront also expose same-origin `/graphql/`, so public storefront domains can talk to the local Saleor API without mixed-content or private-LAN reachability failures.
- Saleor stack metadata, marketplace descriptions, catalog ports, scanner exclusions, and app-session routing now describe the storefront/dashboard/API split explicitly.
## v1.7.78-alpha (2026-05-20)
- Public Nginx Proxy Manager hosts for Saleor now keep browser GraphQL calls same-origin at `/graphql/` and proxy them to the local API on `8000`, fixing `Failed to fetch` when a public domain such as `noderunner.shop` was loaded from devices that cannot reach the node's private LAN/tailnet API address.
+3 -3
View File
@@ -68,7 +68,7 @@
"id": "saleor",
"title": "Saleor",
"version": "3.23",
"description": "Composable commerce platform with GraphQL API, dashboard, worker, mail testing, and tracing.",
"description": "Composable commerce platform with customer storefront, GraphQL API, dashboard, worker, mail testing, and tracing.",
"icon": "/assets/img/app-icons/saleor.svg",
"author": "Saleor",
"category": "commerce",
@@ -76,9 +76,9 @@
"dockerImage": "ghcr.io/saleor/saleor:3.23",
"repoUrl": "https://github.com/saleor/saleor",
"containerConfig": {
"ports": ["9010:80", "8000:8000", "8025:8025", "16686:16686"],
"ports": ["9011:80", "9010:80", "8000:8000", "8025:8025", "16686:16686"],
"volumes": ["/var/lib/archipelago/saleor:/app/media", "/var/lib/archipelago/saleor-db:/var/lib/postgresql/data"],
"notes": "Installed as a Saleor stack: dashboard on 9010, API on 8000, Mailpit on 8025, and Jaeger on 16686. Supporting containers include PostgreSQL, Valkey, Celery worker, and services required by Saleor."
"notes": "Installed as a Saleor stack: customer storefront on 9011, admin dashboard on 9010, API on 8000, Mailpit on 8025, and Jaeger on 16686. Supporting containers include PostgreSQL, Valkey, Celery worker, and services required by Saleor."
}
},
{
+1 -1
View File
@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "archipelago"
version = "1.7.78-alpha"
version = "1.7.81-alpha"
dependencies = [
"anyhow",
"archipelago-container",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "archipelago"
version = "1.7.78-alpha"
version = "1.7.82-alpha"
edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"]
+223 -5
View File
@@ -76,6 +76,10 @@ async fn adopt_stack_if_exists(
async fn repair_stack_before_adopt(stack_name: &str) {
match stack_name {
"saleor" => {
repair_saleor_network_aliases().await;
let _ = start_saleor_storefront_containers().await;
}
"btcpay" | "btcpay-server" => {
let _ = tokio::process::Command::new("sudo")
.args([
@@ -99,7 +103,6 @@ async fn repair_stack_before_adopt(stack_name: &str) {
}
"indeedhub" => repair_indeedhub_network_aliases().await,
"netbird" => repair_netbird_unified_origin().await,
"saleor" => repair_saleor_network_aliases().await,
_ => {}
}
}
@@ -244,6 +247,8 @@ async fn repair_saleor_network_aliases() {
("saleor-api", "api"),
("saleor-worker", "worker"),
("saleor", "saleor"),
("saleor-storefront", "storefront"),
("saleor-storefront-app", "storefront-app"),
] {
let exists = tokio::process::Command::new("podman")
.args(["container", "exists", container])
@@ -271,7 +276,53 @@ async fn repair_saleor_network_aliases() {
.output()
.await;
}
}
async fn start_saleor_storefront_containers() -> Result<()> {
let names = podman_container_names().await?;
if !names.iter().any(|name| name == "saleor-storefront-app") {
pull_image_with_retry(SALEOR_STOREFRONT_IMAGE).await?;
let mut storefront_cmd = saleor_storefront_app_command();
run_required_stack_command("saleor", "create storefront app", &mut storefront_cmd).await?;
} else {
let _ = tokio::process::Command::new("podman")
.args(["start", "saleor-storefront-app"])
.output()
.await;
}
write_saleor_storefront_proxy_config().await?;
if !names.iter().any(|name| name == "saleor-storefront") {
let mut proxy_cmd = saleor_storefront_proxy_command();
run_required_stack_command("saleor", "create storefront proxy", &mut proxy_cmd).await?;
} else {
let _ = tokio::process::Command::new("podman")
.args(["start", "saleor-storefront"])
.output()
.await;
}
wait_for_stack_containers(
"saleor",
&["saleor-storefront-app", "saleor-storefront"],
60,
)
.await
}
async fn podman_container_names() -> Result<Vec<String>> {
let output = tokio::process::Command::new("podman")
.args(["ps", "-a", "--format", "{{.Names}}"])
.output()
.await
.context("Failed to list containers")?;
Ok(String::from_utf8_lossy(&output.stdout)
.lines()
.map(str::trim)
.filter(|name| !name.is_empty())
.map(ToOwned::to_owned)
.collect())
}
async fn run_required_stack_command(
@@ -446,6 +497,7 @@ 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";
const SALEOR_API_IMAGE: &str = "ghcr.io/saleor/saleor:3.23";
const SALEOR_DASHBOARD_IMAGE: &str = "ghcr.io/saleor/saleor-dashboard:3.23";
const SALEOR_STOREFRONT_IMAGE: &str = "146.59.87.168:3000/lfg2025/saleor-storefront:6eb0b97";
const SALEOR_POSTGRES_IMAGE: &str = "docker.io/library/postgres:15-alpine";
const SALEOR_VALKEY_IMAGE: &str = "docker.io/valkey/valkey:8.1-alpine";
const SALEOR_JAEGER_IMAGE: &str = "docker.io/jaegertracing/jaeger:latest";
@@ -453,6 +505,14 @@ const SALEOR_MAILPIT_IMAGE: &str = "docker.io/axllent/mailpit:latest";
/// Pull an image with retry and exponential backoff (3 attempts).
async fn pull_image_with_retry(image: &str) -> Result<()> {
let exists = tokio::process::Command::new("podman")
.args(["image", "exists", image])
.status()
.await;
if matches!(exists, Ok(status) if status.success()) {
return Ok(());
}
const MAX_ATTEMPTS: u32 = 3;
const BACKOFF_SECS: [u64; 3] = [5, 15, 45];
@@ -497,6 +557,75 @@ async fn pull_image_with_retry(image: &str) -> Result<()> {
unreachable!()
}
fn saleor_storefront_app_command() -> tokio::process::Command {
let mut cmd = tokio::process::Command::new("podman");
cmd.args([
"run",
"-d",
"--name",
"saleor-storefront-app",
"--network",
"saleor-net",
"--network-alias",
"storefront-app",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=512m",
"--pids-limit=2048",
"-e",
"NEXT_PUBLIC_SALEOR_API_URL=http://api:8000/graphql/",
"-e",
"NEXT_PUBLIC_SALEOR_MEDIA_URL=http://api:8000/",
"-e",
"NEXT_PUBLIC_STOREFRONT_URL=http://localhost:9011",
"-e",
"NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel",
"-e",
"HOSTNAME=0.0.0.0",
"-e",
"PORT=3000",
SALEOR_STOREFRONT_IMAGE,
]);
cmd
}
fn saleor_storefront_proxy_command() -> tokio::process::Command {
let mut cmd = tokio::process::Command::new("podman");
cmd.args([
"run",
"-d",
"--name",
"saleor-storefront",
"--network",
"saleor-net",
"--network-alias",
"storefront",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=NET_BIND_SERVICE",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=128m",
"--pids-limit=1024",
"-p",
"9011:80",
"-v",
"/var/lib/archipelago/saleor-storefront/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
NETBIRD_PROXY_IMAGE,
]);
cmd
}
impl RpcHandler {
/// Install Immich stack (postgres + redis + server).
pub(super) async fn install_immich_stack(&self) -> Result<serde_json::Value> {
@@ -1656,6 +1785,8 @@ impl RpcHandler {
"saleor-api",
"saleor-worker",
"saleor",
"saleor-storefront",
"saleor-storefront-app",
],
)
.await?
@@ -1663,7 +1794,7 @@ impl RpcHandler {
return Ok(adopted);
}
install_log("INSTALL START: saleor stack (postgres + valkey + api + worker + dashboard)")
install_log("INSTALL START: saleor stack (postgres + valkey + api + worker + dashboard + storefront)")
.await;
info!("Installing Saleor stack");
@@ -1672,6 +1803,7 @@ impl RpcHandler {
SALEOR_VALKEY_IMAGE,
SALEOR_API_IMAGE,
SALEOR_DASHBOARD_IMAGE,
SALEOR_STOREFRONT_IMAGE,
SALEOR_JAEGER_IMAGE,
SALEOR_MAILPIT_IMAGE,
];
@@ -1692,6 +1824,8 @@ impl RpcHandler {
"saleor",
"saleor-api",
"saleor-worker",
"saleor-storefront",
"saleor-storefront-app",
"saleor-db",
"saleor-cache",
"saleor-jaeger",
@@ -1717,6 +1851,7 @@ impl RpcHandler {
"/var/lib/archipelago/saleor",
"/var/lib/archipelago/saleor-db",
"/var/lib/archipelago/saleor-cache",
"/var/lib/archipelago/saleor-storefront",
])
.output()
.await;
@@ -1725,6 +1860,7 @@ impl RpcHandler {
"/var/lib/archipelago/saleor",
"/var/lib/archipelago/saleor-db",
"/var/lib/archipelago/saleor-cache",
"/var/lib/archipelago/saleor-storefront",
] {
let _ = tokio::process::Command::new("sudo")
.args(["chown", "-R", &format!("{}:{}", user, user), dir])
@@ -1744,10 +1880,11 @@ impl RpcHandler {
let dashboard_origin = format!("http://{}:9010", host_ip);
let dashboard_url = format!("{}/", dashboard_origin);
let api_url = format!("http://{}:8000/graphql/", host_ip);
let storefront_origin = format!("http://{}:9011", host_ip);
let allowed_hosts = format!("localhost,127.0.0.1,api,saleor-api,{}", host_ip);
let allowed_client_hosts = format!(
"{},http://localhost:9010,http://127.0.0.1:9010",
dashboard_origin
"{},{},http://localhost:9010,http://127.0.0.1:9010,http://localhost:9011,http://127.0.0.1:9011",
dashboard_origin, storefront_origin
);
let database_url = format!("postgres://saleor:{}@db/saleor", db_pass);
@@ -2067,6 +2204,18 @@ user.save()
]);
run_required_stack_command("saleor", "create dashboard", &mut dashboard_cmd).await?;
let mut storefront_cmd = saleor_storefront_app_command();
run_required_stack_command("saleor", "create storefront app", &mut storefront_cmd).await?;
write_saleor_storefront_proxy_config().await?;
let mut storefront_proxy_cmd = saleor_storefront_proxy_command();
run_required_stack_command(
"saleor",
"create storefront proxy",
&mut storefront_proxy_cmd,
)
.await?;
wait_for_stack_containers(
"saleor",
&[
@@ -2077,6 +2226,8 @@ user.save()
"saleor-api",
"saleor-worker",
"saleor",
"saleor-storefront",
"saleor-storefront-app",
],
120,
)
@@ -2092,6 +2243,8 @@ user.save()
"saleor-api",
"saleor-worker",
"saleor",
"saleor-storefront",
"saleor-storefront-app",
],
30,
)
@@ -2109,7 +2262,7 @@ user.save()
Ok(serde_json::json!({
"success": true,
"package_id": "saleor",
"message": "Saleor stack installed (7 containers)",
"message": "Saleor stack installed (9 containers)",
}))
}
}
@@ -2130,6 +2283,71 @@ async fn read_or_generate_b64_secret(name: &str) -> String {
secret
}
async fn write_saleor_storefront_proxy_config() -> Result<()> {
tokio::fs::create_dir_all("/var/lib/archipelago/saleor-storefront")
.await
.context("Failed to create Saleor storefront config directory")?;
let nginx_conf = r#"map $http_x_forwarded_proto $saleor_storefront_proto {
default $http_x_forwarded_proto;
"" $scheme;
}
server {
listen 80;
server_name _;
resolver 10.89.4.1 valid=10s ipv6=off;
proxy_http_version 1.1;
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-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
location ^~ /graphql/ {
set $saleor_api http://api:8000/graphql/;
proxy_pass $saleor_api;
proxy_set_header Host api;
proxy_set_header Origin "";
}
location ^~ /thumbnail/ {
set $saleor_media http://api:8000$request_uri;
proxy_pass $saleor_media;
proxy_set_header Host api;
proxy_set_header Origin "";
}
location ^~ /media/ {
set $saleor_media http://api:8000$request_uri;
proxy_pass $saleor_media;
proxy_set_header Host api;
proxy_set_header Origin "";
}
location / {
set $saleor_storefront_app http://storefront-app:3000;
proxy_pass $saleor_storefront_app;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Accept-Encoding "";
sub_filter_once off;
sub_filter_types text/html application/javascript text/javascript;
sub_filter 'http://api:8000/graphql/' '$saleor_storefront_proto://$host/graphql/';
}
}
"#;
tokio::fs::write(
"/var/lib/archipelago/saleor-storefront/nginx.conf",
nginx_conf,
)
.await
.context("Failed to write Saleor storefront nginx.conf")?;
Ok(())
}
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);
@@ -69,6 +69,8 @@ impl DockerPackageScanner {
"saleor-cache",
"saleor-jaeger",
"saleor-mailpit",
"saleor-storefront",
"saleor-storefront-app",
"buildx_buildkit_default",
];
@@ -519,7 +521,7 @@ fn get_app_metadata(app_id: &str) -> AppMetadata {
},
"saleor" => AppMetadata {
title: "Saleor".to_string(),
description: "Composable commerce platform with GraphQL API and dashboard. Log in with admin@example.com; the password is stored on the node at /var/lib/archipelago/secrets/saleor-admin-password".to_string(),
description: "Composable commerce platform with storefront, dashboard, and GraphQL API. The customer storefront opens on port 9011; admin dashboard is on 9010 with admin@example.com credentials stored on the node.".to_string(),
icon: "/assets/img/app-icons/saleor.svg".to_string(),
repo: "https://github.com/saleor/saleor".to_string(),
tier: "",
+1 -1
View File
@@ -129,7 +129,7 @@ impl PodmanClient {
"filebrowser" => "http://localhost:8083",
"nginx-proxy-manager" => "http://localhost:8081",
"portainer" => "http://localhost:9000",
"saleor" => "http://localhost:9010",
"saleor" => "http://localhost:9011",
"uptime-kuma" => "http://localhost:3002",
"fedimint" | "fedimintd" => "http://localhost:8175",
"fedimint-gateway" => "http://localhost:8176",
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "neode-ui",
"version": "1.7.78-alpha",
"version": "1.7.82-alpha",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "neode-ui",
"version": "1.7.78-alpha",
"version": "1.7.82-alpha",
"dependencies": {
"@types/dompurify": "^3.0.5",
"@vue-leaflet/vue-leaflet": "^0.10.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "neode-ui",
"private": true,
"version": "1.7.78-alpha",
"version": "1.7.82-alpha",
"type": "module",
"scripts": {
"start": "./start-dev.sh",
+3 -3
View File
@@ -68,7 +68,7 @@
"id": "saleor",
"title": "Saleor",
"version": "3.23",
"description": "Composable commerce platform with GraphQL API, dashboard, worker, mail testing, and tracing.",
"description": "Composable commerce platform with customer storefront, GraphQL API, dashboard, worker, mail testing, and tracing.",
"icon": "/assets/img/app-icons/saleor.svg",
"author": "Saleor",
"category": "commerce",
@@ -76,9 +76,9 @@
"dockerImage": "ghcr.io/saleor/saleor:3.23",
"repoUrl": "https://github.com/saleor/saleor",
"containerConfig": {
"ports": ["9010:80", "8000:8000", "8025:8025", "16686:16686"],
"ports": ["9011:80", "9010:80", "8000:8000", "8025:8025", "16686:16686"],
"volumes": ["/var/lib/archipelago/saleor:/app/media", "/var/lib/archipelago/saleor-db:/var/lib/postgresql/data"],
"notes": "Installed as a Saleor stack: dashboard on 9010, API on 8000, Mailpit on 8025, and Jaeger on 16686. Supporting containers include PostgreSQL, Valkey, Celery worker, and services required by Saleor."
"notes": "Installed as a Saleor stack: customer storefront on 9011, admin dashboard on 9010, API on 8000, Mailpit on 8025, and Jaeger on 16686. Supporting containers include PostgreSQL, Valkey, Celery worker, and services required by Saleor."
}
},
{
+1
View File
@@ -103,6 +103,7 @@ const PORT_TO_APP_ID: Record<string, string> = {
'8888': 'searxng',
'9000': 'portainer',
'9010': 'saleor',
'9011': 'saleor',
'8087': 'netbird',
'8086': 'netbird',
'9980': 'onlyoffice',
@@ -17,6 +17,7 @@ describe('appSessionConfig', () => {
expect(resolveAppUrl('mempool')).toBe('http://192.168.1.228:4080')
expect(resolveAppUrl('indeedhub')).toBe('http://192.168.1.228:7778')
expect(resolveAppUrl('saleor')).toBe('http://192.168.1.228:9011')
})
it('keeps NetBird on the unified dashboard proxy port', () => {
@@ -14,7 +14,7 @@ export const APP_PORTS: Record<string, number> = {
'archy-electrs-ui': 50002,
'mempool-electrs': 50002,
'btcpay-server': 23000,
'saleor': 9010,
'saleor': 9011,
'lnd': 18083,
'archy-lnd-ui': 18083,
'mempool': 4080,
+1 -1
View File
@@ -79,7 +79,7 @@ export function getCuratedAppList(): MarketplaceApp[] {
{ id: 'bitcoin-knots', title: 'Bitcoin Knots', version: '28.1.0', description: 'Run a full Bitcoin node. Validate and relay blocks and transactions on the Bitcoin network.', icon: '/assets/img/app-icons/bitcoin-knots.webp', author: 'Bitcoin Knots', dockerImage: `${R}/bitcoin-knots:latest`, repoUrl: 'https://github.com/bitcoinknots/bitcoin' },
{ id: 'bitcoin-core', title: 'Bitcoin Core', version: '28.4', description: 'Reference implementation of the Bitcoin protocol. Run a full node validating and relaying blocks on the Bitcoin network.', icon: '/assets/img/app-icons/bitcoin-core.svg', author: 'Bitcoin Core contributors', dockerImage: 'docker.io/bitcoin/bitcoin:28.4', repoUrl: 'https://github.com/bitcoin/bitcoin' },
{ id: 'btcpay-server', title: 'BTCPay Server', version: '2.3.9', description: 'Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries or fees.', icon: '/assets/img/app-icons/btcpay-server.png', author: 'BTCPay Server Foundation', dockerImage: 'docker.io/btcpayserver/btcpayserver:2.3.9', repoUrl: 'https://github.com/btcpayserver/btcpayserver' },
{ id: 'saleor', title: 'Saleor', version: '3.23', category: 'commerce', description: 'Composable commerce platform with GraphQL API, dashboard, worker, mail testing, and tracing. Log in with admin@example.com; the password is stored on the node.', icon: '/assets/img/app-icons/saleor.svg', author: 'Saleor', dockerImage: 'ghcr.io/saleor/saleor:3.23', repoUrl: 'https://github.com/saleor/saleor' },
{ id: 'saleor', title: 'Saleor', version: '3.23', category: 'commerce', description: 'Composable commerce platform with customer storefront, GraphQL API, dashboard, worker, mail testing, and tracing. Storefront opens on port 9011; admin dashboard remains on 9010.', icon: '/assets/img/app-icons/saleor.svg', author: 'Saleor', dockerImage: 'ghcr.io/saleor/saleor:3.23', repoUrl: 'https://github.com/saleor/saleor' },
{ id: 'lnd', title: 'LND', version: '0.18.4', description: 'Lightning Network Daemon. Fast and cheap Bitcoin payments through the Lightning Network.', icon: '/assets/img/app-icons/lnd.svg', author: 'Lightning Labs', dockerImage: `${R}/lnd:v0.18.4-beta`, repoUrl: 'https://github.com/lightningnetwork/lnd' },
{ id: 'mempool', title: 'Mempool Explorer', version: '3.0.0', description: 'Self-hosted Bitcoin blockchain and mempool visualizer. Monitor transactions without revealing your addresses to third parties.', icon: '/assets/img/app-icons/mempool.webp', author: 'Mempool', dockerImage: `${R}/mempool-frontend:v3.0.0`, repoUrl: 'https://github.com/mempool/mempool' },
{ id: 'homeassistant', title: 'Home Assistant', version: '2024.1', description: 'Open-source home automation. Control smart home devices privately, on your own hardware.', icon: '/assets/img/app-icons/homeassistant.png', author: 'Home Assistant', dockerImage: `${R}/home-assistant:2024.1`, repoUrl: 'https://github.com/home-assistant/core' },
@@ -163,7 +163,7 @@ export function getCuratedAppList(): MarketplaceApp[] {
title: 'Saleor',
version: '3.23',
category: 'commerce',
description: 'Composable commerce platform with GraphQL API, dashboard, worker, mail testing, and tracing.',
description: 'Composable commerce platform with customer storefront, GraphQL API, dashboard, worker, mail testing, and tracing.',
icon: '/assets/img/app-icons/saleor.svg',
author: 'Saleor',
dockerImage: 'ghcr.io/saleor/saleor:3.23',
@@ -180,6 +180,19 @@ init()
</button>
</div>
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
<!-- v1.7.79-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.79-alpha</span>
<span class="text-xs text-white/40">May 20, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>Saleor now includes the official Saleor Storefront as the customer-facing shop on port 9011.</p>
<p>Launching Saleor opens the storefront, while the admin dashboard remains on port 9010 with generated admin@example.com credentials shown in Archipelago.</p>
<p>Public storefront domains also get same-origin /graphql/ proxying so phones and laptops can reach the local Saleor API through the domain instead of a private node address.</p>
<p>Saleor catalog, marketplace, scanner, and app-session metadata now describe the storefront/dashboard/API split explicitly.</p>
</div>
</div>
<!-- v1.7.78-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
+17 -20
View File
@@ -1,31 +1,28 @@
{
"version": "1.7.78-alpha",
"release_date": "2026-05-20",
"version": "1.7.82-alpha",
"release_date": "2026-05-22",
"changelog": [
"Public Nginx Proxy Manager hosts for Saleor now keep browser GraphQL calls same-origin at `/graphql/` and proxy them to the local API on `8000`, fixing `Failed to fetch` when a public domain such as `noderunner.shop` was loaded from devices that cannot reach the node's private LAN/tailnet API address.",
"Saleor's validated stack changes are now release-ready: dashboard origins on port `9010` are explicitly allowed for dashboard/API calls, preserving the working test-node install path for production nodes.",
"NetBird launches now stay pinned to the unified dashboard/proxy origin on port `8087` instead of following stale runtime-discovered server URLs on `8086`.",
"NetBird's local nginx proxy now routes browser API, OAuth, relay, and WebSocket traffic through `host.containers.internal:8086` instead of a hard-coded rootless Podman gateway IP, and includes the upstream `management.ProxyService` gRPC path.",
"The mobile credentials interstitial now keeps credential lists scrollable and action buttons reachable in both My Apps and the mobile app icon grid.",
"Android WebView popup windows now hand external popup URLs to the system browser, covering app login/signup flows that open secondary windows.",
"Validation passed with `git diff --check`, `cargo check -p archipelago`, and the focused `npm test -- src/views/appSession/__tests__/appSessionConfig.test.ts` suite."
"Saleor storefront proxying now forwards `X-Forwarded-Host`, fixing Next.js Server Actions requests that compared the browser origin with the internal `storefront-app:3000` upstream host.",
"Saleor storefront media now routes `/thumbnail/` and `/media/` through the same `9011` proxy to the Saleor API, fixing product image optimizer failures caused by `localhost:8000` media URLs.",
"The Saleor storefront container receives an explicit internal media origin so rewritten media URLs resolve inside the Podman network without exposing private API ports to browsers.",
"Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for storefront HTML, static assets, GraphQL, media redirects, and optimized product images."
],
"components": [
{
"name": "archipelago",
"current_version": "1.7.78-alpha",
"new_version": "1.7.78-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.78-alpha/archipelago",
"sha256": "49ac959035029fb77cbf001cfabbe7919bc74aee3bb7176067c77ab0d1c97b58",
"size_bytes": 43069480
"current_version": "1.7.82-alpha",
"new_version": "1.7.82-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.82-alpha/archipelago",
"sha256": "d03ef4ab8a2c01fa5c6e98e4f1acf0e39fecfa260bb0c47cbe01405c5ed5a70d",
"size_bytes": 43118248
},
{
"name": "archipelago-frontend-1.7.78-alpha.tar.gz",
"current_version": "1.7.78-alpha",
"new_version": "1.7.78-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.78-alpha/archipelago-frontend-1.7.78-alpha.tar.gz",
"sha256": "a11ed587122fe2150c7439fdb88bfb4f3b999de2c52855bb4ac860b237854943",
"size_bytes": 166486679
"name": "archipelago-frontend-1.7.82-alpha.tar.gz",
"current_version": "1.7.82-alpha",
"new_version": "1.7.82-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.82-alpha/archipelago-frontend-1.7.82-alpha.tar.gz",
"sha256": "be53e82383c3a8480ae9d45870ebe8ab47f6b07e90b16202cba1ee97530364b0",
"size_bytes": 166485959
}
]
}
+17 -20
View File
@@ -1,31 +1,28 @@
{
"version": "1.7.78-alpha",
"release_date": "2026-05-20",
"version": "1.7.82-alpha",
"release_date": "2026-05-22",
"changelog": [
"Public Nginx Proxy Manager hosts for Saleor now keep browser GraphQL calls same-origin at `/graphql/` and proxy them to the local API on `8000`, fixing `Failed to fetch` when a public domain such as `noderunner.shop` was loaded from devices that cannot reach the node's private LAN/tailnet API address.",
"Saleor's validated stack changes are now release-ready: dashboard origins on port `9010` are explicitly allowed for dashboard/API calls, preserving the working test-node install path for production nodes.",
"NetBird launches now stay pinned to the unified dashboard/proxy origin on port `8087` instead of following stale runtime-discovered server URLs on `8086`.",
"NetBird's local nginx proxy now routes browser API, OAuth, relay, and WebSocket traffic through `host.containers.internal:8086` instead of a hard-coded rootless Podman gateway IP, and includes the upstream `management.ProxyService` gRPC path.",
"The mobile credentials interstitial now keeps credential lists scrollable and action buttons reachable in both My Apps and the mobile app icon grid.",
"Android WebView popup windows now hand external popup URLs to the system browser, covering app login/signup flows that open secondary windows.",
"Validation passed with `git diff --check`, `cargo check -p archipelago`, and the focused `npm test -- src/views/appSession/__tests__/appSessionConfig.test.ts` suite."
"Saleor storefront proxying now forwards `X-Forwarded-Host`, fixing Next.js Server Actions requests that compared the browser origin with the internal `storefront-app:3000` upstream host.",
"Saleor storefront media now routes `/thumbnail/` and `/media/` through the same `9011` proxy to the Saleor API, fixing product image optimizer failures caused by `localhost:8000` media URLs.",
"The Saleor storefront container receives an explicit internal media origin so rewritten media URLs resolve inside the Podman network without exposing private API ports to browsers.",
"Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for storefront HTML, static assets, GraphQL, media redirects, and optimized product images."
],
"components": [
{
"name": "archipelago",
"current_version": "1.7.78-alpha",
"new_version": "1.7.78-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.78-alpha/archipelago",
"sha256": "49ac959035029fb77cbf001cfabbe7919bc74aee3bb7176067c77ab0d1c97b58",
"size_bytes": 43069480
"current_version": "1.7.82-alpha",
"new_version": "1.7.82-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.82-alpha/archipelago",
"sha256": "d03ef4ab8a2c01fa5c6e98e4f1acf0e39fecfa260bb0c47cbe01405c5ed5a70d",
"size_bytes": 43118248
},
{
"name": "archipelago-frontend-1.7.78-alpha.tar.gz",
"current_version": "1.7.78-alpha",
"new_version": "1.7.78-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.78-alpha/archipelago-frontend-1.7.78-alpha.tar.gz",
"sha256": "a11ed587122fe2150c7439fdb88bfb4f3b999de2c52855bb4ac860b237854943",
"size_bytes": 166486679
"name": "archipelago-frontend-1.7.82-alpha.tar.gz",
"current_version": "1.7.82-alpha",
"new_version": "1.7.82-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.82-alpha/archipelago-frontend-1.7.82-alpha.tar.gz",
"sha256": "be53e82383c3a8480ae9d45870ebe8ab47f6b07e90b16202cba1ee97530364b0",
"size_bytes": 166485959
}
]
}
+12 -2
View File
@@ -62,7 +62,9 @@ for row in rows:
forward_port = int(port)
except (TypeError, ValueError):
forward_port = None
is_saleor = forward_port == 9010
is_saleor_dashboard = forward_port == 9010
is_saleor_storefront = forward_port == 9011
is_saleor = is_saleor_dashboard or is_saleor_storefront
graphql_location = ""
saleor_proxy_headers = ""
if is_saleor:
@@ -78,7 +80,15 @@ for row in rows:
proxy_set_header Origin "";
}
"""
saleor_proxy_headers = """
if is_saleor_storefront:
saleor_proxy_headers = """
proxy_set_header Accept-Encoding "";
sub_filter_once off;
sub_filter_types text/html application/javascript text/javascript;
sub_filter 'http://api:8000/graphql/' 'https://$host/graphql/';
"""
if is_saleor_dashboard:
saleor_proxy_headers = """
proxy_set_header Accept-Encoding "";
sub_filter_once off;
sub_filter_types text/html;