v0.1.18 - Add automatic cleanup of dynamic build artifacts after static builds
This commit is contained in:
296
docs/STATIC_BUILD.md
Normal file
296
docs/STATIC_BUILD.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user