feat(metablogizer): Add KISS ULTIME MODE emancipate workflow

Add `metablogizerctl emancipate <name>` command for one-command full
exposure workflow:
1. DNS A record via dnsctl (Gandi/OVH based on availability)
2. Vortex DNS mesh publication
3. HAProxy vhost with SSL/ACME enabled
4. SSL certificate request (webroot mode)
5. Zero-downtime HAProxy reload

Usage:
  metablogizerctl create myblog blog.example.com
  metablogizerctl emancipate myblog

Bump version to 1.1.0.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-06 08:30:58 +01:00
parent 3d26c8a64e
commit e21ca8a060
4 changed files with 235 additions and 2 deletions

View File

@ -663,3 +663,21 @@ _Last updated: 2026-02-07_
- RPCD `fix_ports` method wrapping CLI command - RPCD `fix_ports` method wrapping CLI command
- Visual feedback with modal spinner - Visual feedback with modal spinner
- Updated container.sh to include `dovecot-pop3d` in initial package list. - Updated container.sh to include `dovecot-pop3d` in initial package list.
44. **MetaBlogizer KISS ULTIME MODE (2026-02-07)**
- Added `metablogizerctl emancipate <name>` — one-command full exposure workflow.
- **Workflow steps** (automated in sequence):
- DNS Registration: Creates A record via `dnsctl` (Gandi/OVH based on availability)
- Vortex Mesh: Publishes to mesh via `vortexctl mesh publish`
- HAProxy: Creates backend, server, and vhost with SSL/ACME enabled
- SSL Certificate: Requests ACME cert via `haproxyctl cert add` (webroot mode)
- Zero-downtime Reload: Applies HAProxy config via SIGUSR2
- **Helper functions**:
- `_emancipate_dns()`: Public IP detection, subdomain extraction, dnsctl integration
- `_emancipate_vortex()`: Mesh publication if vortex-dns enabled
- `_emancipate_haproxy()`: UCI backend/server/vhost creation, haproxyctl generate
- `_emancipate_ssl()`: ACME certificate request with status feedback
- `_emancipate_reload()`: Graceful HAProxy reload with restart fallback
- **Usage**: `metablogizerctl create myblog blog.example.com && metablogizerctl emancipate myblog`
- **Tracking**: Stores `emancipated=1` and `emancipated_at` timestamp in UCI
- Part of Punk Exposure architecture (multi-channel emancipation).

View File

@ -51,7 +51,17 @@ _Last updated: 2026-02-07_
- Gossip-based exposure config sync via secubox-p2p - Gossip-based exposure config sync via secubox-p2p
- Created `luci-app-vortex-dns` dashboard - Created `luci-app-vortex-dns` dashboard
### Just Completed (2026-02-06) ### Just Completed (2026-02-07)
- **MetaBlogizer KISS ULTIME MODE** — DONE (2026-02-07)
- Added `metablogizerctl emancipate` command
- One-command workflow: DNS + Vortex + HAProxy + SSL + Reload
- DNS registration via dnsctl (Gandi/OVH based on availability)
- Vortex DNS mesh publication
- HAProxy vhost with SSL and ACME
- Zero-downtime reload via SIGUSR2
### Completed (2026-02-06)
- **AI Insights Dashboard** — DONE - **AI Insights Dashboard** — DONE
- Created `luci-app-ai-insights` - unified view across all AI agents - Created `luci-app-ai-insights` - unified view across all AI agents

View File

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-app-metablogizer PKG_NAME:=secubox-app-metablogizer
PKG_VERSION:=1.0.0 PKG_VERSION:=1.1.0
PKG_RELEASE:=1 PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
@ -17,6 +17,7 @@ endef
define Package/secubox-app-metablogizer/description define Package/secubox-app-metablogizer/description
Static site publisher with auto-vhost creation. Static site publisher with auto-vhost creation.
Supports uhttpd (default) and nginx LXC runtimes. Supports uhttpd (default) and nginx LXC runtimes.
KISS ULTIME MODE: One-command DNS + SSL + Mesh workflow.
endef endef
define Package/secubox-app-metablogizer/install define Package/secubox-app-metablogizer/install

View File

