Obtain privileges for Node.js to bind to ports < 1024 on Linux

parent dc9a8448
......@@ -8,6 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
Nothing yet.
## [1.0.3] - 2019-02-26
## Added
- Node.js is automatically privileged to bind to ports < 1024 (including the default TLS port of 443).
## [1.0.2] - 2019-02-25
## Changed
......
......@@ -14,28 +14,6 @@ An HTTPS server that uses [nodecert](https://source.ind.ie/hypha/tools/nodecert)
npm i -g @ind.ie/https-server
```
## Note regarding port 443
The server is started on port 443 by default. This is on purpose as an overarching goal of https-server is to make your development environment mirror your production environment as closely possible to remove that complexity from the code you have to write.
However, you must have your system setup to allow Node (Linux) or your account (macOS) to bind to so-called “privileged” ports so that this works. I will automate this as part of the process in the future but, for the time being:
### Linux
```sh
sudo setcap 'cap_net_bind_service=+ep' $(which node)
```
### macOS
```sh
sudo touch /etc/authbind/byport/443
sudo chown $(whoami) /etc/authbind/byport/443
sudo chmod 755 /etc/authbind/byport/443
```
macOS instructions courtesy of [Setup authbind on Mac OS](https://medium.com/@steve.mu.dev/setup-authbind-on-mac-os-6aee72cb828) by Steve Mu.
## Usage
### Commandline
......@@ -47,11 +25,11 @@ https-server [folder-to-serve] [port]
Both arguments are optional. Currently, if you want to specify the port manually, you must also specify the folder-to-serve.
* `[folder-to-serve]` defaults to `.` (the current directory)
* `[port]` defaults to 443. (See [note regarding port 443](#note-regarding-port-443), above.)
* `[port]` defaults to 443 (automatically privileges Node.js to bind to it on Linux. This is not an issue on macOS & Windows.)
If you do not already have TLS certificates, they will be created for you automatically using [nodecert](https://source.ind.ie/hypha/tools/nodecert).
All dependencies will be installed automatically for you if they do not exist if you have apt, yum (untested), or pacman (untested) on Linux or if you have [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/) (untested) on macOS.
All dependencies will be installed automatically for you if they do not exist if you have apt, yum (untested), or pacman (untested) on Linux or if you have [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/) (untested) on macOS.
## Help wanted
......
......@@ -4,6 +4,7 @@ const express = require('express')
const morgan = require('morgan')
const path = require('path')
const os = require('os')
const childProcess = require('child_process')
const arguments = process.argv
......@@ -12,7 +13,6 @@ if (arguments.length > 4) {
process.exit()
}
// If no path is passed, serve the current folder.
// If there is a path, serve that.
let pathToServe = '.'
......@@ -37,7 +37,7 @@ console.log('')
//
// If the requested port is < 1024 ensure that we can bind to it. Note: this is
// only a problem on Linux systems. As of macOS Mojave, privileged ports are
// only an issue on Linux systems. As of macOS Mojave, privileged ports are
// history on macOS (source regarding version:
// https://news.ycombinator.com/item?id=18302380 confirmed with first-party
// tests) and are not an issue on (at least client versions of) Windows.
......@@ -48,8 +48,22 @@ console.log('')
// https://www.staldal.nu/tech/2007/10/31/why-can-only-root-listen-to-ports-below-1024/
//
if (port < 1024 && os.platform() === 'linux') {
// sudo setcap 'cap_net_bind_service=+ep' $(which node)
console.log('TODO: Linux: ensure we can bind to ports < 1024.')
const options = {env: process.env}
try {
childProcess.execSync("setcap -v 'cap_net_bind_service=+ep' $(which node)", options)
} catch (error) {
try {
// Allow Node.js to bind to ports < 1024.
childProcess.execSync("sudo setcap 'cap_net_bind_service=+ep' $(which node)", options)
// Fork a new instance of the server so that it is launched with the privileged Node.js.
childProcess.fork(path.join(__dirname, 'index.js'), [pathToServe, port], {env: process.env, shell: true})
// We’re done here. Go into an endless loop. Exiting (Ctrl+C) this will also exit the child process.
while(1){}
} catch (error) {
console.log(`\n Error: could not get privileges for Node.js to bind to port ${port}.`, error)
process.exit(1)
}
}
}
// Requiring nodecert ensures that locally-trusted TLS certificates exist.
......
{
"name": "@ind.ie/https-server",
"version": "1.0.2",
"version": "1.0.3",
"description": "HTTPS server that uses nodecert",
"main": "index.js",
"bin": "bin/https-server.js",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment