Files
ginxsom/docs/STATIC_BUILD.md

7.0 KiB

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

# 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

# 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

# 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

# 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

# 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

# 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

# Install Docker
sudo apt install docker.io

# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker

Build Fails

# Clean Docker cache and rebuild
docker system prune -a
make static

Binary Won't Run on Target

# 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:

Advanced Usage

Cross-Compilation

Build for different architectures:

# 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:

./build.sh --nips=1,6,19  # Minimal
./build.sh --nips=1,6,13,17,19,44,59  # Full (default)

Debug Build

# 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

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

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