Skip to content

doc: add Docker container for reference #26

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Nginx/Lua on AlmaLinux

FROM fabiocicerchia/nginx-lua:1.23.2-almalinux8.7-20221201

# The luajit package expects Lua 5.1, but this container has 5.3 so remove that.
# Then build Lua 5.1 and luarocks from source so you can install the luafilesystem module
RUN dnf remove -y lua \
&& dnf install -y cmake luajit readline-devel \
&& cd /tmp \
&& curl https://www.lua.org/ftp/lua-5.1.5.tar.gz -L -o lua-5.1.5.tar.gz \
&& tar -zxvf lua-5.1.5.tar.gz \
&& cd lua-5.1.5 \
&& CFLAGS=-DLUA_USE_LINUX make linux \
&& make install \
&& cd .. \
&& curl https://luarocks.org/releases/luarocks-3.8.0.tar.gz -L -o luarocks-3.8.0.tar.gz \
&& tar -zxvf luarocks-3.8.0.tar.gz \
&& cd luarocks-3.8.0 \
&& ./configure --with-lua-include=/usr/local/include \
&& make install \
&& cd .. \
&& luarocks install luafilesystem

# Build the EmmyLuaDebugger from source for debugging Lua via IntelliJ IDEA
RUN curl https://github.com/EmmyLua/EmmyLuaDebugger/archive/refs/tags/1.0.16.tar.gz \
-L -o EmmyLuaDebugger-1.0.16.tar.gz && \
tar -xzvf EmmyLuaDebugger-1.0.16.tar.gz && \
cd EmmyLuaDebugger-1.0.16 && \
mkdir -p build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ../ && \
make install && \
mkdir -p /usr/local/emmy && \
cp install/bin/emmy_core.so /usr/local/emmy/ && \
cd .. && \
cd ..

# Set the lua_shared_dict, set the nginx root to ./web and load the `htaccess.lua` script (without caching)
RUN sed -i "s@http {@http {\n lua_shared_dict htaccess 16m;\n@g" /etc/nginx/nginx.conf \
&& sed -i "s@root /usr/share/nginx/html;@root /docker/web;@g" /etc/nginx/conf.d/default.conf \
&& sed -i "s@server {@\nserver {\n lua_code_cache off;\n rewrite_by_lua_file /docker/htaccess.lua;\n@g" /etc/nginx/conf.d/default.conf
97 changes: 30 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,31 @@ Physical memory usage of this plugin is insanely low, under 10 KB for each nginx

## Installation

