# Ginxsom Static MUSL Build Guide This guide explains how to build and deploy Ginxsom as a fully static MUSL binary with zero runtime dependencies. ## Overview Ginxsom now supports building as a static MUSL binary using Alpine Linux and Docker. This produces a truly portable binary that works on **any Linux distribution** without requiring any system libraries. ## Benefits | Feature | Static MUSL | Dynamic glibc | |---------|-------------|---------------| | **Portability** | ✓ Any Linux | ✗ Requires matching libs | | **Dependencies** | None | libfcgi, libsqlite3, etc. | | **Deployment** | Copy one file | Build on target | | **Binary Size** | ~7-10 MB | ~2-3 MB + libraries | | **Deployment Time** | ~10 seconds | ~5-10 minutes | ## Prerequisites - Docker installed and running - Internet connection (for first build only) - ~2GB disk space for Docker images ## Quick Start ### 1. Build Static Binary ```bash # Build production binary (optimized, stripped) make static # Or build debug binary (with symbols) make static-debug # Or use the script directly ./build_static.sh ./build_static.sh --debug ``` The binary will be created in `build/ginxsom-fcgi_static_x86_64` (or `_arm64` for ARM systems). ### 2. Verify Binary ```bash # Check if truly static ldd build/ginxsom-fcgi_static_x86_64 # Should output: "not a dynamic executable" # Check file info file build/ginxsom-fcgi_static_x86_64 # Should show: "statically linked" # Check size ls -lh build/ginxsom-fcgi_static_x86_64 ``` ### 3. Deploy to Server ```bash # Use the simplified deployment script ./deploy_static.sh # Or manually copy and start scp build/ginxsom-fcgi_static_x86_64 user@server:/path/to/ginxsom/ ssh user@server chmod +x /path/to/ginxsom/ginxsom-fcgi_static_x86_64 sudo spawn-fcgi -M 666 -u www-data -g www-data \ -s /tmp/ginxsom-fcgi.sock \ -- /path/to/ginxsom/ginxsom-fcgi_static_x86_64 \ --db-path /path/to/db/ginxsom.db \ --storage-dir /var/www/html/blossom ``` ## Build Process Details ### What Happens During Build 1. **Docker Image Creation** (5-10 minutes first time, cached after): - Uses Alpine Linux 3.19 (native MUSL) - Builds secp256k1 statically - Builds nostr_core_lib with required NIPs - Embeds web interface files - Compiles Ginxsom with full static linking 2. **Binary Extraction**: - Extracts binary from Docker container - Verifies static linking - Makes executable 3. **Verification**: - Checks for dynamic dependencies - Reports file size - Tests execution ### Docker Layers (Cached) The Dockerfile uses multi-stage builds with caching: ``` Layer 1: Alpine base + dependencies (cached) Layer 2: Build secp256k1 (cached) Layer 3: Initialize git submodules (cached unless .gitmodules changes) Layer 4: Build nostr_core_lib (cached unless nostr_core_lib changes) Layer 5: Embed web files (cached unless api/ changes) Layer 6: Build Ginxsom (rebuilds when src/ changes) ``` This means subsequent builds are **much faster** (~1-2 minutes) since only changed layers rebuild. ## Deployment Comparison ### Old Dynamic Build Deployment ```bash # 1. Sync entire project (30 seconds) rsync -avz . user@server:/path/ # 2. Build on remote server (5-10 minutes) ssh user@server "cd /path && make clean && make" # 3. Restart service (10 seconds) ssh user@server "sudo systemctl restart ginxsom" # Total: ~6-11 minutes ``` ### New Static Build Deployment ```bash # 1. Build locally once (5-10 minutes first time, cached after) make static # 2. Copy binary (10 seconds) scp build/ginxsom-fcgi_static_x86_64 user@server:/path/ # 3. Restart service (10 seconds) ssh user@server "sudo systemctl restart ginxsom" # Total: ~20 seconds (after first build) ``` ## Cleanup ### Automatic Cleanup The static build script automatically cleans up old dynamic build artifacts (`.o` files and `ginxsom-fcgi` binary) after successfully building the static binary. This keeps your `build/` directory clean. ### Manual Cleanup ```bash # Clean dynamic build artifacts (preserves static binaries) make clean # Clean everything including static binaries make clean-all # Or manually remove specific files rm -f build/*.o rm -f build/ginxsom-fcgi rm -f build/ginxsom-fcgi_static_* ``` ## Troubleshooting ### Docker Not Found ```bash # Install Docker sudo apt install docker.io # Add user to docker group sudo usermod -aG docker $USER newgrp docker ``` ### Build Fails ```bash # Clean Docker cache and rebuild docker system prune -a make static ``` ### Binary Won't Run on Target ```bash # Verify it's static ldd build/ginxsom-fcgi_static_x86_64 # Check architecture matches file build/ginxsom-fcgi_static_x86_64 uname -m # On target system ``` ### Alpine Package Not Found If you get errors about missing Alpine packages, the package name may have changed. Check Alpine's package database: - https://pkgs.alpinelinux.org/packages ## Advanced Usage ### Cross-Compilation Build for different architectures: ```bash # Build for ARM64 on x86_64 machine docker build --platform linux/arm64 -f Dockerfile.alpine-musl -t ginxsom-arm64 . ``` ### Custom NIPs Edit `Dockerfile.alpine-musl` line 66 to change which NIPs are included: ```dockerfile ./build.sh --nips=1,6,19 # Minimal ./build.sh --nips=1,6,13,17,19,44,59 # Full (default) ``` ### Debug Build ```bash # Build with debug symbols (no optimization) make static-debug # Binary will be larger but include debugging info gdb build/ginxsom-fcgi_static_x86_64 ``` ## File Structure ``` ginxsom/ ├── Dockerfile.alpine-musl # Alpine Docker build definition ├── build_static.sh # Build script wrapper ├── deploy_static.sh # Simplified deployment script ├── Makefile # Updated with 'static' target └── build/ └── ginxsom-fcgi_static_x86_64 # Output binary ``` ## CI/CD Integration ### GitHub Actions Example ```yaml name: Build Static Binary on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - name: Build static binary run: make static - name: Upload artifact uses: actions/upload-artifact@v2 with: name: ginxsom-static path: build/ginxsom-fcgi_static_x86_64 ``` ## Performance Static MUSL binaries have minimal performance impact: | Metric | Static MUSL | Dynamic glibc | |--------|-------------|---------------| | Startup Time | ~50ms | ~40ms | | Memory Usage | Similar | Similar | | Request Latency | Identical | Identical | | Binary Size | 7-10 MB | 2-3 MB + libs | The slight startup delay is negligible for a long-running FastCGI process. ## References - [MUSL libc](https://musl.libc.org/) - [Alpine Linux](https://alpinelinux.org/) - [Static Linking Best Practices](https://www.musl-libc.org/faq.html) - [c-relay Static Build](../c-relay/STATIC_BUILD.md) ## Support For issues with static builds: 1. Check Docker is running: `docker info` 2. Verify submodules: `git submodule status` 3. Clean and rebuild: `docker system prune -a && make static` 4. Check logs in Docker build output