because it gets syntax highlighted weird because '.' is not valid for like a variable name so the syntax highlighter is splitting the escape phrase at the '.' which means that phrase won't match when unescaped so it fails to get unescaped for example, this would fail: ``` $$ct ```
419 lines
8.6 KiB
Markdown
419 lines
8.6 KiB
Markdown
$index
|
|
|
|
## Introduction
|
|
|
|
We'll need nginx and luarocks. Buildpack has luarocks installed.
|
|
|
|
docker pull openresty/openresty:bookworm-buildpack
|
|
|
|
$ docker run --rm -it -p 80:80 openresty/openresty:bookworm-buildpack
|
|
|
|
Visit `localhost` in browser. Should see OpenResty splash page.
|
|
|
|

|
|
|
|
https://openresty.org/en/getting-started.html#prepare-directory-layout
|
|
|
|
$ mkdir -p logs/ conf/conf.d/ html/
|
|
|
|
https://github.com/openresty/docker-openresty?tab=readme-ov-file#nginx-config-files
|
|
|
|
$ docker run --rm -it -w /opt -v $PWD:/opt openresty/openresty:bookworm-buildpack \
|
|
cp /etc/nginx/conf.d/default.conf /opt/conf.d/
|
|
|
|
edit default.conf
|
|
change `root /usr/local/openresty/nginx/html;` to:
|
|
|
|
root /var/www;
|
|
|
|
`html/index.html`
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title></title>
|
|
</head>
|
|
<body>
|
|
hello world!
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
Start nginx:
|
|
|
|
```console
|
|
$ docker run --rm -it -p 80:80 \
|
|
-v $PWD/conf/conf.d:/etc/nginx/conf.d -v $PWD/html:/var/www \
|
|
openresty/openresty:bookworm-buildpack
|
|
```
|
|
|
|
Then, in another console:
|
|
|
|
```console
|
|
$ curl -v localhost
|
|
* Trying 127.0.0.1:80...
|
|
* Connected to localhost (127.0.0.1) port 80 (#0)
|
|
> GET / HTTP/1.1
|
|
> Host: localhost
|
|
> User-Agent: curl/7.88.1
|
|
> Accept: */*
|
|
>
|
|
< HTTP/1.1 200 OK
|
|
< Server: openresty/1.27.1.2
|
|
< ...
|
|
<
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
...
|
|
<body>
|
|
hello world!
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
If we wanted to write a test for that, we need some packages from `luarocks`.
|
|
|
|
`Dockerfile`
|
|
|
|
```Dockerfile
|
|
FROM openresty/openresty:bookworm-buildpack
|
|
|
|
WORKDIR /opt/app
|
|
|
|
# needed for testing
|
|
RUN luarocks install busted
|
|
RUN luarocks install luajit-curl
|
|
RUN luarocks install luasocket # needed for testing nginx reverse proxy
|
|
```
|
|
|
|
```console
|
|
$ docker build -t test-nginx .
|
|
$ mkdir spec
|
|
```
|
|
|
|
`spec/nginx_spec.moon`
|
|
|
|
```moonscript
|
|
http = require "luajit-curl-helper.http"
|
|
|
|
req = (url) ->
|
|
request = http.init url
|
|
st = request\perform!
|
|
error request\lastError! if not st
|
|
request
|
|
|
|
describe "http://localhost", ->
|
|
it "sends /index.html", ->
|
|
request = req "http://localhost"
|
|
assert.same request\statusCode!, 200
|
|
assert.same request\statusMessage!, "OK"
|
|
assert.same request\body!\match("<body>%s+(.-)%s+</body>"), "hello world!"
|
|
```
|
|
|
|
Start the test server:
|
|
|
|
```console
|
|
$ ct=$(docker run --rm -d \
|
|
-v $PWD/conf/conf.d:/etc/nginx/conf.d \
|
|
-v $PWD/html:/var/www \
|
|
-v $PWD:/opt/app \
|
|
test-nginx)
|
|
```
|
|
|
|
Run the tests.
|
|
|
|
```console
|
|
$ docker exec -t $ct busted
|
|
●
|
|
1 success / 0 failures / 0 errors / 0 pending : 0.008246 seconds
|
|
```
|
|
|
|
Stop the test server.
|
|
|
|
```console
|
|
$ docker exec -t $ct openresty -s stop
|
|
```
|
|
|
|
## Edit hosts
|
|
|
|
Instead of `localhost` we'd like to use an actual domain name. We can do this
|
|
with the `--add-host` option. But before we do that, we want to make sure our
|
|
container does not have access to the internet, otherwise we might
|
|
unintentionally get a response from a domain's server on the internet rather
|
|
than from our test server.
|
|
|
|
$ docker network create --internal no-internet
|
|
|
|
Now we can start the test server with our host:
|
|
|
|
```console
|
|
$ ct=$(docker run --rm -d \
|
|
-v $PWD/conf/conf.d:/etc/nginx/conf.d \
|
|
-v $PWD/html:/var/www \
|
|
-v $PWD:/opt/app \
|
|
--network no-internet \
|
|
--add-host=domain.abc=127.0.0.1 \
|
|
test-nginx)
|
|
```
|
|
|
|
Update our test
|
|
|
|
request = req "http://localhost"
|
|
|
|
to
|
|
|
|
request = req "http://domain.abc"
|
|
|
|
Run the tests.
|
|
|
|
```console
|
|
$ docker exec -t $ct busted
|
|
●
|
|
1 success / 0 failures / 0 errors / 0 pending : 0.008246 seconds
|
|
```
|
|
|
|
Stop the test server.
|
|
|
|
```console
|
|
$ docker exec -t $ct openresty -s stop
|
|
```
|
|
|
|
## Add a test to make sure the test server is offline
|
|
|
|
```moonscript
|
|
describe "test environment", ->
|
|
it "can't connect to the internet", ->
|
|
assert.has_error (-> req "http://example.org"),
|
|
"Couldn't resolve host name"
|
|
```
|
|
|
|
## Create a Makefile
|
|
|
|
Let's create a `Makefile` to make running all these commands easier.
|
|
|
|
`Makefile`
|
|
|
|
```Makefile
|
|
image = test-nginx
|
|
loopback = 127.0.0.1
|
|
|
|
image-build:
|
|
docker build -t $(image) .
|
|
|
|
image-rm:
|
|
docker image rm $(image)
|
|
|
|
test:
|
|
@ct=$(shell docker run --rm -d \
|
|
-v $(PWD)/conf/conf.d:/etc/nginx/conf.d \
|
|
-v $(PWD)/html:/var/www \
|
|
-v $(PWD):/opt/app \
|
|
--network no-internet \
|
|
--add-host=domain.abc=$(loopback) \
|
|
$(image)); \
|
|
docker exec -t $$ct busted; \
|
|
docker exec $$ct openresty -s stop
|
|
```
|
|
|
|
Now we can run tests by running `make test`.
|
|
|
|
```console
|
|
$ make test
|
|
●●
|
|
2 successes / 0 failures / 0 errors / 0 pending : 0.008812 seconds
|
|
```
|
|
|
|
## SSL
|
|
|
|
We want our server to redirect all `http` requests to `https`.
|
|
|
|
Our test:
|
|
|
|
```moonscript
|
|
describe "http://domain.abc", ->
|
|
it "redirects to https", ->
|
|
request = req "http://domain.abc"
|
|
assert.same request\statusCode!, 301
|
|
assert.same request\statusMessage!, "Moved Permanently"
|
|
assert.same request\header!.Location, "https://domain.abc/"
|
|
```
|
|
|
|
```console
|
|
$ make test
|
|
●●◼
|
|
2 successes / 1 failure / 0 errors / 0 pending : 0.010449 seconds
|
|
|
|
Failure → .../luajit/lib/luarocks/rocks-5.1/busted/2.2.0-1/bin/busted @ 3
|
|
http://domain.abc redirects to https
|
|
spec/nginx_spec.moon:24: Expected objects to be the same.
|
|
Passed in:
|
|
(number) 301
|
|
Expected:
|
|
(number) 200
|
|
```
|
|
|
|
Make self-signed certs in Dockerfile:
|
|
|
|
```Dockerfile
|
|
RUN openssl req -x509 -newkey rsa:4096 -nodes \
|
|
-keyout /etc/ssl/private/domain.abc.pem \
|
|
-out /etc/ssl/certs/domain.abc.pem \
|
|
-sha256 -days 365 -subj '/CN=domain.abc' \
|
|
-addext "subjectAltName=DNS:domain.abc"
|
|
```
|
|
|
|
Edit `default.conf`:
|
|
|
|
```
|
|
server {
|
|
listen 80;
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
server_name domain.abc;
|
|
ssl_certificate /etc/ssl/certs/domain.abc.pem;
|
|
ssl_certificate_key /etc/ssl/private/domain.abc.pem;
|
|
```
|
|
|
|
Rebuild the image:
|
|
|
|
```console
|
|
$ make image-rm
|
|
$ make image-build
|
|
```
|
|
|
|
Run tests:
|
|
|
|
```console
|
|
$ make test
|
|
●◼●
|
|
2 successes / 1 failure / 0 errors / 0 pending : 0.009618 seconds
|
|
|
|
Failure → .../luajit/lib/luarocks/rocks-5.1/busted/2.2.0-1/bin/busted @ 3
|
|
http://domain.abc sends /index.html
|
|
spec/nginx_spec.moon:17: Expected objects to be the same.
|
|
Passed in:
|
|
(number) 200
|
|
Expected:
|
|
(number) 301
|
|
```
|
|
|
|
Fix test:
|
|
|
|
```moonscript
|
|
describe "https://domain.abc", ->
|
|
it "sends /index.html", ->
|
|
request = req "https://domain.abc"
|
|
```
|
|
|
|
Run tests:
|
|
|
|
```console
|
|
$ make test
|
|
●●●
|
|
3 successes / 0 failures / 0 errors / 0 pending : 0.017065 seconds
|
|
```
|
|
|
|
## Reverse proxy a subdomain to a Gitea unix socket
|
|
|
|
Add to `default.conf`:
|
|
|
|
```
|
|
server {
|
|
listen 443 ssl;
|
|
server_name git.domain.abc;
|
|
|
|
location / {
|
|
client_max_body_size 1024M;
|
|
proxy_pass http://unix:/run/gitea/gitea.socket;
|
|
proxy_set_header Connection $http_connection;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
```
|
|
|
|
Add subdomain to certs in Dockerfile:
|
|
|
|
```
|
|
-addext "subjectAltName=DNS:domain.abc,DNS:git.domain.abc"
|
|
```
|
|
|
|
Add a test socket server:
|
|
|
|
`spec/unixstreamsrvr.moon`
|
|
|
|
```moonscript
|
|
-- modified from
|
|
-- https://github.com/lunarmodules/luasocket/blob/4844a48fbf76b0400fd7b7e4d15d244484019df1/test/unixstreamsrvr.lua
|
|
socket = require "socket"
|
|
socket.unix = require "socket.unix"
|
|
u = assert socket.unix.stream!
|
|
assert u\bind "/run/gitea/gitea.socket"
|
|
assert u\listen!
|
|
assert u\settimeout 1
|
|
c = assert u\accept!
|
|
|
|
while true
|
|
m = assert c\receive!
|
|
break if m == ""
|
|
print m
|
|
```
|
|
|
|
Add a spec:
|
|
|
|
```moonscript
|
|
describe "https://git.domain.abc", ->
|
|
it "reverse-proxy's request to a gitea unix socket", ->
|
|
socket = fname: "unixstreamsrvr.moon", dir: "/run/gitea", owner: "nobody"
|
|
basepath = debug.getinfo(1).short_src\match"^(.*)/[^/]*$" or "."
|
|
seconds = 0.1
|
|
|
|
os.execute "install -o #{socket.owner} -d #{socket.dir}"
|
|
cmd = "su -s /bin/bash -c 'moon %s' %s"
|
|
server = io.popen cmd\format "#{basepath}/#{socket.fname}", socket.owner
|
|
os.execute "sleep #{seconds}"
|
|
f = io.popen "find #{socket.dir} -type s -ls", "r"
|
|
result = with f\read "*a"
|
|
f\close!
|
|
assert.truthy result\match "nobody%s+nogroup.+#{socket.dir}/gitea.socket"
|
|
|
|
req "https://git.domain.abc"
|
|
|
|
reqheader = with server\read "*a"
|
|
server\close!
|
|
|
|
assert.truthy reqheader\match "Host: git.domain.abc"
|
|
```
|
|
|
|
Edit Makefile:
|
|
|
|
--add-host=git.domain.abc=$(loopback) \
|
|
|
|
Rebuild image:
|
|
|
|
```console
|
|
$ make image-rm image-build
|
|
```
|
|
|
|
Run tests:
|
|
|
|
```console
|
|
$ make test
|
|
●●●●
|
|
4 successes / 0 failures / 0 errors / 0 pending : 0.131619 seconds
|
|
```
|
|
|
|
|
|
## Conclusion
|
|
|
|
|