1. Install nginx with the [Lua module](https://github.com/openresty/lua-nginx-module) `libnginx-mod-http-lua` and the `luajit` package.
1. Debian: `apt-get install nginx libnginx-mod-http-lua luajit`
2. Fedora: `yum install nginx libnginx-mod-http-lua luajit`

### Docker container

A Docker container is included as a reference; simply start it via `docker compose up -d`.

If you navigate to http://localhost it will process the sample `web/.htaccess`, which has a RewriteRule mapping http://localhost/go/ to http://localhost/redirect.html.


#### Remote debugging

Using IntelliJ IDEA, you can remotely debug Lua scripts running in an nginx Docker container, using [these steps](https://dev.to/omervk/debugging-lua-inside-openresty-inside-docker-with-intellij-idea-2h95). In particular, this has been tested on a Windows 10 host running IntelliJ IDEA 2022.2.4 (Community Edition).

It assumes you are mapping a host path of `C:\path\to\project\on\windows` to a path in the container volume of `/docker`.

1. Install [IntelliJ IDEA](https://www.jetbrains.com/idea/download/#section=windows)
1. At the top of `htaccess.lua`, uncomment the debugging block and update the Windows path mapping.
1. In IDEA, create a Run/Debug configuration per the link above and then start the debugger

When you request a URL that triggers the Lua script, it will pause on the `dbg.breakHere()` line so you can step through the code, watch variables, etc.

### Manual installation

1. Install nginx with the [Lua module](https://github.com/openresty/lua-nginx-module) `libnginx-mod-http-lua` and the `luajit` and `luarocks` packages.
1. Debian: `apt-get install nginx libnginx-mod-http-lua luajit luarocks`
2. Fedora: `dnf install nginx libnginx-mod-http-lua luajit luarocks`
1. Install the [LuaFileSystem](https://lunarmodules.github.io/luafilesystem/) module via `luarocks install luafilesystem`
1. Verify that the Lua module is properly installed by running:
```bash
nginx -V 2>&1 | tr ' ' '\n' | grep lua
Expand All @@ -67,6 +88,9 @@ Physical memory usage of this plugin is insanely low, under 10 KB for each nginx
http {
...
lua_shared_dict htaccess 16m;

# This is useful for debugging but may cause performance problems
# lua_code_cache off;
...
}
```
Expand Down Expand Up @@ -242,7 +266,7 @@ mod_negotiation | `ForceLanguagePriority` | No |
mod_negotiation | `LanguagePriority` | No |
mod_reflector | `*` | Never | Security reasons
mod_rewrite | `RewriteBase` | Yes |
mod_rewrite | `RewriteCond` | Partial | Environment (E=) flag is unsupported, as are *CondPattern* integer comparisons and some file attribute tests listed in the [documentation](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html)
mod_rewrite | `RewriteCond` | Partial | Environment (E=) flag is unsupported, as are *CondPattern* integer comparisons and some file attribute tests listed in the [documentation](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html).
mod_rewrite | `RewriteEngine` | Yes |
mod_rewrite | `RewriteOptions` | No |
mod_rewrite | `RewriteRule` | Yes |
Expand Down Expand Up @@ -320,65 +344,4 @@ Variables not listed below are not supported.
include snippets/htaccess.conf
...
}
```


## Debugging Lua inside a Docker container

Using IntelliJ IDEA, you can remotely debug Lua scripts like `htaccess.lua` running in an nginx Docker container, using [these steps](https://dev.to/omervk/debugging-lua-inside-openresty-inside-docker-with-intellij-idea-2h95). In particular, this has been tested on a Windows 10 host running IntelliJ IDEA 2022.2.4 (Community Edition), with the `fabiocicerchia/nginx-lua:1.23.2-almalinux8.7-20221201` Docker image from https://hub.docker.com/r/fabiocicerchia/nginx-lua.

It assumes you are mapping a host path of `C:\path\to\project\on\windows` to a path in the container volume of `/path/to/project`.

1. Install [IntelliJ IDEA](https://www.jetbrains.com/idea/download/#section=windows)
1. The container needs to forward port 9966 to allow for Lua debugging. If you are using `docker-compose.yml` it will look something like this:
```yml
version: '2.4'
services:
nginx-lua:
build:
context: .
container_name: nginx-lua
ports:
# For nginx requests over HTTP
- 80:80
# If you support nginx requests over HTTPS
- 443:443
# For Lua debugging
- 9966:9966
volumes:
- ./relative/path/to/project/on/windows/:/path/to/project/
```
1. In the `Dockerfile` for the container, run the following command to build the EmmyLuaDebugger from source:
```bash
RUN dnf install -y cmake && \
curl https://github.com/EmmyLua/EmmyLuaDebugger/archive/refs/tags/1.0.16.tar.gz \
-L -o EmmyLuaDebugger-1.0.16.tar.gz && \
tar -xzvf EmmyLuaDebugger-1.0.16.tar.gz && \
cd EmmyLuaDebugger-1.0.16 && \
mkdir -p build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ../ && \
make install && \
mkdir -p /usr/local/emmy && \
cp install/bin/emmy_core.so /usr/local/emmy/ && \
cd .. && \
cd .. && \
rm -rf EmmyLuaDebugger-1.0.16 EmmyLuaDebugger-1.0.16.tar.gz
```
1. Start the container
1. At the top of your Lua script to debug, add the following:
```lua
_G.emmy = {}
_G.emmy.fixPath = function(path)
return string.gsub(path, '/path/to/project/', 'C:/path/to/project/on/windows')
end

package.cpath = package.cpath .. ';/usr/local/emmy/?.so'
local dbg = require('emmy_core')
dbg.tcpListen('localhost', 9966)
dbg.waitIDE()
dbg.breakHere()
```
1. In IDEA, create a Run/Debug configuration per the link and then start the debugger

When you request a URL that triggers the Lua script, it will pause on the `dbg.breakHere()` line so you can step through the code, watch variables, etc.
```
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: '2.4'
services:
nginx-lua:
build:
context: .
ports:
# For nginx requests over HTTP
- 80:80
# For Lua debugging
- 9966:9966
volumes:
- ./:/docker/
# Edit for your environment
#- ./relative/path/to/project/on/windows/:/path/to/project/
46 changes: 43 additions & 3 deletions htaccess.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@

-- TODO: Sometimes code is executed 4 times for each request due to the way nginx handles requests. Make sure it is cached accordingly.

-- Uncomment the following to enable remote debugging
-- Note that if the container volume path contains dashes, they will need to be escaped - e.g., /path/to/htaccess%-for%-nginx
-- _G.emmy = {}
-- _G.emmy.fixPath = function(path)
-- return path:gsub('/docker/', 'C:/path/to/project/on/windows')
-- end

-- package.cpath = package.cpath .. ';/usr/local/emmy/?.so'
-- local dbg = require('emmy_core')
-- dbg.tcpListen('localhost', 9966)
-- dbg.waitIDE()
-- dbg.breakHere()

-- Error function, returns HTTP 500 and logs an error message
local fail = function(msg)
if msg then
Expand Down Expand Up @@ -137,6 +150,27 @@ local path_exists = function(filepath, soft_fail)
return ok
end

-- Get the type of a file system object
-- @param filepath .... the filename
-- @return file_type .. One of (directory|link|file), or nil if the path is invalid
local get_file_type = function(filepath)
local lfs = require "lfs"
local file_type = nil
if (lfs.symlinkattributes (filepath) ~= nil) then
local attr = lfs.symlinkattributes (filepath);
assert (type(attr) == "table")
if attr.mode == "directory" then
file_type = 'directory'
elseif attr['target'] ~= nil then
-- print ("*** symlink found "..attr['target'])
file_type = 'link'
else
file_type = 'file'
end
end
return file_type
end

-- Read contents of any file
local get_file_contents = function(name)
ensure_doc_root(name) -- Security: enforce document root
Expand Down Expand Up @@ -770,7 +804,7 @@ local replace_server_vars = function(str, track_used_headers)
replace = os.date('%w')
end
elseif whitelist[svar] then
replace = ngx.var[svar]
replace = ngx.var[svar] or ''
elseif svar == 'request_uri' then -- %{REQUEST_URI}
-- Use ngx.var['uri'] to match the Apache convention since it doesn't contain the query string
replace = ngx.var['uri']
Expand Down Expand Up @@ -1088,10 +1122,16 @@ if get_cdir('rewrite') and #parsed_rewriterules > 0 then
fail('RewriteCond expressions ("expr ...") are unsupported') -- We don't support expr style conditions due to their weird complexity and redundancy
elseif cond_pattern:sub(1,1) == '-' then -- File attribute tests or integer comparisons (case sensitive)
local filepath = cond_test:gsub('/$','',1)
local file_type = get_file_type(filepath)

cond_matches = false

if cond_pattern == '-d' then -- is directory
cond_matches = path_exists(filepath..'/')
cond_matches = file_type == 'directory'
elseif cond_pattern == '-f' or cond_pattern == '-F' then -- is file
cond_matches = path_exists(filepath) and not path_exists(filepath..'/')
cond_matches = file_type == 'file'
elseif cond_pattern == '-l' or cond_pattern == '-L' then -- is symlink
cond_matches = file_type == 'link'
else
fail('RewriteCond pattern unsupported: '..cond_pattern)
end
Expand Down
7 changes: 7 additions & 0 deletions web/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This is a sample .htaccess file

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^go /redirect.html [L]
</IfModule>
5 changes: 5 additions & 0 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
This is the htaccess-for-nginx webroot
</body>
</html>
5 changes: 5 additions & 0 deletions web/redirect.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
This is redirect.html
</body>
</html>