├── .gitignore ├── LICENSE ├── README.md ├── index.sh └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mathias Buus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # taco-nginx 2 | 3 | Bash script that runs a service and forwards a subdomain to it using nginx when it listens to `$PORT` 4 | 5 | ``` 6 | npm install -g taco-nginx 7 | ``` 8 | 9 | We recommend using latest stable nginx (>1.8.0). If you are on Ubuntu LTS for example you may need to do this: 10 | 11 | ``` 12 | add-apt-repository ppa:nginx/stable 13 | apt-get update 14 | apt-get install nginx 15 | ``` 16 | 17 | ## Usage 18 | 19 | First write a service (in any language) similar to this 20 | 21 | ``` js 22 | var http = require('http') 23 | var server = http.createServer(function (req, res) { 24 | console.log('Got request!', req.url) 25 | res.end('hello world\n') 26 | }) 27 | 28 | server.listen(process.env.PORT, function () { 29 | console.log('Server is listening...') 30 | }) 31 | ``` 32 | 33 | Assuming the above file is called `server.js` and you have `nginx` running you can now do 34 | 35 | ``` sh 36 | taco-nginx --name my-service node server.js 37 | ``` 38 | 39 | taco-nginx will now spawn `node server.js`, wait for it to listen to the port specified in 40 | `$PORT` and then have nginx route requests to `my-service.*` to it. 41 | 42 | If you don't specify `--name` it will see if you have a `package.json` and use the name field 43 | 44 | ``` sh 45 | taco-nginx node server.js # uses name from package.json 46 | ``` 47 | 48 | For a full list of options run 49 | 50 | ``` 51 | taco-nginx --help 52 | ``` 53 | 54 | ## License 55 | 56 | MIT 57 | -------------------------------------------------------------------------------- /index.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SOFT_EXIT=false 4 | ENABLE_WEBSOCKETS=false 5 | HELP=false 6 | VERSION=false 7 | HTTP_PORT=80 8 | HTTPS_PORT=443 9 | HTTP_ONLY=false 10 | HTTPS_ONLY=false 11 | 12 | while true; do 13 | case "$1" in 14 | --soft-exit) SOFT_EXIT=true; shift ;; 15 | -s) SOFT_EXIT=true; shift ;; 16 | --name) SERVICE_NAME="$2"; shift; shift ;; 17 | -n) SERVICE_NAME="$2"; shift; shift ;; 18 | --help) HELP=true; shift ;; 19 | -h) HELP=true; shift ;; 20 | --port) PORT="$2"; shift; shift ;; 21 | -p) PORT="$2"; shift; shift ;; 22 | --version) VERSION=true; shift ;; 23 | -v) VERSION=true; shift ;; 24 | --domain) DOMAIN="$2"; shift; shift ;; 25 | --server-name) DOMAIN="$2"; shift; shift ;; 26 | -d) DOMAIN="$2"; shift; shift ;; 27 | --server-config) SERVER_CONFIG="$2"; shift; shift ;; 28 | -c) SERVER_CONFIG="$2"; shift; shift ;; 29 | --location-config) LOCATION_CONFIG="$2"; shift; shift ;; 30 | -l) LOCATION_CONFIG="$2"; shift; shift ;; 31 | --http-port) HTTP_PORT=$2; shift; shift ;; 32 | --https-port) HTTPS_PORT=$2; shift; shift ;; 33 | --http-only) HTTP_ONLY=true; shift ;; 34 | --https-only) HTTPS_ONLY=true; shift ;; 35 | --static) SERVE_STATIC="$2"; shift; shift ;; 36 | --autoindex) AUTO_INDEX="autoindex on;"; shift ;; 37 | --websockets) ENABLE_WEBSOCKETS=true; shift ;; 38 | -w) ENABLE_WEBSOCKETS=true; shift ;; 39 | *) break ;; 40 | esac 41 | done 42 | 43 | 44 | if $VERSION; then 45 | printf "1.12.1\n" 46 | exit 47 | fi 48 | 49 | if $ENABLE_WEBSOCKETS; then 50 | WEBSOCKETS_LINE_1="proxy_set_header Upgrade \$http_upgrade;" 51 | WEBSOCKETS_LINE_2="proxy_set_header Connection \"upgrade\";" 52 | fi 53 | 54 | if $HELP || [ "$1$SERVE_STATIC" == "" ]; then 55 | cat << EOF 56 | Usage: taco-nginx [run-opts] command arg1 ... 57 | --name, -n [service-name] 58 | --port, -p [port] 59 | --server-name,-d [nginx server name pattern] 60 | --server-config,-c [add this file to the server config] 61 | --location-config,-l [add this file to the location config] 62 | --soft-exit, -s [wait 5s when shutting down] 63 | --http-only [only listen on http port] 64 | --https-only [only listen on https port] 65 | --http-port [default: 80] 66 | --https-port [default: 443] 67 | --static [path/to/folder to serve statically] 68 | --autoindex [serve file listing when using --static] 69 | --websockets,w [enable websocket support] 70 | --version, -v [prints installed version] 71 | 72 | EOF 73 | exit 74 | fi 75 | 76 | [ "$PORT" = "" ] && export PORT=$(echo "require('net').createServer().listen(0, function() { process.stdout.write(''+this.address().port); this.close() })" | node) 77 | [ "$SERVICE_NAME" == "" ] && SERVICE_NAME=$(node -e "process.stdout.write(require('./package.json').name)" 2>/dev/null) 78 | 79 | if [ "$SERVICE_NAME" == "" ]; then 80 | printf "You need to specify a name using --name [name] or adding a package.json\n" 81 | exit 1 82 | fi 83 | 84 | [ "$DOMAIN" == "" ] && DOMAIN=$SERVICE_NAME.* 85 | [ -f "$SERVER_CONFIG" ] && SERVER_CONFIG_CONTENTS="$(cat $SERVER_CONFIG)" 86 | [ -f "$LOCATION_CONFIG" ] && LOCATION_CONFIG_CONTENTS="$(cat $LOCATION_CONFIG)" 87 | [ ""] 88 | 89 | if [ ! -d /etc/nginx/conf.d ]; then 90 | printf "/etc/nginx/conf.d does not exist. Is nginx installed?\n" 91 | exit 2 92 | fi 93 | 94 | LISTEN_HTTPS="listen $HTTPS_PORT;" 95 | LISTEN_HTTP="listen $HTTP_PORT;" 96 | $HTTPS_ONLY && LISTEN_HTTP="" 97 | $HTTP_ONLY && LISTEN_HTTPS="" 98 | 99 | reload_nginx () { 100 | [ ! -O /etc/nginx/conf.d ] && SUDO_MAYBE=sudo 101 | $SUDO_MAYBE mv /tmp/nginx.$SERVICE_NAME.$PORT.conf /etc/nginx/conf.d/$SERVICE_NAME.conf 102 | $SUDO_MAYBE nginx -s reload 103 | trap on_exit EXIT 104 | } 105 | 106 | on_sigterm () { 107 | $SOFT_EXIT && sleep 5 108 | kill $PID 109 | wait $PID 110 | } 111 | 112 | on_exit () { 113 | $SUDO_MAYBE rm -f /etc/nginx/conf.d/$SERVICE_NAME.conf 114 | $SUDO_MAYBE nginx -s reload 115 | } 116 | 117 | on_static () { 118 | cat << EOF > /tmp/nginx.$SERVICE_NAME.$PORT.conf 119 | server { 120 | $LISTEN_HTTPS 121 | $LISTEN_HTTP 122 | server_name $DOMAIN; 123 | $SERVER_CONFIG_CONTENTS 124 | location / { 125 | $AUTO_INDEX 126 | root $(realpath "$SERVE_STATIC"); 127 | } 128 | } 129 | EOF 130 | 131 | reload_nginx 132 | tail -f /dev/null 133 | exit $? 134 | } 135 | 136 | on_ready () { 137 | cat << EOF > /tmp/nginx.$SERVICE_NAME.$PORT.conf 138 | upstream $SERVICE_NAME { 139 | server 127.0.0.1:$PORT; 140 | } 141 | server { 142 | $LISTEN_HTTPS 143 | $LISTEN_HTTP 144 | server_name $DOMAIN; 145 | location / { 146 | proxy_pass http://$SERVICE_NAME; 147 | proxy_set_header X-Forwarded-For \$remote_addr; 148 | proxy_set_header Host \$host; 149 | proxy_buffering off; 150 | proxy_request_buffering off; 151 | proxy_http_version 1.1; 152 | client_max_body_size 0; 153 | $LOCATION_CONFIG_CONTENTS 154 | $WEBSOCKETS_LINE_1 155 | $WEBSOCKETS_LINE_2 156 | } 157 | $SERVER_CONFIG_CONTENTS 158 | } 159 | EOF 160 | 161 | reload_nginx 162 | wait $PID 163 | exit $? 164 | } 165 | 166 | if [ "$SERVE_STATIC" != "" ]; then 167 | on_static 168 | else 169 | trap on_sigterm SIGTERM 170 | PATH="node_modules/.bin:$PATH" 171 | 172 | "$@" & 173 | PID=$! 174 | 175 | for i in {1..20}; do 176 | lsof -p $PID 2>/dev/null | grep "TCP \*:$PORT" 2>/dev/null >/dev/null && on_ready 177 | sleep 0.2 178 | done; 179 | 180 | on_ready 181 | fi 182 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taco-nginx", 3 | "version": "1.12.1", 4 | "description": "Bash script that runs a service and forwards a subdomain to it using nginx when it listens to $PORT", 5 | "main": "index.js", 6 | "dependencies": {}, 7 | "devDependencies": {}, 8 | "bin": { 9 | "taco-nginx": "./index.sh" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/mafintosh/taco-nginx.git" 14 | }, 15 | "author": "Mathias Buus (@mafintosh)", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/mafintosh/taco-nginx/issues" 19 | }, 20 | "homepage": "https://github.com/mafintosh/taco-nginx" 21 | } 22 | --------------------------------------------------------------------------------