Files
nixpkgs/pkgs/servers/http/nginx/generic.nix
Martin Weinelt 8d6d3999f9 nginx: make module source trees writable
The config script of multiple nginx modules must be able to write into
its source tree, so let's accumulate this logic once in nginx instead of
in multiple modules.
2026-07-31 21:49:51 +02:00

329 lines
9.0 KiB
Nix

outer@{
lib,
stdenv,
fetchurl,
fetchpatch,
openssl,
zlib-ng,
pcre2,
libxml2,
libxslt,
nginx-doc,
nixosTests,
installShellFiles,
replaceVars,
removeReferencesTo,
gd,
geoip,
perl,
withDebug ? false,
withGeoIP ? false,
withImageFilter ? false,
withKTLS ? true,
withStream ? true,
withMail ? false,
withPerl ? true,
withSlice ? false,
modules ? [ ],
...
}:
{
pname ? "nginx",
version,
nginxVersion ? version,
src ? null, # defaults to upstream nginx ${version}
hash ? null, # when not specifying src
configureFlags ? [ ],
nativeBuildInputs ? [ ],
buildInputs ? [ ],
extraPatches ? [ ],
fixPatch ? p: p,
postPatch ? null,
preConfigure ? "",
preInstall ? "",
postInstall ? "",
meta ? null,
nginx-doc ? outer.nginx-doc,
passthru ? { },
}:
let
moduleNames = map (mod: mod.pname) modules;
mapModules =
attrPath:
lib.flip lib.concatMap modules (
mod:
let
supports = mod.supports or (_: true);
in
if supports nginxVersion then
mod.${attrPath} or [ ]
else
throw "Module ${mod.name} does not support nginx version ${nginxVersion}!"
);
in
assert lib.assertMsg (lib.unique moduleNames == moduleNames)
"nginx: duplicate modules: ${lib.concatStringsSep ", " moduleNames}. A common cause for this is that services.nginx.additionalModules adds a module which the nixos module itself already adds.";
stdenv.mkDerivation {
inherit pname version nginxVersion;
outputs = [
"out"
"doc"
];
src =
if src != null then
src
else
fetchurl {
url = "https://nginx.org/download/nginx-${version}.tar.gz";
inherit hash;
};
nativeBuildInputs = [
installShellFiles
removeReferencesTo
]
++ nativeBuildInputs;
buildInputs = [
openssl
zlib-ng
pcre2
libxml2
libxslt
perl
]
++ buildInputs
++ mapModules "buildInputs"
++ lib.optional withGeoIP geoip
++ lib.optional withImageFilter gd;
configureFlags = [
"--sbin-path=bin/nginx"
"--with-http_ssl_module"
"--with-http_v2_module"
"--with-http_v3_module"
"--with-http_realip_module"
"--with-http_addition_module"
"--with-http_xslt_module"
"--with-http_sub_module"
"--with-http_dav_module"
"--with-http_flv_module"
"--with-http_mp4_module"
"--with-http_gunzip_module"
"--with-http_gzip_static_module"
"--with-http_auth_request_module"
"--with-http_random_index_module"
"--with-http_secure_link_module"
"--with-http_degradation_module"
"--with-http_stub_status_module"
"--with-threads"
"--with-pcre-jit"
"--http-log-path=/var/log/nginx/access.log"
"--error-log-path=/var/log/nginx/error.log"
"--pid-path=/var/log/nginx/nginx.pid"
"--http-client-body-temp-path=/tmp/nginx_client_body"
"--http-proxy-temp-path=/tmp/nginx_proxy"
"--http-fastcgi-temp-path=/tmp/nginx_fastcgi"
"--http-uwsgi-temp-path=/tmp/nginx_uwsgi"
"--http-scgi-temp-path=/tmp/nginx_scgi"
]
++ lib.optionals withDebug [
"--with-debug"
]
++ lib.optionals withKTLS [
"--with-openssl-opt=enable-ktls"
]
++ lib.optionals withStream [
"--with-stream"
"--with-stream_realip_module"
"--with-stream_ssl_module"
"--with-stream_ssl_preread_module"
]
++ lib.optionals withMail [
"--with-mail"
"--with-mail_ssl_module"
]
++ lib.optionals withPerl [
"--with-http_perl_module"
"--with-perl=${perl}/bin/perl"
"--with-perl_modules_path=lib/perl5"
]
++ lib.optional withImageFilter "--with-http_image_filter_module"
++ lib.optional withSlice "--with-http_slice_module"
++ lib.optionals withGeoIP (
[ "--with-http_geoip_module" ] ++ lib.optional withStream "--with-stream_geoip_module"
)
++ lib.optional (with stdenv.hostPlatform; isLinux || isFreeBSD) "--with-file-aio"
++ lib.optional (
stdenv.buildPlatform != stdenv.hostPlatform
) "--crossbuild=${stdenv.hostPlatform.uname.system}::${stdenv.hostPlatform.uname.processor}"
++ configureFlags;
env = {
NIX_CFLAGS_COMPILE = toString (
[
"-I${libxml2.dev}/include/libxml2"
"-Wno-error=implicit-fallthrough"
(
# zlig-ng patch needs this
if stdenv.cc.isGNU then
"-Wno-error=discarded-qualifiers"
else
"-Wno-error=incompatible-pointer-types-discards-qualifiers"
)
]
++ lib.optionals (stdenv.cc.isGNU && lib.versionAtLeast stdenv.cc.version "11") [
# fix build vts module on gcc11
"-Wno-error=stringop-overread"
]
++ lib.optionals stdenv.cc.isClang [
"-Wno-error=deprecated-declarations"
"-Wno-error=gnu-folding-constant"
"-Wno-error=unused-but-set-variable"
]
++ lib.optionals stdenv.hostPlatform.isMusl [
# fix sys/cdefs.h is deprecated
"-Wno-error=cpp"
]
);
}
// lib.optionalAttrs (stdenv.buildPlatform != stdenv.hostPlatform) {
CONFIG_BIG_ENDIAN = if stdenv.hostPlatform.isBigEndian then "y" else "n";
};
configurePlatforms = [ ];
# Disable _multioutConfig hook which adds --bindir=$out/bin into configureFlags,
# which breaks build, since nginx does not actually use autoconf.
preConfigure = ''
setOutputFlags=
''
# Make all modules source trees writable
+ ''
for module in ${toString modules}; do
dst="$NIX_BUILD_TOP/$(basename "$module")"
cp --recursive "$module" "$dst"
chmod --recursive +w "$dst"
appendToVar configureFlags "--add-module=$dst"
done
''
+ preConfigure
+ lib.concatMapStringsSep "\n" (mod: mod.preConfigure or "") modules;
patches =
map fixPatch (
[
./nix-etag-1.15.4.patch
./nix-skip-check-logs-path.patch
]
# Upstream may be against cross-compilation patches.
# https://trac.nginx.org/nginx/ticket/2240 https://trac.nginx.org/nginx/ticket/1928#comment:6
# That dev quit the project in 2024 so the stance could be different now.
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
(fetchpatch {
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/102-sizeof_test_fix.patch";
sha256 = "0i2k30ac8d7inj9l6bl0684kjglam2f68z8lf3xggcc2i5wzhh8a";
})
(fetchpatch {
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/101-feature_test_fix.patch";
sha256 = "0v6890a85aqmw60pgj3mm7g8nkaphgq65dj4v9c6h58wdsrc6f0y";
})
(fetchpatch {
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/103-sys_nerr.patch";
sha256 = "0s497x6mkz947aw29wdy073k8dyjq8j99lax1a1mzpikzr4rxlmd";
})
(fetchpatch {
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/104-endianness_fix.patch";
sha256 = "sha256-M7V3ZJfKImur2OoqXcoL+CbgFj/huWnfZ4xMCmvkqfc=";
})
]
++ mapModules "nginxPatches"
)
++ extraPatches;
postPatch = lib.defaultTo ''
substituteInPlace src/http/ngx_http_core_module.c \
--replace-fail '@nixStoreDir@' "$NIX_STORE" \
--replace-fail '@nixStoreDirLen@' "''${#NIX_STORE}"
'' postPatch;
enableParallelBuilding = true;
preInstall = ''
mkdir -p $doc
cp -r ${nginx-doc}/* $doc
# TODO: make it unconditional when `openresty` and `nginx` are not
# sharing this code.
if [[ -e man/nginx.8 ]]; then
installManPage man/nginx.8
fi
''
+ preInstall;
disallowedReferences = map (m: m.src) modules;
postInstall =
let
noSourceRefs = lib.concatMapStrings (
m: "remove-references-to -t ${m.src} $(readlink -fn $out/bin/nginx)\n"
) modules;
in
postInstall + noSourceRefs;
passthru = {
inherit modules;
tests =
passthru.tests or {
inherit (nixosTests)
nginx
nginx-auth
nginx-etag
nginx-etag-compression
nginx-globalredirect
nginx-http3
nginx-lua
nginx-proxyprotocol
nginx-pubhtml
nginx-sso
nginx-status-page
nginx-unix-socket
;
variants = lib.recurseIntoAttrs nixosTests.nginx-variants;
acme-integration = nixosTests.acme.nginx;
acme-integration-without-reload = nixosTests.acme.nginx-without-reload;
};
}
// lib.optionalAttrs (passthru ? updateScript) {
inherit (passthru) updateScript;
};
meta =
if meta != null then
meta
else
{
description = "Reverse proxy and lightweight webserver";
mainProgram = "nginx";
homepage = "https://nginx.org";
license = [ lib.licenses.bsd2 ] ++ lib.concatMap (m: lib.toList m.meta.license) modules;
broken = lib.any (m: m.meta.broken or false) modules;
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [
helsinki-Jo
ma27
leona
];
};
}