@ -38,6 +38,12 @@ Site Commands:
delete <name> Delete site delete <name> Delete site
sync <name> Sync site from git repo sync <name> Sync site from git repo
publish <name> Publish site (create HAProxy vhost) publish <name> Publish site (create HAProxy vhost)
emancipate <name> KISS ULTIME MODE - Full exposure workflow:
1. DNS A record (Gandi/OVH)
2. Vortex DNS mesh publication
3. HAProxy vhost with SSL
4. ACME certificate
5. Zero-downtime reload
Runtime Commands: Runtime Commands:
runtime Show current runtime runtime Show current runtime
@ -51,6 +57,10 @@ Runtime Selection:
auto - Auto-detect (uhttpd preferred) auto - Auto-detect (uhttpd preferred)
uhttpd - Use uhttpd instances (lightweight) uhttpd - Use uhttpd instances (lightweight)
nginx - Use nginx LXC container (more features) nginx - Use nginx LXC container (more features)
Examples:
metablogizerctl create myblog blog.example.com
metablogizerctl emancipate myblog # Full exposure in one command
EOF EOF
} }
@ -512,6 +522,199 @@ EOF
log_info "Start with: lxc-start -n $NGINX_LXC -d" log_info "Start with: lxc-start -n $NGINX_LXC -d"
} }
# ===========================================
# KISS ULTIME MODE - Emancipate
# ===========================================
_emancipate_dns() {
local name="$1"
local domain="$2"
local zone=$(uci -q get dns-provider.main.zone)
local provider=$(uci -q get dns-provider.main.provider)
[ -z "$zone" ] && { log_warn "[DNS] No zone configured, skipping external DNS"; return 1; }
# Extract subdomain from domain
local subdomain=$(echo "$domain" | sed "s/\.${zone}$//")
# Get public IP
local public_ip=$(curl -s --connect-timeout 5 https://ipv4.icanhazip.com 2>/dev/null | tr -d '\n')
[ -z "$public_ip" ] && { log_warn "[DNS] Cannot detect public IP, skipping DNS"; return 1; }
log_info "[DNS] Registering $subdomain.$zone -> $public_ip via $provider"
# Check if dnsctl is available
if ! command -v dnsctl >/dev/null 2>&1; then
log_warn "[DNS] dnsctl not found, skipping external DNS"
return 1
fi
# Check if provider is available
if ! dnsctl test >/dev/null 2>&1; then
log_warn "[DNS] Provider $provider not configured or credentials invalid"
log_warn "[DNS] Skipping external DNS registration"
return 1
fi
# Add A record
dnsctl add A "$subdomain" "$public_ip" 3600
# Verify propagation (non-blocking)
log_info "[DNS] Verify with: dnsctl verify $domain"
}
_emancipate_vortex() {
local name="$1"
local domain="$2"
# Check if vortexctl is available
if ! command -v vortexctl >/dev/null 2>&1; then
log_info "[VORTEX] vortexctl not found, skipping mesh publication"
return 0
fi
# Check if vortex-dns is enabled
local vortex_enabled=$(uci -q get vortex-dns.main.enabled)
if [ "$vortex_enabled" = "1" ]; then
log_info "[VORTEX] Publishing $name as $domain to mesh"
vortexctl mesh publish "$name" "$domain" 2>/dev/null
else
log_info "[VORTEX] Vortex DNS disabled, skipping mesh publication"
fi
}
_emancipate_haproxy() {
local name="$1"
local domain="$2"
local port=$(uci_get site_${name}.port)
log_info "[HAPROXY] Creating vhost for $domain"
# Create backend
local backend_name="metablog_${name}"
uci set haproxy.${backend_name}=backend
uci set haproxy.${backend_name}.name="$backend_name"
uci set haproxy.${backend_name}.mode="http"
uci set haproxy.${backend_name}.balance="roundrobin"
uci set haproxy.${backend_name}.enabled="1"
# Create server
local server_name="${backend_name}_srv"
uci set haproxy.${server_name}=server
uci set haproxy.${server_name}.backend="$backend_name"
uci set haproxy.${server_name}.name="uhttpd"
uci set haproxy.${server_name}.address="192.168.255.1"
uci set haproxy.${server_name}.port="$port"
uci set haproxy.${server_name}.weight="100"
uci set haproxy.${server_name}.check="1"
uci set haproxy.${server_name}.enabled="1"
# Create vhost with SSL
local vhost_name=$(echo "$domain" | tr '.-' '_')
uci set haproxy.${vhost_name}=vhost
uci set haproxy.${vhost_name}.domain="$domain"
uci set haproxy.${vhost_name}.backend="$backend_name"
uci set haproxy.${vhost_name}.ssl="1"
uci set haproxy.${vhost_name}.ssl_redirect="1"
uci set haproxy.${vhost_name}.acme="1"
uci set haproxy.${vhost_name}.enabled="1"
uci commit haproxy
# Generate HAProxy config
if command -v haproxyctl >/dev/null 2>&1; then
haproxyctl generate 2>/dev/null
fi
}
_emancipate_ssl() {
local domain="$1"
log_info "[SSL] Requesting certificate for $domain"
# Check if haproxyctl is available
if ! command -v haproxyctl >/dev/null 2>&1; then
log_warn "[SSL] haproxyctl not found, skipping SSL"
return 1
fi
# haproxyctl cert add handles ACME webroot mode (no HAProxy restart needed)
haproxyctl cert add "$domain" 2>&1 | while read line; do
echo " $line"
done
if [ -f "/srv/haproxy/certs/$domain.pem" ]; then
log_info "[SSL] Certificate obtained successfully"
else
log_warn "[SSL] Certificate request may still be pending"
log_warn "[SSL] Check with: haproxyctl cert verify $domain"
fi
}
_emancipate_reload() {
log_info "[RELOAD] Applying HAProxy configuration"
/etc/init.d/haproxy reload 2>/dev/null || {
log_warn "[RELOAD] Reload failed, restarting..."
/etc/init.d/haproxy restart 2>/dev/null
}
}
cmd_emancipate() {
local name="$1"
[ -z "$name" ] && { log_error "Site name required"; usage; return 1; }
if ! site_exists "$name"; then
log_error "Site '$name' not found"
log_error "Create first: metablogizerctl create $name <domain>"
return 1
fi
local domain=$(uci_get site_${name}.domain)
[ -z "$domain" ] && { log_error "Site domain not configured"; return 1; }
echo ""
echo "=============================================="
echo " KISS ULTIME MODE: Emancipating $name"
echo "=============================================="
echo ""
# Step 1: DNS Registration (external provider)
_emancipate_dns "$name" "$domain"
# Step 2: Vortex DNS (mesh registration)
_emancipate_vortex "$name" "$domain"
# Step 3: HAProxy vhost + backend
_emancipate_haproxy "$name" "$domain"
# Step 4: SSL Certificate
_emancipate_ssl "$domain"
# Step 5: Reload HAProxy
_emancipate_reload
# Mark site as emancipated
uci set ${CONFIG}.site_${name}.emancipated="1"
uci set ${CONFIG}.site_${name}.emancipated_at="$(date -Iseconds)"
uci commit ${CONFIG}
echo ""
echo "=============================================="
echo " EMANCIPATION COMPLETE"
echo "=============================================="
echo ""
echo " Site: https://$domain"
echo " Status: Published and SSL-protected"
echo " Mesh: $(uci -q get vortex-dns.main.enabled | grep -q 1 && echo 'Published' || echo 'Disabled')"
echo ""
echo " Verify:"
echo " curl -v https://$domain"
echo " dnsctl verify $domain"
echo " haproxyctl cert verify $domain"
echo ""
}
# =========================================== # ===========================================
# Main # Main
# =========================================== # ===========================================
@ -522,6 +725,7 @@ case "${1:-}" in
delete) shift; cmd_delete "$@" ;; delete) shift; cmd_delete "$@" ;;
sync) shift; cmd_sync "$@" ;; sync) shift; cmd_sync "$@" ;;
publish) shift; cmd_publish "$@" ;; publish) shift; cmd_publish "$@" ;;
emancipate) shift; cmd_emancipate "$@" ;;
runtime) shift; cmd_runtime "$@" ;; runtime) shift; cmd_runtime "$@" ;;
status) shift; cmd_status "$@" ;; status) shift; cmd_status "$@" ;;
install-nginx) shift; cmd_install_nginx "$@" ;; install-nginx) shift; cmd_install_nginx "$@" ;;