# Alpine-based MUSL static binary builder for Ginxsom # Produces truly portable binaries with zero runtime dependencies ARG DEBUG_BUILD=false FROM alpine:3.19 AS builder # Re-declare build argument in this stage ARG DEBUG_BUILD=false # Install build dependencies RUN apk add --no-cache \ build-base \ musl-dev \ git \ cmake \ pkgconfig \ autoconf \ automake \ libtool \ openssl-dev \ openssl-libs-static \ zlib-dev \ zlib-static \ curl-dev \ curl-static \ sqlite-dev \ sqlite-static \ fcgi-dev \ fcgi \ linux-headers \ wget \ bash \ nghttp2-dev \ nghttp2-static \ c-ares-dev \ c-ares-static \ libidn2-dev \ libidn2-static \ libunistring-dev \ libunistring-static \ libpsl-dev \ libpsl-static \ brotli-dev \ brotli-static # Set working directory WORKDIR /build # Build libsecp256k1 static (cached layer - only rebuilds if Alpine version changes) RUN cd /tmp && \ git clone https://github.com/bitcoin-core/secp256k1.git && \ cd secp256k1 && \ ./autogen.sh && \ ./configure --enable-static --disable-shared --prefix=/usr \ CFLAGS="-fPIC" && \ make -j$(nproc) && \ make install && \ rm -rf /tmp/secp256k1 # Copy only submodule configuration and git directory COPY .gitmodules /build/.gitmodules COPY .git /build/.git # Initialize submodules (cached unless .gitmodules changes) RUN git submodule update --init --recursive # Copy nostr_core_lib source files (cached unless nostr_core_lib changes) COPY nostr_core_lib /build/nostr_core_lib/ # Build nostr_core_lib with required NIPs (cached unless nostr_core_lib changes) # Disable fortification in build.sh to prevent __*_chk symbol issues # NIPs: 001(Basic), 006(Keys), 013(PoW), 017(DMs), 019(Bech32), 042(Auth), 044(Encryption), 059(Gift Wrap) RUN cd nostr_core_lib && \ chmod +x build.sh && \ sed -i 's/CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -fPIC -O2"/' build.sh && \ rm -f *.o *.a 2>/dev/null || true && \ ./build.sh --nips=1,6,13,17,19,42,44,59 # Copy web interface files for embedding COPY api/ /build/api/ COPY scripts/embed_web_files.sh /build/scripts/ # Create src directory and embed web files into C headers RUN mkdir -p src && \ chmod +x scripts/embed_web_files.sh && \ ./scripts/embed_web_files.sh # Copy Ginxsom source files LAST (only this layer rebuilds on source changes) COPY src/ /build/src/ COPY include/ /build/include/ # Build Ginxsom with full static linking (only rebuilds when src/ changes) # Disable fortification to avoid __*_chk symbols that don't exist in MUSL # Use conditional compilation flags based on DEBUG_BUILD argument RUN if [ "$DEBUG_BUILD" = "true" ]; then \ CFLAGS="-g -O0 -DDEBUG"; \ STRIP_CMD=""; \ echo "Building with DEBUG symbols enabled"; \ else \ CFLAGS="-O2"; \ STRIP_CMD="strip /build/ginxsom-fcgi_static"; \ echo "Building optimized production binary"; \ fi && \ gcc -static $CFLAGS -Wall -Wextra -std=gnu99 \ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \ -I. -Iinclude -Inostr_core_lib -Inostr_core_lib/nostr_core \ -Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \ src/main.c src/admin_api.c src/admin_auth.c src/admin_event.c \ src/admin_handlers.c src/admin_interface.c src/admin_commands.c \ src/bud04.c src/bud06.c src/bud08.c src/bud09.c \ src/request_validator.c src/relay_client.c \ nostr_core_lib/nostr_core/core_relay_pool.c \ -o /build/ginxsom-fcgi_static \ nostr_core_lib/libnostr_core_x64.a \ -lfcgi -lsqlite3 -lsecp256k1 -lssl -lcrypto -lcurl \ -lnghttp2 -lcares -lidn2 -lunistring -lpsl -lbrotlidec -lbrotlicommon \ -lz -lpthread -lm -ldl && \ eval "$STRIP_CMD" # Verify it's truly static RUN echo "=== Binary Information ===" && \ file /build/ginxsom-fcgi_static && \ ls -lh /build/ginxsom-fcgi_static && \ echo "=== Checking for dynamic dependencies ===" && \ (ldd /build/ginxsom-fcgi_static 2>&1 || echo "Binary is static") && \ echo "=== Build complete ===" # Output stage - just the binary FROM scratch AS output COPY --from=builder /build/ginxsom-fcgi_static /ginxsom-fcgi_static