Skip to content

Commit

Permalink
Build on Windows
Browse files Browse the repository at this point in the history
- Windows Docker container to build libModSecurity v3 & nginx w/ModSecurity-nginx
  • Loading branch information
eduar-hte committed May 4, 2024
1 parent 2e4cbf7 commit c999ba8
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 0 deletions.
197 changes: 197 additions & 0 deletions win32/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# ModSecurity-nginx Windows build information <!-- omit from toc -->

## Contents <!-- omit from toc -->

- [References](#references)
- [Prerequisites](#prerequisites)
- [Build](#build)
- [Docker container](#docker-container)
- [Tests](#tests)
- [Miscellaneous](#miscellaneous)

## References

* [Building nginx on the Win32 platform with Visual C](https://nginx.org/en/docs/howto_build_on_win32.html)
* [libModSecurity Windows build information](https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md)
* [ModSecurity-nginx - Compilation](https://github.com/owasp-modsecurity/ModSecurity-nginx#compilation)

## Prerequisites

* [Build Tools for Visual Studio 2022](https://aka.ms/vs/17/release/vs_buildtools.exe)
* Install *Desktop development with C++* workload, which includes:
* MSVC C++ compiler
* Windows SDK
* CMake
* NOTE: The build steps assume this has been installed in `C:\BuildTools`.
* [MSYS2](https://www.msys2.org/)
* For nginx build on Windows
* NOTE: The build steps assume this has been installed in `C:\msys64`.
* [Conan package manager 2.2.2](https://github.com/conan-io/conan/releases/download/2.2.2/conan-2.2.2-windows-x86_64-installer.exe)
* Required to build libModSecurity v3 on Windows.
* Install and then setup the default Conan profile to use the MSVC C++ compiler:
1. Open a command-prompt and set the MSVC C++ compiler environment by executing: `C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat`
2. Execute: `conan profile detect --force`
* [Git for Windows 2.44.0](https://github.com/git-for-windows/git/releases/download/v2.44.0.windows.1/Git-2.44.0-64-bit.exe)
* [Strawberry Perl for Windows](https://strawberryperl.com/)
* nginx build on Windows requires a native Perl build. The one included in MSYS2 triggers the following error:
```
This perl implementation doesn't produce Windows like paths (with backward slash directory separators). Please use an implementation that matches your building platform.
```
* NOTE: The build steps assume this has been installed in `C:\Strawberry\perl`.

## Build

1. Open a command prompt
2. Set up MSVC C++ compiler environment by executing:
```shell
C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat
```
3. From this command prompt, launch a `MSYS2 UCRT64 Shell` (to inherit MSVC C++ compiler environment)
```shell
c:\msys64\ucrt64.exe
```
4. Checkout nginx source code
```shell
git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx.git
cd nginx
```
5. Download third-party libraries
```shell
mkdir objs
mkdir objs/lib
cd objs/lib
echo Downloading PCRE2
wget -q -O - https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.39/pcre2-10.39.tar.gz | tar -xzf -
echo Downloading zlib
wget -q -O - https://www.zlib.net/fossils/zlib-1.3.tar.gz | tar -xzf -
echo Downloading OpenSSL
wget -q -O - https://www.openssl.org/source/openssl-3.0.13.tar.gz | tar -xzf -
```
6. Checkout and build libModSecurity v3
* For more information on libModSecurity v3 build options, see [libModSecurity Windows build information](https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md).
```shell
git clone -c advice.detachedHead=false --depth 1 --branch windows-port https://github.com/eduar-hte/ModSecurity
#git clone -c advice.detachedHead=false --depth 1 https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
git submodule init
git submodule update
vcbuild.bat
cd ..
```
7. Checkout ModSecurity-nginx
```shell
git clone -c advice.detachedHead=false --depth 1 --branch windows-port https://github.com/eduar-hte/ModSecurity-nginx.git
#git clone -c advice.detachedHead=false --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git
cd ../..
```
8. Setup environment variables for nginx build
```shell
# remove (or move) /usr/bin/link conflicting with MSVC link.exe
rm /usr/bin/link
# nginx build on windows requires a native perl build (see prerequisites)
export PATH=/c/Strawberry/perl/bin:$PATH
# avoid perl 'Setting locale failed.' warnings
export LC_ALL=C
# provide location of libModsecurity headers & libraries for
# the ModSecurity-nginx module build
export MODSECURITY_INC=objs/lib/ModSecurity/headers
export MODSECURITY_LIB=objs/lib/ModSecurity/build/win32/build/Release
```
9. Configure nginx build
```shell
auto/configure \
--with-cc=cl \
--with-debug \
--prefix= \
--conf-path=conf/nginx.conf \
--pid-path=logs/nginx.pid \
--http-log-path=logs/access.log \
--error-log-path=logs/error.log \
--sbin-path=nginx.exe \
--http-client-body-temp-path=temp/client_body_temp \
--http-proxy-temp-path=temp/proxy_temp \
--http-fastcgi-temp-path=temp/fastcgi_temp \
--http-scgi-temp-path=temp/scgi_temp \
--http-uwsgi-temp-path=temp/uwsgi_temp \
--with-cc-opt=-DFD_SETSIZE=1024 \
--with-pcre=objs/lib/pcre2-10.39 \
--with-zlib=objs/lib/zlib-1.3 \
--with-openssl=objs/lib/openssl-3.0.13 \
--with-openssl-opt=no-asm \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_auth_request_module \
--add-module=objs/lib/ModSecurity-nginx
```
10. Build nginx
```shell
nmake
```

### Docker container

A `Dockerfile` configuration file is provided in the `docker` subdir that creates a Windows container image which installs the [prerequisites](#prerequisites) and builds libModSecurity v3 and nginx w/ModSecurity-nginx.

NOTE: Windows containers are supported in Docker Desktop for Windows, using the *Switch to Windows containers...* option on the context menu of the system tray icon.

To build the docker image, execute the following command (from the `win32\docker` directory):

* `docker build -t modsecurity_nginx:latest -m 4GB .`

Once the image is generated, the built binaries are located in the `C:\src\nginx\objs` directory.

To extract the built binaries from the image, you can execute the following commands:

* `docker container create --name [container_name] modsecurity_nginx`
* `docker cp [container_name]:C:\src\nginx\objs\nginx.exe .`
* `docker cp [container_name]:C:\src\nginx\objs\libModSecurity.dll .`

Additionally, the image can be used interactively for additional development work by executing:

* `docker run -it modsecurity_nginx`

## Tests

In order to validate the nginx w/ModSecurity-nginx binary it's recommended that you set up and run ModSecurity-nginx tests following these steps:
1. Open a command prompt and go to the directory where `nginx` was built.
2. Clone nginx-tests
```shell
git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx-tests.git test
```
3. Copy `libModSecurity.dll` to the directory where `nginx.exe` is located.
```shell
cd objs
copy objs\lib\ModSecurity\build\win32\Release\build\libModSecurity.dll
```
4. Copy ModSecurity-nginx tests to the nginx tests directory.
```shell
cd ..\test
copy ..\objs\lib\ModSecurity-nginx\tests\*.*
```
5. Run ModSecurity-nginx tests
```shell
set TEST_NGINX_BINARY=..\objs\nginx.exe
prove modsecurity*.t
```
NOTES
* `TEST_NGINX_BINARY` requires path with backslashes. nginx won't work with path with slashes.
* The tests generate nginx configuration and associated files (such as log files) on the temp directory indicated by the `TEMP` environment variable. nginx won't work if the path contains spaces or short path names with the `~` character. You may need to set the `TEMP` environment variable to a path that respects these limitations (such as `C:\TEMP`).
## Miscellaneous
The ModSecurity-nginx connector is built as a static nginx module. It looks as if there's currently no support for dynamic modules on nginx for Windows using MSVC.

It may be possible to cross-compile for Windows using gcc/clang, which may enable building using dynamic modules too.
161 changes: 161 additions & 0 deletions win32/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# escape=`

# References
#
# * Building nginx on the Win32 platform with Visual C
# * https://nginx.org/en/docs/howto_build_on_win32.html
# * libModSecurity Windows build information
# * https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md
# * ModSecurity-nginx - Compilation
# * https://github.com/owasp-modsecurity/ModSecurity-nginx#compilation

ARG FROM_IMAGE=mcr.microsoft.com/windows/servercore:ltsc2022
FROM ${FROM_IMAGE}

# reset the shell.
SHELL ["cmd", "/S", "/C"]

# set up environment to collect install errors.
COPY InstallBuildTools.cmd C:\TEMP\
ADD https://aka.ms/vscollect.exe C:\TEMP\collect.exe

# download channel for fixed install.
ARG CHANNEL_URL=https://aka.ms/vs/17/release/channel
ADD ${CHANNEL_URL} C:\TEMP\VisualStudio.chman

# download and install Build Tools for Visual Studio 2022 for native desktop workload.
ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe
RUN C:\TEMP\InstallBuildTools.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache `
--channelUri C:\TEMP\VisualStudio.chman `
--installChannelUri C:\TEMP\VisualStudio.chman `
--add Microsoft.VisualStudio.Workload.VCTools `
--includeRecommended `
--installPath C:\BuildTools

# download & install git
ARG GIT_VERSION=2.44.0
ARG GIT_BINARY=Git-${GIT_VERSION}-64-bit.exe
ARG GIT_URL=https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/${GIT_BINARY}

COPY git.inf C:\TEMP\
ARG INSTALLER=C:\TEMP\${GIT_BINARY}
ADD ${GIT_URL} ${INSTALLER}
RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES /NOCANCEL `
/NORESTART /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF=git.inf

# download & setup conan (for libModSecurity build)
ARG CONAN_VERSION=2.2.2
ARG CONAN_BINARY=conan-${CONAN_VERSION}-windows-x86_64-installer.exe
ARG CONAN_URL=https://github.com/conan-io/conan/releases/download/${CONAN_VERSION}/${CONAN_BINARY}

ARG INSTALLER=C:\TEMP\${CONAN_BINARY}
ADD ${CONAN_URL} ${INSTALLER}
RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES

# setup conan profile
RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && conan profile detect --force

# download & setup Strawberry Perl (nginx requires a native Windows perl version to build)
ARG PERL_VERSION=5.38.2.2
ARG PERL_BINARY=strawberry-perl-${PERL_VERSION}-64bit.msi
ARG PERL_URL=https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_53822_64bit/${PERL_BINARY}

ARG INSTALLER=C:\TEMP\${PERL_BINARY}
ADD ${PERL_URL} ${INSTALLER}
RUN msiexec /i %INSTALLER% /quiet /qn /norestart

# msys2 (to build nginx)
#
# References
#
# * Using MSYS2 in CI
# * https://www.msys2.org/docs/ci/

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; `
Invoke-WebRequest -UseBasicParsing -uri "https://github.com/msys2/msys2-installer/releases/download/nightly-x86_64/msys2-base-x86_64-latest.sfx.exe" -OutFile msys2.exe; `
.\msys2.exe -y -oC:\; `
Remove-Item msys2.exe ; `
function msys() { C:\msys64\usr\bin\bash.exe @('-lc') + @Args; } `
msys ' '; `
msys 'pacman --noconfirm -Syuu'; `
msys 'pacman --noconfirm -Syuu'; `
msys 'pacman --noconfirm -Scc';

# revert back to the default shell (cmd.exe)
SHELL ["cmd", "/S", "/C"]

# create src dir
ARG SRC_DIR=C:\src

WORKDIR C:\
RUN cmd.exe /C md %SRC_DIR%

WORKDIR ${SRC_DIR}

# nginx
#

RUN git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx.git

ARG NGINX_DIR=${SRC_DIR}\nginx
WORKDIR ${NGINX_DIR}

# nginx/tests
RUN git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx-tests.git test

ARG NGINX_LIBS_DIR=${NGINX_DIR}\objs\lib

# libModSecurity
#

WORKDIR ${NGINX_LIBS_DIR}

ARG MOD_SECURITY_TAG=windows-port
RUN git clone -c advice.detachedHead=false --depth 1 --branch %MOD_SECURITY_TAG% https://github.com/eduar-hte/ModSecurity.git

ARG MOD_SECURITY_DIR=${NGINX_LIBS_DIR}\ModSecurity
WORKDIR ${MOD_SECURITY_DIR}

# fetch submodules (bindings/python, others/libinjection, test/test-cases/secrules-language-tests)
RUN git submodule init
RUN git submodule update

# build
RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && vcbuild.bat

RUN cmd.exe /C copy build\win32\build\Release\libModSecurity.dll ..\..

# ModSecurity-nginx
#

WORKDIR ${NGINX_LIBS_DIR}

ARG MOD_SECURITY_NGINX_TAG=windows-port
RUN git clone -c advice.detachedHead=false --depth 1 --branch %MOD_SECURITY_NGINX_TAG% https://github.com/eduar-hte/ModSecurity-nginx.git

RUN cmd.exe /C copy ModSecurity-nginx\tests\*.* ..\..\test

# nginx w/ModSecurity-nginx
#

WORKDIR ${NGINX_DIR}

COPY build-nginx.sh ${NGINX_DIR}
COPY build-nginx-bootstrap.bat ${NGINX_DIR}

RUN cmd.exe /C build-nginx-bootstrap.bat

# execute ModSecurity-nginx tests
WORKDIR ${NGINX_DIR}\test

RUN set TEST_NGINX_BINARY=..\objs\nginx.exe && prove modsecurity*.t

# setup container's entrypoint
#

WORKDIR ${NGINX_DIR}

# Use developer command prompt and start PowerShell if no other command specified.
ENTRYPOINT ["C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
17 changes: 17 additions & 0 deletions win32/docker/InstallBuildTools.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@rem Copyright (C) Microsoft Corporation. All rights reserved.
@rem Licensed under the MIT license. See LICENSE.txt in the project root for license information.

@if not defined _echo echo off
setlocal enabledelayedexpansion

call %*
if "%ERRORLEVEL%"=="3010" (
exit /b 0
) else (
if not "%ERRORLEVEL%"=="0" (
set ERR=%ERRORLEVEL%
call C:\TEMP\collect.exe -zip:C:\vslogs.zip

exit /b !ERR!
)
)
6 changes: 6 additions & 0 deletions win32/docker/build-nginx-bootstrap.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@echo off
rem Bootstrap to setup MSVC compiler environment and inherit it into bash
call "C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
set MSYSTEM=UCRT64
set MSYS2_PATH_TYPE=inherit
C:\msys64\usr\bin\bash.exe -lc 'cd /c/src/nginx ; ./build-nginx.sh'
Loading

0 comments on commit c999ba8

Please sign in to comment.