Rework freenginx.sh: options, logging, and error handling #1

Merged
iamdoubz merged 1 commits from build-script-logging into free 2026-10-29 23:03:47 -05:00
2 changed files with 243 additions and 188 deletions

No files matched your search

+8
View File
@@ -29,6 +29,14 @@ There are quite a few dependencies to install. The main ones being:
# How to download
Please use the provided script `freenginx.sh`. Make sure to make it executable first `sudo chmod +x freenginx.sh`. Then run it with `./freenginx.sh`.
By default only the build steps are printed and all output goes to a log file in the build root. Options:
- `-v` stream all build output (still logged), `-q` print only errors and the final summary
- `-r DIR` build root, `-j N` parallel jobs, `-l FILE` log file, `-c` run `make clean` first
- `--no-brotli`, `--no-zstd`, `--no-geoip2`, `--no-headers`, `--no-ktls`, `--no-debug`
- Versions can be set from the environment: `V_NGINX=1.31.6 V_QSSL=3.6.5 ./freenginx.sh`
If a step fails, the script stops and prints the end of the log.
# Make a backup of your existing binary
Type `which nginx` and make a copy i.e. `sudo cp /usr/sbin/nginx /usr/sbin/nginx_apt`. **NOTE**: if you have *not* installed nginx, you do not have to do this step. **NOTE**: this script for freenginx is built as a drop in replacement for nginx.
+235 -188
View File
@@ -1,204 +1,251 @@
#!/bin/sh
####################################
### START change these variables ###
####################################
V_NGINX="1.31.5"
V_ZLIB="1.3.2"
V_PCRE="10.49"
V_QSSL="3.6.5"
V_MAXM="1.14.1"
V_HEAD="0.41"
USE_ZSTD=true
BUILDROOT="/home/dwdoubet/Gits/free"
####################################
#### END change these variables ####
####################################
USE_KTLS=""
BUILD_INFO="w/GeoIP2,Brotli,Zstd,H3,Headers-More,Quantum,debug"
#!/usr/bin/env bash
# Build freenginx from source with bundled zlib/PCRE2/OpenSSL and third-party modules.
# Installing is left to you: cd into the freenginx source dir and run `sudo make install`.
#
# Every setting below can be overridden from the environment, e.g.
# V_NGINX=1.31.6 BUILDROOT=/tmp/free ./freenginx.sh -v
set -Eeuo pipefail
kernelcheck()
{
MAJOR_VERSION=$(uname -r | awk -F '.' '{print $1}')
MINOR_VERSION=$(uname -r | awk -F '.' '{print $2}')
if [ $MAJOR_VERSION -ge 5 ] && [ $MINOR_VERSION -gt 9 ] || [ $MAJOR_VERSION -ge 6 ] ; then
return true
### Versions
: "${V_NGINX:=1.31.5}"
: "${V_ZLIB:=1.3.2}"
: "${V_PCRE:=10.49}"
: "${V_QSSL:=3.6.5}"
: "${V_MAXM:=1.14.1}"
: "${V_HEAD:=0.41}"
### Build settings
: "${BUILDROOT:=$HOME/Gits/free}"
: "${JOBS:=$(nproc)}"
: "${LOG:=}" # default: $BUILDROOT/build-<version>-<timestamp>.log
: "${VERBOSITY:=1}" # 0 = quiet, 1 = steps only, 2 = everything
: "${CLEAN:=0}"
### Optional features (1 = on, 0 = off)
: "${USE_BROTLI:=1}"
: "${USE_ZSTD:=1}"
: "${USE_GEOIP2:=1}"
: "${USE_HEADERS:=1}"
: "${USE_KTLS:=1}"
: "${USE_DEBUG:=1}"
usage() {
cat <<EOF
Usage: ${0##*/} [options]
-r DIR build root (default: $BUILDROOT)
-j N parallel jobs (default: $JOBS)
-l FILE log file (default: <build root>/build-$V_NGINX-<timestamp>.log)
-q quiet: print only errors and the final summary
-v verbose: stream all build output to the terminal (still logged)
-c run 'make clean' in the freenginx tree before configuring
--no-brotli | --no-zstd | --no-geoip2 | --no-headers | --no-ktls | --no-debug
disable an optional feature
-h show this help
Versions come from the top of the script or the environment:
V_NGINX V_ZLIB V_PCRE V_QSSL V_MAXM V_HEAD
EOF
}
while [ $# -gt 0 ]; do
case $1 in
-r) BUILDROOT=${2:?-r needs a directory}; shift ;;
-j) JOBS=${2:?-j needs a number}; shift ;;
-l) LOG=${2:?-l needs a file}; shift ;;
-q) VERBOSITY=0 ;;
-v) VERBOSITY=2 ;;
-c) CLEAN=1 ;;
--no-brotli) USE_BROTLI=0 ;;
--no-zstd) USE_ZSTD=0 ;;
--no-geoip2) USE_GEOIP2=0 ;;
--no-headers) USE_HEADERS=0 ;;
--no-ktls) USE_KTLS=0 ;;
--no-debug) USE_DEBUG=0 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
esac
shift
done
### Logging: everything goes to $LOG; the terminal gets steps (1) or everything (2).
log() { printf '%s\n' "$*" >>"$LOG"; }
step() {
if [ "$VERBOSITY" -ge 1 ]; then printf '==> %s\n' "$*"; fi
printf '\n==> [%s] %s\n' "$(date +%T)" "$*" >>"$LOG"
}
run() {
log "+ $*"
if [ "$VERBOSITY" -ge 2 ]; then "$@" 2>&1 | tee -a "$LOG"; else "$@" >>"$LOG" 2>&1; fi
}
on_error() {
local rc=$?
echo "!! Build failed (exit $rc, line $1). Full log: $LOG" >&2
if [ "$VERBOSITY" -lt 2 ]; then tail -n 30 "$LOG" >&2; fi
exit "$rc"
}
### Helpers
fetch() { # url dir: download and extract into $BUILDROOT unless dir already exists
local url=$1 dir=$2 file=${1##*/}
if [ -d "$dir" ]; then step "$dir (cached)"; return 0; fi
step "Downloading $dir"
run curl -fsSL -o "$file" "$url"
case $file in
*.zip) run unzip -q "$file" ;;
*) run tar -xzf "$file" ;;
esac
rm -f "$file"
}
sync_git() { # url dir: clone, or fast-forward an existing clone
if [ -d "$2/.git" ]; then
step "Updating $2"
run git -C "$2" pull --ff-only
else
return false
step "Cloning $2"
run git clone "$1" "$2"
fi
run git -C "$2" submodule update --init --recursive --jobs "$JOBS"
}
check_dir()
{
path=$1
what=$2
if [ ! -d "$path" ]; then
if [ $what = "create" ]; then
echo " "
echo "Creating directory at $path"
mkdir -p "$path"
elif [ $what = "zlib" ]; then
echo " "
echo "zlib Downloading..."
curl -s -L -O "https://www.zlib.net/zlib-$V_ZLIB.tar.gz"
echo "zlib Extracting..."
tar -xzf "zlib-$V_ZLIB.tar.gz"
rm "zlib-$V_ZLIB.tar.gz"
elif [ $what = "pcre" ]; then
echo " "
echo "pcre2 Downloading..."
curl -s -L -O "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$V_PCRE/pcre2-$V_PCRE.tar.gz"
echo "pcre2 Extracting..."
tar -xzf "pcre2-$V_PCRE.tar.gz"
rm "pcre2-$V_PCRE.tar.gz"
elif [ $what = "openssl" ]; then
echo " "
echo "openssl Downloading..."
curl -s -L -O "https://github.com/openssl/openssl/releases/download/openssl-$V_QSSL/openssl-$V_QSSL.tar.gz"
echo "openssl Extracting..."
tar -xzf "openssl-$V_QSSL.tar.gz"
rm "openssl-$V_QSSL.tar.gz"
elif [ $what = "headers" ]; then
echo " "
echo "Headers More Downloading..."
curl -s -L -O "https://github.com/openresty/headers-more-nginx-module/archive/refs/tags/v$V_HEAD.zip"
echo "Headers More Extracting..."
unzip -qq "v$V_HEAD.zip"
rm "v$V_HEAD.zip"
elif [ $what = "brotli" ]; then
echo " "
echo "Brotli Downloading..."
git clone --quiet --recurse-submodules -j8 https://github.com/google/ngx_brotli ngx-brotli
elif [ $what = "zstd" ]; then
echo " "
echo "Zstd Downloading..."
git clone --quiet https://github.com/HanadaLee/ngx_http_zstd_module.git ngx-zstd
elif [ $what = "geoip2" ]; then
echo " "
echo "GeoIP2 Downloading..."
git clone --quiet https://github.com/leev/ngx_http_geoip2_module nginx-geoip2
elif [ $what = "maxmind" ]; then
echo " "
echo "MaxMind downloading..."
curl -s -L -O "https://github.com/maxmind/libmaxminddb/releases/download/$V_MAXM/libmaxminddb-$V_MAXM.tar.gz"
echo "MaxMind Extracting..."
tar -xzf "libmaxminddb-$V_MAXM.tar.gz"
rm "libmaxminddb-$V_MAXM.tar.gz"
cd "libmaxminddb-$V_MAXM"
./configure &>/dev/null
make &>/dev/null
sudo make install &>/dev/null
# sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf"
sudo ldconfig &>/dev/null
elif [ $what = "ktls" ]; then
if [ kernelcheck ] ; then
echo " "
echo "Enabling KTLS..."
sudo modprobe tls
USE_KTLS=" enable-ktls"
BUILD_INFO="$BUILD_INFO,KTLS"
fi
elif [ $what = "freenginx" ]; then
echo " "
echo "freenginx Downloading..."
curl -s -L -O "https://github.com/freenginx/nginx/archive/refs/tags/release-$V_NGINX.tar.gz"
tar -xzf "release-$V_NGINX.tar.gz"
rm "release-$V_NGINX.tar.gz"
else
echo " "
echo "Path: $path What: $what"
fi
fi
ktls_supported() { # kernel >= 5.10
local maj min
IFS=. read -r maj min _ <<<"$(uname -r)"
[ "$maj" -gt 5 ] || { [ "$maj" -eq 5 ] && [ "$min" -ge 10 ]; }
}
### Main script start
# Create build directory
CURRENTDIR="$BUILDROOT"
check_dir $CURRENTDIR create
cd "$CURRENTDIR"
build_brotli() {
local src=ngx-brotli/deps/brotli
local flags="-Ofast -m64 -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections"
step "Building brotli"
run cmake -S "$src" -B "$src/out" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \
-DCMAKE_C_FLAGS="$flags" -DCMAKE_CXX_FLAGS="$flags" -DCMAKE_INSTALL_PREFIX=./installed
run cmake --build "$src/out" --config Release --target brotlienc -j "$JOBS"
}
# zlib
CURRENTDIR="$BUILDROOT/zlib-$V_ZLIB"
check_dir $CURRENTDIR zlib
install_maxmind() { # system-wide, only the first time a given version is fetched
local dir=libmaxminddb-$V_MAXM
if [ -d "$dir" ]; then step "$dir (cached, assumed installed)"; return 0; fi
fetch "https://github.com/maxmind/libmaxminddb/releases/download/$V_MAXM/$dir.tar.gz" "$dir"
step "Installing $dir system-wide (sudo)"
cd "$dir"
run ./configure
run make -j "$JOBS"
run sudo make install
run sudo ldconfig
cd "$BUILDROOT"
}
# pcre
CURRENTDIR="$BUILDROOT/pcre2-$V_PCRE"
check_dir $CURRENTDIR pcre
### Setup
case $BUILDROOT in /*) ;; *) BUILDROOT=$PWD/$BUILDROOT ;; esac
mkdir -p "$BUILDROOT"
: "${LOG:=$BUILDROOT/build-$V_NGINX-$(date +%Y%m%d-%H%M%S).log}"
case $LOG in /*) ;; *) LOG=$PWD/$LOG ;; esac
mkdir -p "$(dirname "$LOG")"
: >"$LOG"
trap 'on_error $LINENO' ERR
cd "$BUILDROOT"
# openssl
CURRENTDIR="$BUILDROOT/openssl-$V_QSSL"
check_dir $CURRENTDIR openssl
missing=()
for t in curl tar unzip git cmake make cc; do command -v "$t" >/dev/null || missing+=("$t"); done
if [ ${#missing[@]} -gt 0 ]; then echo "Missing required tools: ${missing[*]}" >&2; exit 1; fi
# headers
CURRENTDIR="$BUILDROOT/headers-more-nginx-module-$V_HEAD"
check_dir $CURRENTDIR headers
step "freenginx $V_NGINX in $BUILDROOT (log: $LOG)"
set | grep -E '^(V_[A-Z]+|USE_[A-Z0-9]+|JOBS|BUILDROOT|VERBOSITY|CLEAN)=' >>"$LOG"
# brotli
CURRENTDIR="$BUILDROOT/ngx-brotli"
check_dir $CURRENTDIR brotli
cd "$CURRENTDIR"
git pull --quiet
CURRENTDIR="$BUILDROOT/ngx-brotli/deps/brotli/out"
check_dir $CURRENTDIR create
cd "$CURRENTDIR"
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS="-Ofast -m64 -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" \
-DCMAKE_CXX_FLAGS="-Ofast -m64 -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_INSTALL_PREFIX=./installed .. &>/dev/null
cmake --build . --config Release --target brotlienc &>/dev/null
### Sources
fetch "https://www.zlib.net/zlib-$V_ZLIB.tar.gz" "zlib-$V_ZLIB"
fetch "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$V_PCRE/pcre2-$V_PCRE.tar.gz" "pcre2-$V_PCRE"
fetch "https://github.com/openssl/openssl/releases/download/openssl-$V_QSSL/openssl-$V_QSSL.tar.gz" "openssl-$V_QSSL"
fetch "https://github.com/freenginx/nginx/archive/refs/tags/release-$V_NGINX.tar.gz" "nginx-release-$V_NGINX"
# zstd
if [ $USE_ZSTD ] ; then
CURRENTDIR="$BUILDROOT"
cd "$CURRENTDIR"
CURRENTDIR="$BUILDROOT/ngx-zstd"
check_dir $CURRENTDIR zstd
cd "$CURRENTDIR"
git pull --quiet
### Optional modules (BUILD_INFO order matches the old hardcoded string)
info=() mods=()
if [ "$USE_GEOIP2" = 1 ]; then
install_maxmind
sync_git https://github.com/leev/ngx_http_geoip2_module nginx-geoip2
info+=(GeoIP2); mods+=(--add-module=../nginx-geoip2)
fi
if [ "$USE_BROTLI" = 1 ]; then
sync_git https://github.com/google/ngx_brotli ngx-brotli
build_brotli
info+=(Brotli); mods+=(--add-module=../ngx-brotli)
fi
if [ "$USE_ZSTD" = 1 ]; then
sync_git https://github.com/HanadaLee/ngx_http_zstd_module.git ngx-zstd
info+=(Zstd); mods+=(--add-module=../ngx-zstd)
fi
info+=(H3)
if [ "$USE_HEADERS" = 1 ]; then
fetch "https://github.com/openresty/headers-more-nginx-module/archive/refs/tags/v$V_HEAD.zip" "headers-more-nginx-module-$V_HEAD"
info+=(Headers-More); mods+=(--add-module=../headers-more-nginx-module-$V_HEAD)
fi
info+=(Quantum)
if [ "$USE_DEBUG" = 1 ]; then info+=(debug); mods+=(--with-debug); fi
ktls_opt=""
if [ "$USE_KTLS" = 1 ]; then
if ktls_supported; then
step "Enabling kTLS (sudo)"
run sudo modprobe tls
ktls_opt=" enable-ktls"
info+=(KTLS)
else
step "Kernel $(uname -r) is older than 5.10, skipping kTLS"
fi
fi
build_info="w/$(IFS=,; echo "${info[*]}")"
### Configure and build
SRC=$BUILDROOT/nginx-release-$V_NGINX
cd "$SRC"
if [ "$CLEAN" = 1 ] && [ -f Makefile ]; then
step "Cleaning previous build"
run make clean
fi
# geoip2
CURRENTDIR="$BUILDROOT"
cd "$CURRENTDIR"
CURRENTDIR="$BUILDROOT/nginx-geoip2"
check_dir $CURRENTDIR geoip2
cd "$CURRENTDIR"
git pull --quiet
# maxmind
CURRENTDIR="$BUILDROOT"
cd "$CURRENTDIR"
CURRENTDIR="$BUILDROOT/libmaxminddb-$V_MAXM"
check_dir $CURRENTDIR maxmind
# ktls
CURRENTDIR="$BUILDROOT"
cd "$CURRENTDIR"
CURRENTDIR="$BUILDROOT/ktls"
check_dir $CURRENTDIR ktls
# freenginx
CURRENTDIR="$BUILDROOT"
cd "$CURRENTDIR"
CURRENTDIR="$BUILDROOT/nginx-release-$V_NGINX"
check_dir $CURRENTDIR freenginx
cd "$CURRENTDIR"
echo " "
echo " "
echo "Configuring freenginx..."
#make clean &>/dev/null
./auto/configure --build="$BUILD_INFO" --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module \
--with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_realip_module \
--with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module \
--with-http_v2_module --with-http_v3_module --with-stream --with-select_module --with-poll_module --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module \
--with-zlib=../zlib-$V_ZLIB --with-pcre=../pcre2-$V_PCRE --with-openssl=../openssl-$V_QSSL --with-openssl-opt="no-asm no-tests enable-tls1_3$USE_KTLS" \
--add-module='../ngx-brotli' --add-module='../nginx-geoip2' --add-module="../headers-more-nginx-module-$V_HEAD" --add-module="../ngx-zstd" \
step "Configuring freenginx ($build_info)"
run ./auto/configure \
--build="$build_info" \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx --group=nginx \
--with-compat --with-file-aio --with-threads \
--with-http_addition_module --with-http_auth_request_module --with-http_dav_module \
--with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module \
--with-http_realip_module --with-http_secure_link_module --with-http_slice_module \
--with-http_ssl_module --with-http_stub_status_module --with-http_sub_module \
--with-http_v2_module --with-http_v3_module \
--with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module \
--with-select_module --with-poll_module \
--with-zlib="../zlib-$V_ZLIB" \
--with-pcre="../pcre2-$V_PCRE" \
--with-openssl="../openssl-$V_QSSL" \
--with-openssl-opt="no-asm no-tests enable-tls1_3$ktls_opt" \
"${mods[@]}" \
--with-cc-opt="-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-$V_NGINX/debian/debuild-base/nginx-$V_NGINX=. -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC -I../openssl-$V_QSSL/build/include" \
--with-ld-opt="-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L../openssl-$V_QSSL/build/lib" \
--with-debug > config.log
echo " "
make -j8 > make.log
echo " "
$BUILDROOT/nginx-release-$V_NGINX/objs/nginx -V
echo " "
ls -lh $BUILDROOT/nginx-release-$V_NGINX/objs/nginx
--with-ld-opt="-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L../openssl-$V_QSSL/build/lib"
step "Compiling with $JOBS jobs (this takes a while)"
run make -j "$JOBS"
### Summary (always shown, even with -q)
{
echo
"$SRC/objs/nginx" -V 2>&1
ls -lh "$SRC/objs/nginx"
echo
echo "Log: $LOG"
echo "Install: cd $SRC && sudo make install"
} | tee -a "$LOG"