Archipelago — open-source initial import

This commit is contained in:
Archipelago
2026-08-12 10:55:50 +00:00
commit 4c4417787a
1661 changed files with 358288 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
# Multi-stage Dockerfile for Indeehub Frontend (Next.js)
# Build: podman build -t localhost/indeedhub:latest -f apps/indeedhub/Dockerfile /path/to/indeehub-frontend
# Run: podman run -d --name indeedhub -p 8190:3000 localhost/indeedhub:latest
# ── Stage 1: Dependencies ──
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --ignore-scripts
# ── Stage 2: Build ──
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Inject standalone output mode for containerized deployment
RUN sed -i 's/reactStrictMode: true,/reactStrictMode: true, output: "standalone",/' next.config.js
# Build-time environment — connects to Indeehub production services
ENV NEXT_PUBLIC_APP_ENVIRONMENT=production
ENV NEXT_PUBLIC_APP_URL=http://localhost:8190
ENV NEXT_PUBLIC_API_URL=https://staging-api.indeehub.studio
ENV NEXT_PUBLIC_S3_PRIVATE_BUCKET=indeehub-private
ENV NEXT_PUBLIC_S3_PUBLIC_BUCKET=indeehub-public
ENV NEXT_PUBLIC_ENABLE_APPROVAL_FLOW=false
ENV NEXT_TELEMETRY_DISABLED=1
# Remove shaka-player .d.ts files that break the build (per package.json build script)
RUN rm -f ./node_modules/shaka-player/dist/*.d.ts
# Patch: replace home page with error-resilient version that doesn't crash
# when the Webflow landing page URL is unreachable from the container.
RUN printf '%s\n' \
"import axios from 'axios';" \
"import { HomeClient } from './page.client';" \
"" \
"export const dynamic = 'force-dynamic';" \
"" \
"export default async function Home() {" \
" try {" \
" const response = await axios('https://indeehub-30479a.webflow.io/', { timeout: 8000 });" \
" if (response.status !== 200) throw new Error('Bad status');" \
" const html = String(response.data)" \
" .replace('https://cdn.prod.website-files.com/img/favicon.ico', '/favicon.ico')" \
" .replace('https://cdn.prod.website-files.com/img/webclip.png', '/favicon.ico');" \
" return <HomeClient html={html} />;" \
" } catch {" \
" return <HomeClient html=\"<html><head><title>IndeeHub</title></head><body style='background:#000;color:#fff;font-family:sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0'><div style='text-align:center'><h1>IndeeHub</h1><p>Loading content...</p><script>setTimeout(function(){location.reload()},5000)</script></div></body></html>\" />;" \
" }" \
"}" > src/app/page.tsx
RUN npm run build
# ── Stage 3: Runner ──
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Copy standalone build output
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
CMD ["node", "server.js"]
+53
View File
@@ -0,0 +1,53 @@
# Indeehub — Bitcoin Documentary Streaming
Bitcoin documentary streaming platform featuring God Bless Bitcoin and other educational content about Bitcoin, sovereignty, and decentralized technology.
Self-hosted Next.js app with Nostr identity sign-in via Archipelago's NIP-07 provider.
## Building the Image
The app image is built from the **indeehub-frontend** project at `~/Projects/indeehub-frontend`.
### Option 1: Use the build script
```bash
# From archy repo root
./apps/indeedhub/build-from-prototype.sh
```
### Option 2: Build from source directory
```bash
cd ~/Projects/indeehub-frontend
podman build -t localhost/indeedhub:latest -f ~/Projects/archy/apps/indeedhub/Dockerfile .
```
## Installing from App Store
1. **Build the image** using one of the options above (must exist before install)
2. Go to **Dashboard -> App Store** (Marketplace)
3. Find **Indeehub** and click **Install**
4. On first launch, pick a Nostr identity to sign in with
5. The app appears in **My Apps** once the container is running
## Port
- Web UI: 8190 (maps to container port 3000)
## Container
- Image: `localhost/indeedhub:latest` (built locally, not pulled from a registry)
- Runtime: Node.js 20 (Next.js standalone)
- Port: 8190 -> 3000
- Read-only root filesystem with tmpfs for /tmp and .next/cache
## Nostr Identity
On first launch, Archipelago shows a cypherpunk identity picker modal. Select which of your identities to use for NIP-07 signing. The NIP-07 provider is injected automatically via nginx proxy.
## Services
The app connects to the following external services (configured at build time):
- Indeehub API (content, auth, streaming)
- AWS S3 (media storage via CloudFront CDN)
- Nostr relays (via NIP-07 provider from Archipelago)
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# Build Indeehub container image from the indeehub-frontend project
# Usage: ./build-from-prototype.sh [path-to-indeehub-frontend]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_FRONTEND="$HOME/Projects/indeehub-frontend"
FRONTEND_DIR="${1:-$DEFAULT_FRONTEND}"
IMAGE_TAG="localhost/indeedhub:latest"
if [ ! -d "$FRONTEND_DIR" ]; then
echo "Indeehub frontend not found at: $FRONTEND_DIR"
echo " Set path: $0 /path/to/indeehub-frontend"
exit 1
fi
if [ ! -f "$FRONTEND_DIR/package.json" ]; then
echo "No package.json found in $FRONTEND_DIR — is this the right directory?"
exit 1
fi
# Determine container runtime
RUNTIME="podman"
if ! command -v podman >/dev/null 2>&1; then
RUNTIME="docker"
fi
echo "Building Indeehub from $FRONTEND_DIR using $SCRIPT_DIR/Dockerfile"
$RUNTIME build -t "$IMAGE_TAG" -f "$SCRIPT_DIR/Dockerfile" "$FRONTEND_DIR"
echo "Built $IMAGE_TAG"
echo ""
echo "You can now install Indeehub from the App Store in Archipelago."
echo "Or run directly: $RUNTIME run -d --name indeedhub -p 8190:3000 $IMAGE_TAG"
+104
View File
@@ -0,0 +1,104 @@
app:
id: indeedhub
name: IndeeHub
version: "1.0.0"
description: Bitcoin documentary streaming platform featuring God Bless Bitcoin and other educational content about Bitcoin, sovereignty, and decentralized technology. Sign in with your Nostr identity.
category: community
# The user-facing launcher (app_id "indeedhub"). Container is named "indeedhub"
# (matches the runtime's per-app references + the live container, so the
# orchestrator adopts it). Its nginx (listen 7777) proxies to the backends by
# their short aliases on indeedhub-net: api:4000, minio:9000, relay:8080.
container_name: indeedhub
container:
image: 146.59.87.168:3000/lfg2025/indeedhub:1.0.0
pull_policy: if-not-present
network: indeedhub-net
dependencies:
- app_id: indeedhub-api
- storage: 1Gi
resources:
memory_limit: 512Mi
disk_limit: 1Gi
security:
# nginx master runs as root and drops workers to the nginx user (uid/gid
# 101) — needs SET{UID,GID}; CHOWN + DAC_OVERRIDE let it own + write the
# proxy cache under the tmpfs /var/cache/nginx. The orchestrator does
# --cap-drop=ALL, so (unlike the legacy `podman run` default caps) these
# must be declared or nginx workers die with "setgid(101) failed".
capabilities: [CHOWN, DAC_OVERRIDE, SETGID, SETUID]
readonly_root: false
network_policy: isolated
ports:
- host: 7778
container: 7777
protocol: tcp # Web UI. Port 7777 on the host is reserved for the Nostr relay.
# Writable scratch the baked nginx needs; matches the legacy installer's
# --tmpfs /run + /var/cache/nginx.
volumes:
- type: tmpfs
target: /run
options: [rw, nosuid, nodev, size=16m]
- type: tmpfs
target: /var/cache/nginx
options: [rw, nosuid, nodev, size=32m]
environment: []
# Defensive + idempotent. The current indeedhub:1.0.0 image already bakes the
# iframe-friendly nginx (X-Frame-Options omitted, nostr-provider.js present +
# <script> injected), so these are mostly no-ops on that tag — but they keep
# the app iframe-loadable + the provider script fresh for any image build that
# predates the bake. copy_from_host pulls /opt/archipelago/web-ui/nostr-provider.js
# (kept current by frontend OTA releases). Replaces the legacy hardcoded
# patch_indeedhub_nostr_provider() Rust hook.
hooks:
post_install:
- exec: ["sed", "-i", "/X-Frame-Options/d", "/etc/nginx/conf.d/default.conf"]
- copy_from_host:
src: "web-ui/nostr-provider.js"
dest: "/usr/share/nginx/html/nostr-provider.js"
- exec: ["sh", "-c", "grep -q nostr-provider /etc/nginx/conf.d/default.conf || sed -i 's#</head>#<script src=\"/nostr-provider.js\"></script></head>#' /etc/nginx/conf.d/default.conf"]
- exec: ["nginx", "-s", "reload"]
# TCP liveness on the nginx port, NOT an http GET of /. nginx binds 7777 at
# startup (before workers), so this passes immediately and stays green under
# load. An http check of / runs the SPA + sub_filter and false-fails when the
# node is busy → the reconciler then treats the frontend as wedged and
# recreates it in a loop (observed churning the frontend on the loaded .198).
health_check:
type: tcp
endpoint: localhost:7777
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
interfaces:
main:
name: Web UI
description: Stream Bitcoin documentaries with Nostr identity
type: ui
port: 7778
protocol: http
path: /
metadata:
author: Indeehub Team
icon: /assets/img/app-icons/indeedhub.png
website: https://indeedhub.com
repo: https://github.com/indeedhub/indeedhub
license: MIT
tags:
- bitcoin
- documentary
- streaming
- media
- education
- nostr
+70
View File
@@ -0,0 +1,70 @@
#!/bin/bash
# Build and push Indeehub container image to a registry
# Usage: ./push-to-registry.sh [version]
#
# Environment variables:
# REGISTRY - Registry host (default: ghcr.io)
# NAMESPACE - Registry namespace (default: archipelago-os)
# RUNTIME - Container runtime (default: podman)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FRONTEND_DIR="${INDEEHUB_FRONTEND:-$HOME/Projects/indeehub-frontend}"
VERSION="${1:-latest}"
REGISTRY="${REGISTRY:-146.59.87.168:3000}"
NAMESPACE="${NAMESPACE:-lfg2025}"
IMAGE_NAME="indeedhub"
RUNTIME="${RUNTIME:-podman}"
FULL_TAG="${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}"
LATEST_TAG="${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:latest"
if [ ! -d "$FRONTEND_DIR" ]; then
echo "Indeehub frontend not found at: $FRONTEND_DIR"
echo "Set INDEEHUB_FRONTEND=/path/to/indeehub-frontend"
exit 1
fi
echo "=== Indeehub Container Registry Push ==="
echo "Source: $FRONTEND_DIR"
echo "Image: $FULL_TAG"
echo "Runtime: $RUNTIME"
echo ""
# Step 1: Build for linux/amd64 (target architecture)
echo "[1/3] Building image..."
$RUNTIME build --platform linux/amd64 \
-t "$FULL_TAG" \
-t "$LATEST_TAG" \
-t "localhost/${IMAGE_NAME}:latest" \
-t "localhost/${IMAGE_NAME}:${VERSION}" \
-f "$SCRIPT_DIR/Dockerfile" \
"$FRONTEND_DIR"
echo "[2/3] Pushing to registry..."
# Login check
if ! $RUNTIME login --get-login "$REGISTRY" >/dev/null 2>&1; then
echo ""
echo "Not logged in to $REGISTRY."
echo "Run: $RUNTIME login $REGISTRY"
exit 1
fi
$RUNTIME push "$FULL_TAG"
if [ "$VERSION" != "latest" ]; then
$RUNTIME push "$LATEST_TAG"
fi
echo ""
echo "[3/3] Done!"
echo ""
echo "Image pushed: $FULL_TAG"
if [ "$VERSION" != "latest" ]; then
echo "Also tagged: $LATEST_TAG"
fi
echo ""
echo "Federated nodes can now install via:"
echo " podman pull $FULL_TAG"
echo ""
echo "Update marketplace dockerImage to: $FULL_TAG"