nginx powershell

From time to time there is a need to create some small service which is not required to be super fast or fancy

In my case it will be a webhook for external system that will be called few times per day

I wish not to have some buildable language, docker images, etc

What if all this will be configured ad-hoc?

Here is how we can have such service powered by powershell

We are going to use nginx:alpine docker image, install powershell and fastcgi inside and serve our endpoints with powershell scripts

Here are starting point examples (make sure to make all scripts executable by running chmod +x script.file)

entrypoint.sh

#!/bin/sh

apk add -q fcgiwrap spawn-fcgi powershell

/usr/bin/spawn-fcgi -s /var/run/fcgiwrap.socket -M 766 /usr/bin/fcgiwrap

Nothing fancy here, just installing required software and instantiating fastcgi

default.conf

server {
  listen 80;
  root   /usr/share/nginx/html;

  location /post {
    fastcgi_pass unix:/var/run/fcgiwrap.socket;
    fastcgi_param REQUEST_BODY $request_body;
    fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/post.ps1;
  }

  location /query {
    fastcgi_pass unix:/var/run/fcgiwrap.socket;
    fastcgi_param NAME $arg_name;
    fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/query.ps1;
  }
}

Here you can see how we are mapping certain urls to our scripts, as well as how to pass request body and query string parameters

And here are our oversimplified scripts

post.ps1

#!/usr/bin/pwsh


Write-Host 'content-type: application/json'
Write-Host 'cache-control: no-store'
Write-Host ''
$body = $env:REQUEST_BODY | ConvertFrom-Json
$body | ConvertTo-Json | Out-Host

query.ps1

#!/usr/bin/pwsh


Write-Host 'content-type: text/html'
Write-Host 'cache-control: no-store'
Write-Host ''
if ($env:NAME) {
    Write-Host "<h1>Hell $($env:NAME)</h1>"
} else {
    Write-Host "<h1>Hell World</h1>"
}

Now we can run container like this:

docker run -it --rm -p 8080:80 -v $PWD/entrypoint.sh:/docker-entrypoint.d/00-init.sh -v $PWD/default.conf:/etc/nginx/conf.d/default.conf -v $PWD/post.ps1:/usr/share/nginx/html/post.ps1 -v $PWD/query.ps1:/usr/share/nginx/html/query.ps1 nginx:alpine

Usage examples

curl localhost:8080
# will respond with default nginx page

curl localhost:8080/query
# <h1>Hello World</h1>

curl localhost:8080/query?name=Alex
# <h1>Hello Alex</h1>

curl localhost:8080/post -d '{"foo":"bar"}'
# {
#   "foo": "bar"
# }

Notes:

  • because of how locations work, even if you will call /query.ps1 results will be the same
  • make sure to not mess with headers and content
  • more complex bash example can be found here