diff --git a/Dockerfile b/Dockerfile index 2976516..d213f0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openresty/openresty:1.27.1.2-0-bookworm-buildpack +FROM openresty/openresty:bookworm-buildpack WORKDIR /opt/app @@ -11,7 +11,27 @@ RUN apt-get update && apt-get install -y \ wget -q -O $pkgname $pkgurl && dpkg -i $pkgname && rm $pkgname RUN luarocks install sitegen -RUN luarocks install busted + +# needed for sitegen watcher RUN luarocks install inotify INOTIFY_INCDIR=/usr/include/x86_64-linux-gnu/ +# needed for testing +RUN luarocks install busted +RUN luarocks install luajit-curl +RUN luarocks install luasocket # needed for testing nginx reverse proxy + +RUN mkdir -p /var/www/certs/miti.sh \ + && openssl req -x509 -newkey rsa:4096 -nodes \ + -keyout /var/www/certs/miti.sh/privkey.pem \ + -out /var/www/certs/miti.sh/fullchain.pem \ + -sha256 -days 365 -subj '/CN=miti.sh' \ + -addext "subjectAltName=DNS:miti.sh,DNS:git.miti.sh,DNS:apps.miti.sh" + +RUN mkdir -p /var/www/certs/webdevcat.me \ + && openssl req -x509 -newkey rsa:4096 -nodes \ + -keyout /var/www/certs/webdevcat.me/privkey.pem \ + -out /var/www/certs/webdevcat.me/fullchain.pem \ + -sha256 -days 365 -subj '/CN=webdevcat.me' \ + -addext "subjectAltName=DNS:webdevcat.me,DNS:git.webdevcat.me,DNS:apps.webdevcat.me" + CMD ["sh", "-c", "openresty -p `pwd` -g 'daemon off;'"] diff --git a/Makefile b/Makefile index 0450f57..3d3b558 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,19 @@ +image = miti.sh + run: - docker run --rm -it --init -v $(PWD):/opt/app -p 8080:8080 \ - sitegen-openresty + docker run --rm -it --init -v $(PWD):/opt/app -p 8080:80 $(image) build: - docker run --rm -w /opt/app -v $(PWD):/opt/app sitegen-openresty sitegen + docker run --rm -w /opt/app -v $(PWD):/opt/app $(image) sitegen + +image-rm: + docker image rm $(image):latest + +image-build: + docker build -t $(image) . lint: - docker run --rm -w /opt/app -v $(PWD):/opt/app sitegen-openresty moonc -l . + docker run --rm -w /opt/app -v $(PWD):/opt/app $(image) moonc -l . + +test: + ./test.sh diff --git a/README.md b/README.md index 8341fc9..1cd7362 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,19 @@ ### build docker image - $ docker build -t sitegen-openresty . + $ make image-build + +### rebuild an existing docker image + + $ make image-rm image-build ### generate a new site file - $ docker run --rm -w /opt -v $PWD:/opt sitegen-openresty sitegen new + $ docker run --rm -w /opt/app -v $PWD:/opt/app miti.sh sitegen new ### add an index page - $ docker run --rm -w /opt -v $PWD:/opt sitegen-openresty sitegen page /opt/ index + $ docker run --rm -w /opt/app -v $PWD:/opt/app miti.sh sitegen page /opt/app index ### add to `site.moon` @@ -50,17 +54,9 @@ ### build site - $ docker run --rm -w /opt/app -v $PWD:/opt/app sitegen-openresty sitegen - -or - $ make build -### start server - - $ docker run --rm -it --init -v $PWD:/opt/app -p 8080:8080 sitegen-openresty - -or +### start dev server $ make @@ -70,6 +66,10 @@ Visit `localhost:8080` in web browser $ docker exec -it container_name sitegen watch +### run tests + + $ make test + ### lint moonscript $ make lint @@ -100,8 +100,7 @@ to return `nil`, you will see this cryptic error: Delete your `.sitegen_cache` file. -## todo +## thinking about * draft documents * treesitter highlighting for moonscript -* penlight library diff --git a/app.ini b/app.ini index a8fb316..ba2d8d8 100644 --- a/app.ini +++ b/app.ini @@ -21,12 +21,13 @@ ROOT = /var/lib/gitea/data/gitea-repositories [server] ; SSH_DOMAIN = localhost -SSH_DOMAIN = git.miti.sh ; DOMAIN = localhost DOMAIN = git.miti.sh -HTTP_PORT = 3000 -; ROOT_URL = http://localhost:3000/ -ROOT_URL = https://git.miti.sh +; HTTP_PORT = 3000 +PROTOCOL = unix +ROOT_URL = https://git.miti.sh/ +HTTP_ADDR = /run/gitea/gitea.socket +LOCAL_ROOT_URL = APP_DATA_PATH = /var/lib/gitea/data DISABLE_SSH = false SSH_PORT = 22 diff --git a/conf/nginx.conf b/conf/nginx.conf index 68e7585..e74cc14 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -8,6 +8,10 @@ events { http { server { listen 80; + return 301 https://$host$request_uri; + } + + server { listen 443 ssl; include mime.types; @@ -30,7 +34,7 @@ http { # redirect requests ending in a forward slash location ~ ^/(.+)/$ { - return 302 /$1; + return 301 /$1; } location /css { @@ -49,7 +53,7 @@ http { location / { client_max_body_size 1024M; - proxy_pass http://localhost:3000; + 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; @@ -93,7 +97,7 @@ http { return 301 https://miti.sh$request_uri; } - location ~ ^/git/(.*)$ { + location ~ ^/git/?(.*)$ { return 301 https://git.miti.sh/ccm/$1; } @@ -101,20 +105,32 @@ http { return 301 https://apps.miti.sh/$1; } } + server { listen 443 ssl; server_name git.webdevcat.me; - location ^~ /.well-known/acme-challenge { - alias /var/www/dehydrated; - } - } - server { - listen 443 ssl; - server_name apps.webdevcat.me; + ssl_certificate /var/www/certs/webdevcat.me/fullchain.pem; + ssl_certificate_key /var/www/certs/webdevcat.me/privkey.pem; location ^~ /.well-known/acme-challenge { alias /var/www/dehydrated; } + + return 301 https://git.miti.sh$request_uri; + } + + server { + listen 443 ssl; + server_name apps.webdevcat.me; + + ssl_certificate /var/www/certs/webdevcat.me/fullchain.pem; + ssl_certificate_key /var/www/certs/webdevcat.me/privkey.pem; + + location ^~ /.well-known/acme-challenge { + alias /var/www/dehydrated; + } + + return 301 https://apps.miti.sh$request_uri; } } diff --git a/spec/nginx_spec.moon b/spec/nginx_spec.moon new file mode 100644 index 0000000..dfd8403 --- /dev/null +++ b/spec/nginx_spec.moon @@ -0,0 +1,138 @@ +http = require "luajit-curl-helper.http" +index_title = "miti.sh · Catalin Constantin Mititiuc" + +req = (url) -> + request = http.init url + st = request\perform! + error request\lastError! if not st + request + +describe "test environment", -> + it "can't connect to the internet", -> + assert.has_error (-> req "http://example.org"), "Couldn't resolve host name" + +describe "http://miti.sh", -> + it "redirects to https", -> + request = req "http://miti.sh" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://miti.sh/" + +describe "https://webdevcat.me", -> + it "permanently redirects to https://miti.sh", -> + request = req "https://webdevcat.me" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://miti.sh/" + +describe "https://webdevcat.me/git", -> + it "permanently redirects to https://git.miti.sh/ccm/", -> + request = req "https://webdevcat.me/git" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://git.miti.sh/ccm/" + +describe "https://webdevcat.me/git/", -> + it "permanently redirects to https://git.miti.sh", -> + request = req "https://webdevcat.me/git" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://git.miti.sh/ccm/" + +describe "https://webdevcat.me/git/pandoc", -> + it "permanently redirects to https://git.miti.sh/ccm/pandoc", -> + request = req "https://webdevcat.me/git/pandoc" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://git.miti.sh/ccm/pandoc" + +describe "https://git.webdevcat.me", -> + it "permanently redirects to https://git.miti.sh/", -> + request = req "https://git.webdevcat.me" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://git.miti.sh/" + +describe "https://webdevcat.me/apps/btroops", -> + it "permanently redirects to https://apps.miti.sh/btroops", -> + request = req "https://webdevcat.me/apps/btroops" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://apps.miti.sh/btroops" + +describe "https://apps.webdevcat.me", -> + it "permanently redirects to https://apps.miti.sh/", -> + request = req "https://apps.webdevcat.me" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://apps.miti.sh/" + +describe "https://apps.webdevcat.me/btroops", -> + it "permanently redirects to https://apps.miti.sh/btroops", -> + request = req "https://apps.webdevcat.me/btroops" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://apps.miti.sh/btroops" + +describe "https://miti.sh", -> + it "sends /index.html", -> + request = req "https://miti.sh" + assert.same request\statusCode!, 200 + assert.same request\statusMessage!, "OK" + assert.same request\body!\match("(.*)"), index_title + +describe "https://miti.sh/index", -> + it "sends /index.html", -> + request = req "https://miti.sh/index" + assert.same request\statusCode!, 200 + assert.same request\statusMessage!, "OK" + assert.same request\body!\match("(.*)"), index_title + +describe "https://miti.sh/index.html", -> + it "sends /index.html", -> + request = req "https://miti.sh/index.html" + assert.same request\statusCode!, 200 + assert.same request\statusMessage!, "OK" + assert.same request\body!\match("(.*)"), index_title + +describe "https://miti.sh/posts/", -> + it "permanently redirects to http://miti.sh/posts", -> + request = req "https://miti.sh/posts/" + assert.same request\statusCode!, 301 + assert.same request\statusMessage!, "Moved Permanently" + assert.same request\header!.Location, "https://miti.sh/posts" + +describe "https://miti.sh/posts", -> + it "sends /posts/index.html", -> + request = req "https://miti.sh/posts" + assert.same request\statusCode!, 200 + assert.same request\statusMessage!, "OK" + assert.same request\body!\match("(.*)"), "miti.sh · Posts" + +describe "https://git.miti.sh", -> + it "reverse-proxies request to a gitea unix socket", -> + Path = require "sitegen.path" + socket_fname = "unixstreamsrvr.moon" + socket_dir = "/run/gitea" + socket_owner = "nobody" + basepath = Path.basepath debug.getinfo(1).short_src + + Path.exec "install", "-o", socket_owner, "-d", socket_dir + cmd = "su -s /bin/bash -c 'moon %s' %s" + server = io.popen cmd\format Path.join(basepath, socket_fname), socket_owner + Path.exec "sleep", "0.1" + result = Path.read_exec "find", socket_dir, "-type", "s", "-ls" + assert.truthy result\match "nobody%s+nogroup.+" .. Path.join(socket_dir, "gitea.socket") + + req "https://git.miti.sh" + + reqheader = with server\read "*a" + server\close! + + assert.truthy reqheader\match "Host: git.miti.sh" + +describe "https://apps.miti.sh", -> + it "doesn't find it", -> + request = req "https://apps.miti.sh" + assert.same request\statusCode!, 404 + assert.same request\statusMessage!, "Not Found" diff --git a/spec/unixstreamsrvr.moon b/spec/unixstreamsrvr.moon new file mode 100644 index 0000000..b0ffd8a --- /dev/null +++ b/spec/unixstreamsrvr.moon @@ -0,0 +1,14 @@ +-- 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 diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..8904929 --- /dev/null +++ b/test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +image=miti.sh +loopback=127.0.0.1 + +# Make sure to create 'no-internet' network, if it doesn't already exist: +# $ docker network create --internal no-internet +container_id=$(docker run --rm -d -v $(pwd):/opt/app --network no-internet \ + --add-host=miti.sh=$loopback \ + --add-host=git.miti.sh=$loopback \ + --add-host=apps.miti.sh=$loopback \ + --add-host=webdevcat.me=$loopback \ + --add-host=git.webdevcat.me=$loopback \ + --add-host=apps.webdevcat.me=$loopback \ + $image) + +docker exec -t $container_id busted + +docker exec $container_id openresty -p /opt/app -s stop + +is_running=$(docker inspect -f '{{.State.Running}}' $container_id) + +if [[ $is_running == "true" ]]; then + echo "Warning: Docker reports test container is still running" +fi