Compare commits
10 Commits
ee38b2468e
...
1e7531e632
Author | SHA1 | Date | |
---|---|---|---|
1e7531e632 | |||
b2a02407b9 | |||
f196697569 | |||
f77961145e | |||
3001dbca73 | |||
5ded2bc320 | |||
a184866de3 | |||
c48e985d23 | |||
e8d238f3c3 | |||
8f35aaef11 |
@ -1,15 +1,18 @@
|
||||
# LiveReload-npm server supporting SSL/TLS
|
||||
# node-livereload server supporting SSL/TLS
|
||||
|
||||
# allow dynamic building by specifying base image elements as build-args
|
||||
ARG NODE_VERSION=16
|
||||
ARG ALPINE_VERSION=3.14
|
||||
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}
|
||||
|
||||
# create new node user with set id from build-arg
|
||||
# create new node user with set id from build-arg and create volume directories
|
||||
ARG NODE_UID=9999
|
||||
RUN deluser --remove-home node \
|
||||
&& addgroup -g ${NODE_UID} -S node \
|
||||
&& adduser -G node -S -u ${NODE_UID} node
|
||||
&& adduser -G node -S -u ${NODE_UID} node \
|
||||
&& mkdir /watch /certs \
|
||||
&& chown root:node /certs \
|
||||
&& chmod 770 /certs
|
||||
|
||||
# create default volumes in-case user forgets, expose default port
|
||||
VOLUME [ "/watch", "/certs" ]
|
||||
@ -23,8 +26,8 @@ RUN apk --update --no-cache add \
|
||||
|
||||
# labels
|
||||
LABEL org.opencontainers.image.authors="Asif Bacchus <asif@asifbacchus.dev>"
|
||||
LABEL org.opencontainers.image.title="livereload npm"
|
||||
LABEL org.opencontainers.image.description="Dockerized npm livereload supporting TLS and running under limited user account. Environment variables allow specifying files to watch/exclude and notification delay."
|
||||
LABEL org.opencontainers.image.title="node-livereload-tls"
|
||||
LABEL org.opencontainers.image.description="Dockerized node-livereload supporting TLS and running under limited user account. Environment variables allow specifying files to watch/exclude and notification delay."
|
||||
LABEL org.opencontainers.image.url="https://git.asifbacchus.dev/ab-docker/livereload"
|
||||
LABEL org.opencontainers.image.documentation="https://git.asifbacchus.dev/ab-docker/livereload/raw/branch/master/README.md"
|
||||
LABEL org.opencontainers.image.source="https://git.asifbacchus.dev/ab-docker/livereload.git"
|
||||
@ -39,8 +42,10 @@ ENV LR_EXTS="html,xml,css,js,jsx,ts,tsx,php,py"
|
||||
ENV LR_EXCLUDE=".git/,.svn/,.vscode/,.idea/"
|
||||
ENV LR_DELAY=500
|
||||
ENV LR_DEBUG=true
|
||||
ENV LR_HTTPS=true
|
||||
ENV CERT_HOSTNAME=""
|
||||
|
||||
# install livereload npm as node user then switch back to root user
|
||||
# install node-livereload as node user then switch back to root user
|
||||
USER node
|
||||
WORKDIR /home/node
|
||||
RUN mkdir -p .npm-global/bin .npm-global/lib \
|
||||
@ -50,11 +55,13 @@ RUN mkdir -p .npm-global/bin .npm-global/lib \
|
||||
|
||||
# copy scripts and fix-up all permissions
|
||||
USER root
|
||||
COPY [ "selfsigned.cnf", "/etc/selfsigned.cnf" ]
|
||||
COPY [ "livereload.js", "/home/node/livereload.js" ]
|
||||
COPY [ "entrypoint.sh", "/usr/local/bin/entrypoint.sh" ]
|
||||
RUN chown node:node /home/node/livereload.js \
|
||||
&& chmod 644 /home/node/livereload.js \
|
||||
&& chmod 755 /usr/local/bin/entrypoint.sh
|
||||
&& chmod 755 /usr/local/bin/entrypoint.sh \
|
||||
&& chmod 644 /etc/selfsigned.cnf
|
||||
|
||||
# switch to node user, run entrypoint script by default
|
||||
USER node
|
||||
@ -62,13 +69,12 @@ WORKDIR /home/node
|
||||
ENTRYPOINT [ "/sbin/tini", "--", "/usr/local/bin/entrypoint.sh" ]
|
||||
|
||||
# set build timestamp and version labels
|
||||
# TODO: uncomment when done testing
|
||||
#ARG INTERNAL_VERSION
|
||||
#ARG BUILD_DATE
|
||||
#LABEL org.opencontainers.image.version="16.5.0, 0.9.3"
|
||||
#LABEL org.opencontainers.image.vendor="NODE.js, node-livereload"
|
||||
#LABEL dev.asifbacchus.image.name="livereload-tls-npm"
|
||||
#LABEL dev.asifbacchus.image.version=${INTERNAL_VERSION}
|
||||
#LABEL org.opencontainers.image.created=${BUILD_DATE}
|
||||
ARG INTERNAL_VERSION
|
||||
ARG BUILD_DATE
|
||||
LABEL org.opencontainers.image.version="16.5.0, 0.9.3"
|
||||
LABEL org.opencontainers.image.vendor="NODE.js, node-livereload"
|
||||
LABEL dev.asifbacchus.image.name="node-livereload-tls"
|
||||
LABEL dev.asifbacchus.image.version=${INTERNAL_VERSION}
|
||||
LABEL org.opencontainers.image.created=${BUILD_DATE}
|
||||
|
||||
#EOF
|
||||
|
@ -1,33 +1,76 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# entrypoint script for livereload-tls-npm container
|
||||
# entrypoint script for node-livereload-tls container
|
||||
#
|
||||
|
||||
# functions
|
||||
certificateCheckExist() {
|
||||
if [ -n "$(find /certs/ -type d -empty -print)" ]; then
|
||||
printf "noexist"
|
||||
elif ! [ -r "/certs/fullchain.pem" ]; then
|
||||
printf "noread_certificate"
|
||||
elif ! [ -r "/certs/privkey.pem" ]; then
|
||||
printf "noread_key"
|
||||
else
|
||||
printf "ok"
|
||||
fi
|
||||
}
|
||||
|
||||
certificateGenerateNew() {
|
||||
# generate self-signed certificate and export as PFX
|
||||
printf "\nGenerating new self-signed certificate:\n"
|
||||
printf "Exporting new certificate:\n"
|
||||
exit 0
|
||||
# shellcheck disable=SC3028
|
||||
if [ -z "$CERT_HOSTNAME" ]; then export CERT_HOSTNAME="$HOSTNAME"; fi
|
||||
if ! openssl req -new -x509 -days 365 -nodes -out /certs/fullchain.pem -keyout /certs/privkey.pem -config /etc/selfsigned.cnf; then
|
||||
printf "\nUnable to generate certificate. Is your 'certs' directory writable by this container?\n\n"
|
||||
exit 55
|
||||
fi
|
||||
|
||||
# print message to user
|
||||
printf "\n\nA self-signed certificate has been generated and saved in the location mounted to '/certs' in this container.\n"
|
||||
printf "The certificate and private key are PEM formatted with names 'fullchain.pem' and 'privkey.pem', respectively.\n"
|
||||
printf "Remember to import 'fullchain.pem' to the trusted store on any client machines or you will get warnings.\n\n"
|
||||
}
|
||||
|
||||
certificateShow() {
|
||||
printf "\nCurrently loaded certificate:\n"
|
||||
exit 0
|
||||
certStatus="$(certificateCheckExist)"
|
||||
case "$certStatus" in
|
||||
noexist)
|
||||
printf "[ERROR]: No certificate is loaded (certificate directory empty).\n\n"
|
||||
exit 51
|
||||
;;
|
||||
noread_certificate)
|
||||
printf "[ERROR]: Cannot read loaded certificate.\n\n"
|
||||
exit 52
|
||||
;;
|
||||
noread_key)
|
||||
printf "\n[WARNING]: Cannot find private key associated with certificate!\n\n"
|
||||
;;
|
||||
esac
|
||||
if ! openssl x509 -noout -text -nameopt align,multiline -certopt no_pubkey,no_sigdump -in /certs/fullchain.pem; then
|
||||
printf "\n[ERROR]: Unable to display loaded certificate.\n\n"
|
||||
exit 52
|
||||
fi
|
||||
}
|
||||
|
||||
certificateExport() {
|
||||
printf "\nExporting currently loaded certificate:\n"
|
||||
exit 0
|
||||
convertCaseLower() {
|
||||
printf "%s" "$1" | tr "[:upper:]" "[:lower:]"
|
||||
}
|
||||
|
||||
# default variable values
|
||||
doCertExport=0
|
||||
doCertNew=0
|
||||
doCertShow=0
|
||||
doServer=0
|
||||
doShell=0
|
||||
|
||||
# clean-up boolean environment variables for this script and JavaScript
|
||||
enableHTTPS="$(convertCaseLower "$LR_HTTPS")"
|
||||
enableDebug="$(convertCaseLower "$LR_DEBUG")"
|
||||
export LR_HTTPS="$enableHTTPS"
|
||||
export LR_DEBUG="$enableDebug"
|
||||
|
||||
# process action parameter
|
||||
case "$1" in
|
||||
listen | server | run | start)
|
||||
@ -42,19 +85,44 @@ new-cert)
|
||||
show-cert)
|
||||
doCertShow=1
|
||||
;;
|
||||
export-cert)
|
||||
doCertExport=1
|
||||
;;
|
||||
*)
|
||||
# invalid or unknown option
|
||||
printf "\nUnknown action requested: %s\n" "$1"
|
||||
printf "Valid actions: [listen | server | run | start] | shell | new-cert | show-cert | export-cert\n\n"
|
||||
printf "Valid actions: [listen | server | run | start] | shell | new-cert | show-cert\n\n"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# action: run server
|
||||
if [ "$doServer" -eq 1 ]; then
|
||||
printf "Starting node-livereload-tls server:\n"
|
||||
|
||||
# https pre-flight check
|
||||
if [ "$enableHTTPS" = "true" ]; then
|
||||
printf "[SSL/TLS mode enabled]\n"
|
||||
certStatus="$(certificateCheckExist)"
|
||||
case "$certStatus" in
|
||||
noexist)
|
||||
printf "[Generating certificate]\n"
|
||||
certificateGenerateNew
|
||||
;;
|
||||
noread_certificate)
|
||||
printf "[Checking mounted certificate]"
|
||||
printf "\nERROR: SSL/TLS mode selected but unable to read certificate!\n\n"
|
||||
exit 52
|
||||
;;
|
||||
noread_key)
|
||||
printf "[Checking mounted certificate]"
|
||||
printf "\nERROR: SSL/TLS mode selected but unable to read private key!\n\n"
|
||||
exit 53
|
||||
;;
|
||||
ok)
|
||||
printf "[Certificate OK]\n"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "[HTTP mode enabled]\n"
|
||||
fi
|
||||
exec node livereload.js
|
||||
exit "$?"
|
||||
fi
|
||||
@ -73,13 +141,16 @@ if [ "$doShell" -eq 1 ]; then
|
||||
fi
|
||||
|
||||
# action: generate new self-signed certificate
|
||||
if [ "$doCertNew" -eq 1 ]; then certificateGenerateNew; fi
|
||||
if [ "$doCertNew" -eq 1 ]; then
|
||||
certificateGenerateNew
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# action: show loaded certificate
|
||||
if [ "$doCertShow" -eq 1 ]; then certificateShow; fi
|
||||
|
||||
# action: export loaded certificate
|
||||
if [ "$doCertExport" -eq 1 ]; then certificateExport; fi
|
||||
if [ "$doCertShow" -eq 1 ]; then
|
||||
certificateShow
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# failsafe exit - terminate with code 99: this code should never be executed!
|
||||
exit 99
|
||||
@ -87,11 +158,12 @@ exit 99
|
||||
# exit codes:
|
||||
# 0: normal exit, no errors
|
||||
# 1: invalid or invalid parameter passed to script
|
||||
# 2: interactive shell required
|
||||
# 50: certificate errors
|
||||
# 51: unable to read certificate/chain
|
||||
# 52: unable to read private key
|
||||
# 51: certificate directory empty
|
||||
# 52: unable to read certificate/chain
|
||||
# 53: unable to read private key
|
||||
# 55: unable to generate new certificate
|
||||
# 56: unable to export certificate, likely write error
|
||||
# 99: code error
|
||||
|
||||
#EOF
|
||||
|
@ -4,13 +4,8 @@
|
||||
let livereload = require('livereload');
|
||||
|
||||
// set createServer options
|
||||
const https = require('https');
|
||||
const fs = require('fs');
|
||||
const options = {
|
||||
https: {
|
||||
cert: fs.readFileSync('/certs/fullchain.pem'),
|
||||
key: fs.readFileSync('/certs/privkey.pem')
|
||||
},
|
||||
port: process.env.LR_PORT,
|
||||
exts: process.env.LR_EXTS,
|
||||
exclusions: process.env.LR_EXCLUDE,
|
||||
@ -19,6 +14,14 @@ const options = {
|
||||
debug: process.env.LR_DEBUG
|
||||
};
|
||||
|
||||
if (process.env.LR_HTTPS) {
|
||||
options.https = {
|
||||
cert: fs.readFileSync('/certs/fullchain.pem'),
|
||||
key: fs.readFileSync('/certs/privkey.pem')
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// start server
|
||||
let server = livereload.createServer(options);
|
||||
server.watch('/watch')
|
||||
|
16
build/selfsigned.cnf
Normal file
16
build/selfsigned.cnf
Normal file
@ -0,0 +1,16 @@
|
||||
default_bits = 4096
|
||||
default_md = sha256
|
||||
distinguished_name = dn
|
||||
req_extensions = san
|
||||
x509_extensions = san
|
||||
prompt = no
|
||||
|
||||
[dn]
|
||||
organizationName = LiveReload WebServer
|
||||
CN = ${ENV::CERT_HOSTNAME}
|
||||
|
||||
[san]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = ${ENV::CERT_HOSTNAME}
|
32
docker-compose.yml
Normal file
32
docker-compose.yml
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# node-livereload-tls stack
|
||||
#
|
||||
|
||||
version: '2.4'
|
||||
|
||||
services:
|
||||
ab-nginx:
|
||||
image: docker.asifbacchus.dev/nginx/ab-nginx:latest
|
||||
container_name: ab-nginx
|
||||
volumes:
|
||||
- ./certs/certs:ro
|
||||
- ${WATCHDIR}:/usr/share/nginx/html:ro
|
||||
- ./nginx/config:/etc/nginx/config:ro
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "8443:443"
|
||||
env_file: livereload.params
|
||||
user: "8080:${GID:-8080}"
|
||||
livereload:
|
||||
image: docker.asifbacchus.dev/livereload/livereload:latest
|
||||
container_name: livereload
|
||||
volumes:
|
||||
- ./certs:certs:ro
|
||||
- ${WATCHDIR}:/watch:ro
|
||||
ports:
|
||||
- "35729:35729"
|
||||
env_file: livereload.params
|
||||
user: "9999:${GID:-9999}"
|
||||
command: listen
|
||||
|
||||
#EOF
|
104
livereload.params
Normal file
104
livereload.params
Normal file
@ -0,0 +1,104 @@
|
||||
#
|
||||
# Parameters for node-livereload-tls stack:
|
||||
# This file makes it easier to customize your node-livereload-tls stack deployment by providing centralized configuration options.
|
||||
# This file is *not required* since all values have (sane) default settings.
|
||||
# There is *no* sensitive information in this file.
|
||||
|
||||
|
||||
#
|
||||
# COMMON PARAMETERS
|
||||
|
||||
# TZ:
|
||||
# Timezone used in logs and console messages. No effect on operation, purely aesthetic.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: Etc/UTC
|
||||
# VALID OPTIONS: Any valid IANA TZ formatted timezone. Refer to https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.
|
||||
#TZ=Etc/UTC
|
||||
|
||||
# GID:
|
||||
# You may wish to change the GroupID of the container's user. This allows it access certain resources on the host like certificates or files.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT:
|
||||
# VALID OPTIONS: Any valid UID/GID
|
||||
#GID=
|
||||
|
||||
# WATCHDIR:
|
||||
# Directory containing files you want to monitor for changes and trigger a browser reload.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT:
|
||||
# VALID OPTIONS: Any valid directory on the host
|
||||
#WATCHDIR=
|
||||
|
||||
#
|
||||
# AB-NGINX parameters
|
||||
# refer to https://git.asifbacchus.dev/ab-docker/ab-nginx/wiki for more details
|
||||
|
||||
# SERVER_NAMES:
|
||||
# Space-delimited list of names to which the server should respond. This needs to match any certificates being used.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: _
|
||||
# VALID OPTIONS: Any valid hostnames for your environment
|
||||
#SERVER_NAMES=_
|
||||
|
||||
# TLS13_ONLY:
|
||||
# Use and accept only TLS version 1.3 connections. If false, both TLS versions 1.2 and 1.3 will be accepted.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: TRUE
|
||||
# VALID OPTIONS: TRUE, FALSE
|
||||
#TLS13_ONLY=TRUE
|
||||
|
||||
|
||||
#
|
||||
# node-livereload parameters
|
||||
|
||||
# LR_PORT:
|
||||
# Port on which the server should listen. Virtually all clients expect the default setting.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: 35729
|
||||
# VALID OPTIONS: Any valid TCP port number that does not conflict within your environment
|
||||
#LR_PORT=35729
|
||||
|
||||
# LR_EXTS:
|
||||
# Comma-delimited list of extensions to watch for changes and trigger a browser reload. This list *must* be quoted.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: "html,xml,css,js,jsx,ts,tsx,php,py"
|
||||
# VALID OPTIONS: Any valid file extension(s)
|
||||
#LR_EXTS="html,xml,css,js,jsx,ts,tsx,php,py"
|
||||
|
||||
# LR_EXCLUDE:
|
||||
# Comma-delimited list of files/directories to exclude from monitoring. This list *must* be quoted.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: ".git/,.svn/,.vscode/,.idea/"
|
||||
# VALID OPTIONS: Any valid files or directories/
|
||||
#LR_EXCLUDE=".git/,.svn/,.vscode/,.idea/"
|
||||
|
||||
# LR_DELAY:
|
||||
# Amount of time in milliseconds before detecting a change and sending a trigger for a browser reload. Useful if you need to allow time for background recompilation, etc.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: 500
|
||||
# VALID OPTIONS: Any integer representing a number of milliseconds (ms)
|
||||
#LR_DELAY=500
|
||||
|
||||
# LR_DEBUG:
|
||||
# Whether or not to print diagnostic debugging messages about the server's operation. Usually a good idea to leave this set to 'true'.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: true
|
||||
# VALID OPTIONS: true, false
|
||||
#LR_DEBUG=true
|
||||
|
||||
# LR_HTTPS:
|
||||
# Whether or not to enable SSL/TLS on the server's listening port. This may be required depending on your domain and environment configuration.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: true
|
||||
# VALID OPTIONS: true, false
|
||||
#LR_HTTPS=true
|
||||
|
||||
# CERT_HOSTNAME:
|
||||
# Hostname to use if container is auto-generating a self-signed certificate.
|
||||
# REQUIRED: NO
|
||||
# DEFAULT: $HOSTNAME
|
||||
# VALID OPTIONS: Any valid hostname
|
||||
#CERT_HOSTNAME=$HOSTNAME
|
||||
|
||||
|
||||
#EOF
|
Loading…
Reference in New Issue
Block a user