After the distribution upgrade of a Linux machine from Bullseye (Debian 11) to Bookworm (Debian 12), the Nginx web server failed to start. The whole distribution upgrade itself failed due to the errors caused by the Nginx upgrade.
As it turns out, the LUA module got removed during the upgrade. Here's what happened and how to fix it.
Typical distribution upgrade procedure. It all seemed to work fine - until the nginx package was upgraded.
root@debian:~# apt-get dist-upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
[...]
Dec 11 09:29:52 debian systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
Dec 11 09:29:52 debian nginx[2425050]: 2025/12/11 09:29:52 [emerg] 2425050#2425050: unknown directive "rewrite_by_lua_block" in /etc/nginx/luaheader.conf:3
Dec 11 09:29:52 debian nginx[2425050]: nginx: configuration file /etc/nginx/nginx.conf test failed
Dec 11 09:29:52 debian systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Dec 11 09:29:52 debian systemd[1]: nginx.service: Failed with result 'exit-code'.
Dec 11 09:29:52 debian systemd[1]: Failed to start nginx.service - A high performance web server and a reverse proxy server.
dpkg: error processing package nginx (--configure):
installed nginx package post-installation script subprocess returned error exit status 1
[...]
Errors were encountered while processing:
nginx
libnginx-mod-http-headers-more-filter
libnginx-mod-http-image-filter
libnginx-mod-stream
libnginx-mod-http-upstream-fair
libnginx-mod-stream-geoip
libnginx-mod-http-uploadprogress
libnginx-mod-http-xslt-filter
libnginx-mod-http-auth-pam
libnginx-mod-http-geoip
libnginx-mod-nchan
libnginx-mod-http-ndk
libnginx-mod-http-cache-purge
libnginx-mod-http-echo
libnginx-mod-http-subs-filter
libnginx-mod-http-perl
libnginx-mod-http-geoip2
libnginx-mod-stream-geoip2
libnginx-mod-http-dav-ext
libnginx-mod-mail
libnginx-mod-http-fancyindex
E: Sub-process /usr/bin/dpkg returned an error code (1)
Taking a closer look at the mentioned file /etc/nginx/luaheader.conf indeed uses the "rewrite_by_lua_block" and is included in multiple server contexts.
The rewrite_by_lua_block is part of the lua-nginx-module. This module is packaged in the libnginx-mod-http-lua package. Was this module not upgraded or installed?
As it turns out, the libnginx-mod-http-lua package was not installed during the upgrade - even though it was installed before. To make this even more confusing, the symlink in /etc/nginx/modules-enabled was renamed from the suffix .conf to .removed. Nginx only enabled dynamic modules ending with .conf.
root@debian:/etc/nginx/modules-enabled# ls -la
total 28
[...]
lrwxrwxrwx 1 root root 61 Apr 20 2020 50-mod-http-image-filter.conf -> /usr/share/nginx/modules-available/mod-http-image-filter.conf
lrwxrwxrwx 1 root root 52 Apr 20 2020 50-mod-http-lua.conf.removed -> /usr/share/nginx/modules-available/mod-http-lua.conf
lrwxrwxrwx 1 root root 53 Apr 20 2020 50-mod-http-perl.conf -> /usr/share/nginx/modules-available/mod-http-perl.conf
[...]
Obviously with the lua module disabled, Nginx will not recognize the rewrite_by_lua_block snippet and will fail with an error.
root@debian:~# nginx -t
2025/12/11 09:31:40 [emerg] 2426763#2426763: unknown directive "rewrite_by_lua_block" in /etc/nginx/luaheader.conf:3
nginx: configuration file /etc/nginx/nginx.conf test failed
The fix is to install the (for whatever reason) missing module and then fix the symlink in /etc/nginx/modules-enabled:
root@debian:~# apt install libnginx-mod-http-lua
root@debian:~# cd /etc/nginx/modules-enabled/
root@debian:/etc/nginx/modules-enabled# ln -s /usr/share/nginx/modules-available/mod-http-lua.conf 50-mod-http-lua.conf
root@debian:/etc/nginx/modules-enabled# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@debian:/etc/nginx/modules-enabled# rm 50-mod-http-lua.conf.removed
rm: remove symbolic link '50-mod-http-lua.conf.removed'? y
The config now works again, and the distribution-upgrade process can be successfully finished:
root@debian:~# apt-get dist-upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
[...]
Removing perl-modules-5.32 (5.32.1-4+deb11u4) ...
Removing python3-requests-toolbelt (0.10.1-1) ...
Removing python3-zope.component (5.1.0-1) ...
Removing python3-zope.event (4.4-3) ...
Removing python3-zope.hookable (5.1.0-1+b4) ...
Removing python3-zope.interface (5.5.2-1+b1) ...
Processing triggers for libc-bin (2.36-9+deb12u13) ...
Processing triggers for mailcap (3.70+nmu1) ...
Processing triggers for nginx (1.22.1-9+deb12u3) ...
Triggering nginx reload ...
No comments yet.
AWS Android Ansible Apache Apple Atlassian BSD Backup Bash Bluecoat CMS Chef Cloud Coding Consul Containers CouchDB DB DNS Databases Docker ELK Elasticsearch Filebeat FreeBSD Galera Git GlusterFS Grafana Graphics HAProxy HTML Hacks Hardware Icinga Influx Internet Java KVM Kibana Kodi Kubernetes LVM LXC Linux Logstash Mac Macintosh Mail MariaDB Minio MongoDB Monitoring Multimedia MySQL NFS Nagios Network Nginx OSSEC OTRS Observability Office OpenSearch PHP Perl Personal PostgreSQL PowerDNS Proxmox Proxy Python Rancher Rant Redis Roundcube SSL Samba Seafile Security Shell SmartOS Solaris Surveillance Systemd TLS Tomcat Ubuntu Unix VMware Varnish Virtualization Windows Wireless Wordpress Wyse ZFS Zoneminder