feat: NostrVPN as native system service, remove FIPS
- Convert NostrVPN from container app to native systemd service - Auto-configure VPN with node's Nostr identity after onboarding - Add nostr-vpn.service with proper capabilities (NET_ADMIN, NET_RAW) - Remove FIPS from marketplace, container config, nginx, image-versions (consolidated into NostrVPN — same mesh VPN concept) - Add AIUI inclusion step to dev CI workflow - AIUI installed on VPS build server for ISO inclusion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
54cb23f07b
commit
42034c0ff9
@ -58,6 +58,16 @@ jobs:
|
|||||||
echo "=== Orchestration integration tests ==="
|
echo "=== Orchestration integration tests ==="
|
||||||
cargo test --test orchestration_tests --no-fail-fast --manifest-path core/Cargo.toml 2>/dev/null || echo "orchestration_tests not found, skipping"
|
cargo test --test orchestration_tests --no-fail-fast --manifest-path core/Cargo.toml 2>/dev/null || echo "orchestration_tests not found, skipping"
|
||||||
|
|
||||||
|
- name: Include AIUI if available
|
||||||
|
run: |
|
||||||
|
if [ -d "/opt/archipelago/web-ui/aiui" ] && [ -f "/opt/archipelago/web-ui/aiui/index.html" ]; then
|
||||||
|
mkdir -p web/dist/neode-ui/aiui
|
||||||
|
cp -r /opt/archipelago/web-ui/aiui/* web/dist/neode-ui/aiui/
|
||||||
|
echo "AIUI included from /opt/archipelago/web-ui/aiui/"
|
||||||
|
else
|
||||||
|
echo "WARNING: AIUI not found on build server — ISO will not include AIUI"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Configure root podman for insecure registry
|
- name: Configure root podman for insecure registry
|
||||||
run: |
|
run: |
|
||||||
sudo mkdir -p /etc/containers/registries.conf.d
|
sudo mkdir -p /etc/containers/registries.conf.d
|
||||||
|
|||||||
@ -106,6 +106,16 @@ impl RpcHandler {
|
|||||||
pub(super) async fn handle_auth_onboarding_complete(&self) -> Result<serde_json::Value> {
|
pub(super) async fn handle_auth_onboarding_complete(&self) -> Result<serde_json::Value> {
|
||||||
self.auth_manager.complete_onboarding().await?;
|
self.auth_manager.complete_onboarding().await?;
|
||||||
tracing::info!("[onboarding] onboarding marked complete");
|
tracing::info!("[onboarding] onboarding marked complete");
|
||||||
|
|
||||||
|
// Auto-configure NostrVPN with the node's Nostr identity
|
||||||
|
let data_dir = self.config.data_dir.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match crate::vpn::configure_nostr_vpn(&data_dir).await {
|
||||||
|
Ok(()) => tracing::info!("[onboarding] NostrVPN configured and started"),
|
||||||
|
Err(e) => tracing::warn!("[onboarding] NostrVPN setup (non-fatal): {}", e),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Ok(serde_json::json!(true))
|
Ok(serde_json::json!(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -124,9 +124,9 @@ pub(super) fn get_app_capabilities(app_id: &str) -> Vec<String> {
|
|||||||
"--cap-add=DAC_OVERRIDE".to_string(),
|
"--cap-add=DAC_OVERRIDE".to_string(),
|
||||||
"--cap-add=NET_BIND_SERVICE".to_string(),
|
"--cap-add=NET_BIND_SERVICE".to_string(),
|
||||||
],
|
],
|
||||||
// Nostr VPN and FIPS: mesh networking daemons need TUN + NET_ADMIN
|
// Nostr VPN: mesh networking needs TUN + NET_ADMIN
|
||||||
// Note: --device=/dev/net/tun is added separately in install.rs
|
// Note: --device=/dev/net/tun is added separately in install.rs
|
||||||
"nostr-vpn" | "fips" => vec![
|
"nostr-vpn" => vec![
|
||||||
"--cap-add=NET_ADMIN".to_string(),
|
"--cap-add=NET_ADMIN".to_string(),
|
||||||
"--cap-add=NET_RAW".to_string(),
|
"--cap-add=NET_RAW".to_string(),
|
||||||
],
|
],
|
||||||
@ -251,7 +251,6 @@ pub(super) fn get_health_check_args(app_id: &str, _rpc_pass: &str) -> Vec<String
|
|||||||
"3",
|
"3",
|
||||||
),
|
),
|
||||||
"nostr-vpn" => ("nvpn status || exit 1", "30s", "3"),
|
"nostr-vpn" => ("nvpn status || exit 1", "30s", "3"),
|
||||||
"fips" => ("fipsctl status || exit 1", "30s", "3"),
|
|
||||||
_ => return vec![],
|
_ => return vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -294,7 +293,6 @@ pub(super) fn get_memory_limit(app_id: &str) -> &'static str {
|
|||||||
"nostr-rs-relay" | "nostr-relay" => "256m",
|
"nostr-rs-relay" | "nostr-relay" => "256m",
|
||||||
"routstr" => "512m",
|
"routstr" => "512m",
|
||||||
"nostr-vpn" => "256m",
|
"nostr-vpn" => "256m",
|
||||||
"fips" => "256m",
|
|
||||||
"nginx-proxy-manager" => "256m",
|
"nginx-proxy-manager" => "256m",
|
||||||
// Databases
|
// Databases
|
||||||
"archy-btcpay-db" | "archy-mempool-db" | "mysql-mempool" => "512m",
|
"archy-btcpay-db" | "archy-mempool-db" | "mysql-mempool" => "512m",
|
||||||
@ -360,7 +358,6 @@ pub(super) fn all_container_names(package_id: &str) -> Vec<String> {
|
|||||||
"penpot-backend".into(), "penpot-exporter".into(), "penpot-frontend".into(),
|
"penpot-backend".into(), "penpot-exporter".into(), "penpot-frontend".into(),
|
||||||
],
|
],
|
||||||
"nostr-vpn" => vec!["nostr-vpn".into(), "archy-nostr-vpn".into(), "archy-nostr-vpn-ui".into()],
|
"nostr-vpn" => vec!["nostr-vpn".into(), "archy-nostr-vpn".into(), "archy-nostr-vpn-ui".into()],
|
||||||
"fips" => vec!["fips".into(), "archy-fips".into(), "archy-fips-ui".into()],
|
|
||||||
"routstr" => vec!["routstr".into(), "archy-routstr".into()],
|
"routstr" => vec!["routstr".into(), "archy-routstr".into()],
|
||||||
// Default: exact name + archy- prefix
|
// Default: exact name + archy- prefix
|
||||||
_ => vec![base, archy],
|
_ => vec![base, archy],
|
||||||
@ -837,27 +834,6 @@ pub(super) async fn get_app_config(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"fips" => {
|
|
||||||
let nsec = read_nostr_secret_hex();
|
|
||||||
let mut env = vec![];
|
|
||||||
if !nsec.is_empty() {
|
|
||||||
env.push(format!("FIPS_NSEC={}", nsec));
|
|
||||||
env.push(format!("FIPS_NPUB={}", read_nostr_pubkey_hex()));
|
|
||||||
}
|
|
||||||
(
|
|
||||||
vec![
|
|
||||||
"2121:2121/udp".to_string(),
|
|
||||||
"8443:8443".to_string(),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
"/var/lib/archipelago/fips/config:/etc/fips".to_string(),
|
|
||||||
"/var/lib/archipelago/fips/run:/run/fips".to_string(),
|
|
||||||
],
|
|
||||||
env,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
"dwn" => (
|
"dwn" => (
|
||||||
vec!["3100:3000".to_string()],
|
vec!["3100:3000".to_string()],
|
||||||
vec!["/var/lib/archipelago/dwn:/dwn/data".to_string()],
|
vec!["/var/lib/archipelago/dwn:/dwn/data".to_string()],
|
||||||
|
|||||||
@ -226,7 +226,7 @@ impl RpcHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TUN device for mesh networking apps
|
// TUN device for mesh networking apps
|
||||||
if matches!(package_id, "nostr-vpn" | "fips") {
|
if package_id == "nostr-vpn" {
|
||||||
run_args.push("--device=/dev/net/tun");
|
run_args.push("--device=/dev/net/tun");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,21 +265,13 @@ impl RpcHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pre-install: write Nostr identity key files for headless Nostr-aware apps
|
// Pre-install: write Nostr identity key files for headless Nostr-aware apps
|
||||||
if matches!(package_id, "nostr-vpn" | "fips") {
|
if package_id == "nostr-vpn" {
|
||||||
let nostr_secret = std::fs::read_to_string("/var/lib/archipelago/identity/nostr_secret")
|
let nostr_secret = std::fs::read_to_string("/var/lib/archipelago/identity/nostr_secret")
|
||||||
.map(|s| s.trim().to_string())
|
.map(|s| s.trim().to_string())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
if !nostr_secret.is_empty() {
|
if !nostr_secret.is_empty() {
|
||||||
let key_dir = match package_id {
|
let key_dir = "/var/lib/archipelago/nostr-vpn";
|
||||||
"nostr-vpn" => "/var/lib/archipelago/nostr-vpn",
|
let key_path = format!("{}/nostr_secret", key_dir);
|
||||||
"fips" => "/var/lib/archipelago/fips/config",
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let key_path = match package_id {
|
|
||||||
"nostr-vpn" => format!("{}/nostr_secret", key_dir),
|
|
||||||
"fips" => format!("{}/fips.key", key_dir),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
tokio::fs::create_dir_all(key_dir).await.ok();
|
tokio::fs::create_dir_all(key_dir).await.ok();
|
||||||
tokio::fs::write(&key_path, &nostr_secret).await.ok();
|
tokio::fs::write(&key_path, &nostr_secret).await.ok();
|
||||||
// Restrict permissions on key file
|
// Restrict permissions on key file
|
||||||
@ -864,9 +856,6 @@ autopilot.active=false\n",
|
|||||||
"nostr-vpn" => {
|
"nostr-vpn" => {
|
||||||
vec![("archy-nostr-vpn-ui", "/opt/archipelago/docker/nostr-vpn-ui", "nostr-vpn-ui")]
|
vec![("archy-nostr-vpn-ui", "/opt/archipelago/docker/nostr-vpn-ui", "nostr-vpn-ui")]
|
||||||
}
|
}
|
||||||
"fips" => {
|
|
||||||
vec![("archy-fips-ui", "/opt/archipelago/docker/fips-ui", "fips-ui")]
|
|
||||||
}
|
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -541,18 +541,6 @@ server {
|
|||||||
proxy_hide_header Content-Security-Policy;
|
proxy_hide_header Content-Security-Policy;
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
}
|
}
|
||||||
location /app/fips/ {
|
|
||||||
proxy_pass http://127.0.0.1:8202/;
|
|
||||||
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-Proto $scheme;
|
|
||||||
proxy_hide_header X-Frame-Options;
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
proxy_hide_header Content-Security-Policy;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
}
|
|
||||||
location /app/ollama/ {
|
location /app/ollama/ {
|
||||||
proxy_pass http://127.0.0.1:11434/;
|
proxy_pass http://127.0.0.1:11434/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|||||||
@ -1,17 +1,36 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Nostr VPN - Mesh VPN with Nostr signaling
|
Description=Nostr VPN - Mesh VPN with Nostr identity
|
||||||
After=network-online.target tor.service
|
After=network-online.target tor.service archipelago.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=root
|
||||||
EnvironmentFile=-/var/lib/archipelago/nostr-vpn/env
|
EnvironmentFile=-/var/lib/archipelago/nostr-vpn/env
|
||||||
|
ExecStartPre=/bin/bash -c 'test -f /var/lib/archipelago/nostr-vpn/env || { echo "NostrVPN not configured — waiting for onboarding"; exit 1; }'
|
||||||
ExecStart=/usr/local/bin/nvpn daemon
|
ExecStart=/usr/local/bin/nvpn daemon
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
|
TimeoutStartSec=30
|
||||||
TimeoutStopSec=10
|
TimeoutStopSec=10
|
||||||
|
|
||||||
|
# Networking capabilities (required for TUN/WireGuard)
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=/var/lib/archipelago/nostr-vpn /run/nostr-vpn /dev/net/tun
|
||||||
|
ProtectHome=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
|
||||||
|
RestrictRealtime=yes
|
||||||
|
|
||||||
|
# Resource limits
|
||||||
|
MemoryMax=256M
|
||||||
|
TasksMax=64
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
StandardError=journal
|
StandardError=journal
|
||||||
|
|||||||
@ -222,17 +222,6 @@ location /app/nostr-vpn/ {
|
|||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
proxy_hide_header Content-Security-Policy;
|
proxy_hide_header Content-Security-Policy;
|
||||||
}
|
}
|
||||||
location /app/fips/ {
|
|
||||||
proxy_pass http://127.0.0.1:8202/;
|
|
||||||
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-Proto $scheme;
|
|
||||||
proxy_hide_header X-Frame-Options;
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
proxy_hide_header Content-Security-Policy;
|
|
||||||
}
|
|
||||||
location /app/ollama/ {
|
location /app/ollama/ {
|
||||||
proxy_pass http://127.0.0.1:11434/;
|
proxy_pass http://127.0.0.1:11434/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|||||||
@ -39,7 +39,6 @@ export const APP_PORTS: Record<string, number> = {
|
|||||||
'fedimint-gateway': 8176,
|
'fedimint-gateway': 8176,
|
||||||
'nostr-rs-relay': 18081,
|
'nostr-rs-relay': 18081,
|
||||||
'nostr-vpn': 8201,
|
'nostr-vpn': 8201,
|
||||||
'fips': 8202,
|
|
||||||
'routstr': 8200,
|
'routstr': 8200,
|
||||||
'indeedhub': 7777,
|
'indeedhub': 7777,
|
||||||
'dwn': 3100,
|
'dwn': 3100,
|
||||||
@ -88,7 +87,6 @@ export const HTTPS_PROXY_PATHS: Record<string, string> = {
|
|||||||
'indeedhub': '/app/indeedhub/',
|
'indeedhub': '/app/indeedhub/',
|
||||||
'routstr': '/app/routstr/',
|
'routstr': '/app/routstr/',
|
||||||
'nostr-vpn': '/app/nostr-vpn/',
|
'nostr-vpn': '/app/nostr-vpn/',
|
||||||
'fips': '/app/fips/',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** External HTTPS apps -- always loaded directly */
|
/** External HTTPS apps -- always loaded directly */
|
||||||
@ -106,7 +104,7 @@ export const EXTERNAL_URLS: Record<string, string> = {
|
|||||||
export const APP_TITLES: Record<string, string> = {
|
export const APP_TITLES: Record<string, string> = {
|
||||||
'bitcoin-knots': 'Bitcoin', 'btcpay-server': 'BTCPay Server', 'indeedhub': 'Indeehub',
|
'bitcoin-knots': 'Bitcoin', 'btcpay-server': 'BTCPay Server', 'indeedhub': 'Indeehub',
|
||||||
'botfights': 'BotFights', '484-kitchen': '484 Kitchen', 'arch-presentation': 'Presentation',
|
'botfights': 'BotFights', '484-kitchen': '484 Kitchen', 'arch-presentation': 'Presentation',
|
||||||
'nostr-vpn': 'Nostr VPN', 'fips': 'FIPS', 'routstr': 'Routstr',
|
'nostr-vpn': 'Nostr VPN', 'routstr': 'Routstr',
|
||||||
'homeassistant': 'Home Assistant', 'uptime-kuma': 'Uptime Kuma',
|
'homeassistant': 'Home Assistant', 'uptime-kuma': 'Uptime Kuma',
|
||||||
'nginx-proxy-manager': 'Nginx Proxy Manager', 'nostr-rs-relay': 'Nostr Relay',
|
'nginx-proxy-manager': 'Nginx Proxy Manager', 'nostr-rs-relay': 'Nostr Relay',
|
||||||
'call-the-operator': 'Call The Operator', 'syntropy-institute': 'Syntropy Institute',
|
'call-the-operator': 'Call The Operator', 'syntropy-institute': 'Syntropy Institute',
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export const SERVICE_NAMES = new Set([
|
|||||||
'mysql-mempool', 'mempool-api', 'archy-mempool-web',
|
'mysql-mempool', 'mempool-api', 'archy-mempool-web',
|
||||||
'archy-bitcoin-ui', 'archy-lnd-ui', 'archy-electrs-ui',
|
'archy-bitcoin-ui', 'archy-lnd-ui', 'archy-electrs-ui',
|
||||||
'indeedhub-postgres', 'indeedhub-redis', 'indeedhub-minio',
|
'indeedhub-postgres', 'indeedhub-redis', 'indeedhub-minio',
|
||||||
'archy-nostr-vpn-ui', 'archy-fips-ui',
|
'archy-nostr-vpn-ui',
|
||||||
'indeedhub-api', 'indeedhub-ffmpeg',
|
'indeedhub-api', 'indeedhub-ffmpeg',
|
||||||
'indeedhub-relay', 'indeedhub-build_api_1', 'indeedhub-build_ffmpeg-worker_1',
|
'indeedhub-relay', 'indeedhub-build_api_1', 'indeedhub-build_ffmpeg-worker_1',
|
||||||
'indeedhub-build_postgres_1', 'indeedhub-build_redis_1', 'indeedhub-build_minio_1',
|
'indeedhub-build_postgres_1', 'indeedhub-build_redis_1', 'indeedhub-build_minio_1',
|
||||||
@ -40,7 +40,7 @@ export const APP_CATEGORY_MAP: Record<string, string> = {
|
|||||||
'homeassistant': 'home', 'lorabell': 'home', 'endurain': 'home',
|
'homeassistant': 'home', 'lorabell': 'home', 'endurain': 'home',
|
||||||
'searxng': 'community', 'ollama': 'community', 'grafana': 'data',
|
'searxng': 'community', 'ollama': 'community', 'grafana': 'data',
|
||||||
'nostr-rs-relay': 'nostr', 'nostrudel': 'nostr',
|
'nostr-rs-relay': 'nostr', 'nostrudel': 'nostr',
|
||||||
'nostr-vpn': 'networking', 'fips': 'networking', 'routstr': 'community',
|
'nostr-vpn': 'networking', 'routstr': 'community',
|
||||||
'tailscale': 'networking', 'nginx-proxy-manager': 'networking', 'portainer': 'networking',
|
'tailscale': 'networking', 'nginx-proxy-manager': 'networking', 'portainer': 'networking',
|
||||||
'uptime-kuma': 'networking', 'dwn': 'data',
|
'uptime-kuma': 'networking', 'dwn': 'data',
|
||||||
'botfights': 'l484', 'nwnn': 'l484', '484-kitchen': 'l484',
|
'botfights': 'l484', 'nwnn': 'l484', '484-kitchen': 'l484',
|
||||||
|
|||||||
@ -30,7 +30,6 @@ export function getCuratedAppList(): MarketplaceApp[] {
|
|||||||
{ id: 'indeedhub', title: 'Indeehub', version: '0.1.0', description: 'Bitcoin documentary streaming with Nostr identity. Stream sovereignty content.', icon: '/assets/img/app-icons/indeedhub.png', author: 'Indeehub Team', dockerImage: 'localhost/indeedhub:latest', repoUrl: 'https://github.com/indeedhub/indeedhub' },
|
{ id: 'indeedhub', title: 'Indeehub', version: '0.1.0', description: 'Bitcoin documentary streaming with Nostr identity. Stream sovereignty content.', icon: '/assets/img/app-icons/indeedhub.png', author: 'Indeehub Team', dockerImage: 'localhost/indeedhub:latest', repoUrl: 'https://github.com/indeedhub/indeedhub' },
|
||||||
{ id: 'dwn', title: 'Decentralized Web Node', version: '0.4.0', description: 'Own your data with DID-based access control. Sync across devices, sovereign.', icon: '/assets/img/app-icons/dwn.svg', author: 'TBD', dockerImage: `${R}/dwn-server:main`, repoUrl: 'https://github.com/TBD54566975/dwn-server' },
|
{ id: 'dwn', title: 'Decentralized Web Node', version: '0.4.0', description: 'Own your data with DID-based access control. Sync across devices, sovereign.', icon: '/assets/img/app-icons/dwn.svg', author: 'TBD', dockerImage: `${R}/dwn-server:main`, repoUrl: 'https://github.com/TBD54566975/dwn-server' },
|
||||||
{ id: 'nostr-vpn', title: 'Nostr VPN', version: '0.3.4', category: 'networking', description: 'Tailscale-style mesh VPN with Nostr control plane. Peer discovery and key exchange over relays, WireGuard tunnels.', icon: '/assets/img/app-icons/nostr-vpn.svg', author: 'Martti Malmi', dockerImage: `${R}/nostr-vpn:v0.3.4`, repoUrl: 'https://github.com/mmalmi/nostr-vpn' },
|
{ id: 'nostr-vpn', title: 'Nostr VPN', version: '0.3.4', category: 'networking', description: 'Tailscale-style mesh VPN with Nostr control plane. Peer discovery and key exchange over relays, WireGuard tunnels.', icon: '/assets/img/app-icons/nostr-vpn.svg', author: 'Martti Malmi', dockerImage: `${R}/nostr-vpn:v0.3.4`, repoUrl: 'https://github.com/mmalmi/nostr-vpn' },
|
||||||
{ id: 'fips', title: 'FIPS', version: '0.1.0', category: 'networking', description: 'Free Internetworking Peering System. Self-organizing encrypted mesh network with Nostr identity.', icon: '/assets/img/app-icons/fips.svg', author: 'Jim Corgan', dockerImage: `${R}/fips:v0.1.0`, repoUrl: 'https://github.com/jmcorgan/fips' },
|
|
||||||
{ id: 'routstr', title: 'Routstr', version: '0.4.3', category: 'community', description: 'Decentralized AI inference proxy. Pay-per-request with Cashu ecash, provider discovery via Nostr.', icon: '/assets/img/app-icons/routstr.svg', author: 'Routstr', dockerImage: `${R}/routstr:v0.4.3`, repoUrl: 'https://github.com/routstr/routstr-core' },
|
{ id: 'routstr', title: 'Routstr', version: '0.4.3', category: 'community', description: 'Decentralized AI inference proxy. Pay-per-request with Cashu ecash, provider discovery via Nostr.', icon: '/assets/img/app-icons/routstr.svg', author: 'Routstr', dockerImage: `${R}/routstr:v0.4.3`, repoUrl: 'https://github.com/routstr/routstr-core' },
|
||||||
{ id: 'nostrudel', title: 'noStrudel', version: '0.40.0', category: 'nostr', description: 'Feature-rich Nostr web client. Browse feeds, post notes, manage relays with NIP-07.', icon: '/assets/img/app-icons/nostrudel.svg', author: 'hzrd149', dockerImage: '', repoUrl: 'https://github.com/hzrd149/nostrudel', webUrl: 'https://nostrudel.ninja' },
|
{ id: 'nostrudel', title: 'noStrudel', version: '0.40.0', category: 'nostr', description: 'Feature-rich Nostr web client. Browse feeds, post notes, manage relays with NIP-07.', icon: '/assets/img/app-icons/nostrudel.svg', author: 'hzrd149', dockerImage: '', repoUrl: 'https://github.com/hzrd149/nostrudel', webUrl: 'https://nostrudel.ninja' },
|
||||||
{ id: 'botfights', title: 'BotFights', version: '1.0.0', description: 'AI bot arena — build, train, and battle autonomous agents in strategy tournaments.', icon: '/assets/img/app-icons/botfights.svg', author: 'BotFights', dockerImage: '', repoUrl: 'https://botfights.net', webUrl: 'https://botfights.net' },
|
{ id: 'botfights', title: 'BotFights', version: '1.0.0', description: 'AI bot arena — build, train, and battle autonomous agents in strategy tournaments.', icon: '/assets/img/app-icons/botfights.svg', author: 'BotFights', dockerImage: '', repoUrl: 'https://botfights.net', webUrl: 'https://botfights.net' },
|
||||||
@ -62,7 +61,6 @@ export const INSTALLED_ALIASES: Record<string, string[]> = {
|
|||||||
tailscale: ['tailscale'],
|
tailscale: ['tailscale'],
|
||||||
ollama: ['ollama'],
|
ollama: ['ollama'],
|
||||||
'nostr-vpn': ['nostr-vpn'],
|
'nostr-vpn': ['nostr-vpn'],
|
||||||
fips: ['fips'],
|
|
||||||
routstr: ['routstr'],
|
routstr: ['routstr'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,6 @@ export const INSTALLED_ALIASES: Record<string, string[]> = {
|
|||||||
tailscale: ['tailscale'],
|
tailscale: ['tailscale'],
|
||||||
ollama: ['ollama'],
|
ollama: ['ollama'],
|
||||||
'nostr-vpn': ['nostr-vpn'],
|
'nostr-vpn': ['nostr-vpn'],
|
||||||
fips: ['fips'],
|
|
||||||
routstr: ['routstr'],
|
routstr: ['routstr'],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,18 +416,6 @@ export function getCuratedAppList(): MarketplaceApp[] {
|
|||||||
manifestUrl: undefined,
|
manifestUrl: undefined,
|
||||||
repoUrl: 'https://github.com/mmalmi/nostr-vpn'
|
repoUrl: 'https://github.com/mmalmi/nostr-vpn'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'fips',
|
|
||||||
title: 'FIPS',
|
|
||||||
version: '0.1.0',
|
|
||||||
category: 'networking',
|
|
||||||
description: 'Free Internetworking Peering System. Self-organizing encrypted mesh network with Nostr identity.',
|
|
||||||
icon: '/assets/img/app-icons/fips.svg',
|
|
||||||
author: 'Jim Corgan',
|
|
||||||
dockerImage: `${REGISTRY}/fips:v0.1.0`,
|
|
||||||
manifestUrl: undefined,
|
|
||||||
repoUrl: 'https://github.com/jmcorgan/fips'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'routstr',
|
id: 'routstr',
|
||||||
title: 'Routstr',
|
title: 'Routstr',
|
||||||
|
|||||||
@ -65,8 +65,6 @@ NOSTR_RS_RELAY_IMAGE="$ARCHY_REGISTRY/nostr-rs-relay:0.9.0"
|
|||||||
STRFRY_IMAGE="$ARCHY_REGISTRY/strfry:1.0.4"
|
STRFRY_IMAGE="$ARCHY_REGISTRY/strfry:1.0.4"
|
||||||
NOSTR_VPN_IMAGE="$ARCHY_REGISTRY/nostr-vpn:v0.3.4"
|
NOSTR_VPN_IMAGE="$ARCHY_REGISTRY/nostr-vpn:v0.3.4"
|
||||||
NOSTR_VPN_UI_IMAGE="$ARCHY_REGISTRY/nostr-vpn-ui:latest"
|
NOSTR_VPN_UI_IMAGE="$ARCHY_REGISTRY/nostr-vpn-ui:latest"
|
||||||
FIPS_IMAGE="$ARCHY_REGISTRY/fips:v0.1.0"
|
|
||||||
FIPS_UI_IMAGE="$ARCHY_REGISTRY/fips-ui:latest"
|
|
||||||
|
|
||||||
# AI / Routing
|
# AI / Routing
|
||||||
ROUTSTR_IMAGE="$ARCHY_REGISTRY/routstr:v0.4.3"
|
ROUTSTR_IMAGE="$ARCHY_REGISTRY/routstr:v0.4.3"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user