justsml/ssl-proxy

By justsml

Updated about 5 years ago

Simple docker & nginx-based ssl-proxy

Image
5

10K+

justsml/ssl-proxy repository overview

Simple docker & nginx-based ssl-proxy

Protect any HTTP service with HTTPS!

An Nginx & Docker-based HTTPS/SSL reverse proxy.

Will upgrade to newest nginx

Table of Contents
  1. Features
  2. Example
  3. Getting Started
  4. Secure Docker Registry Example
  5. Secure Rancher Server Example
  6. Secure Rancher Server Example using Docker Compose
  7. Client Verification Example
  8. Arguments / Configuration

Features

  • Up-to-date Nginx & Alpine Linux.
  • Fast HTTP2 TLS-enabled reverse proxy
  • Advanced CORS Support (w/ credentials, auto hostname, smart headers)
  • Automatic WebSockets Support
  • NPN/ALPN Application-Layer Protocol Negotiation test here
  • TLS Forward Secrecy, PFS (aka Perfect Forward Secrecy).
  • Supports Optional Username & Password (stored using bcrypt at 14+ rounds)
    • Alternately an .htpasswd file can be volume mounted. (Multiple named users)
  • Great for securing a Docker Registry, Rancher server, Wordpress, etc

Example

Sample SSL Labs/Qualys SSL & TLS Report:

Here's a sample of what you can expect with default configuration.

image image

Getting Started

Requirements

To provide secure, proxied access to local HTTP service:

  1. Requires any working HTTP service (for UPSTREAM_TARGET.) (Supports local, in-docker, even remote).
  2. Start an instance of justsml/ssl-proxy:latest as shown below.
Secure Docker Registry Example
# Note: Small scale users can set certificates directly in the registry instance (v2+) 
docker run -d --restart=on-failure:5 \
  --name docker-registry \
  -v /data/registry/registry:/var/lib/registry \
  registry:2.5

# Create an ssl-proxy to point at the registry's port 5000 (via UPSTREAM_TARGET option - see below.)
docker run -d --restart=on-failure:5 \
  --name ssl-proxy \
  -p 5000:5000 \
  -e 'SERVER_NAME=hub.example.com' \
  -e 'UPSTREAM_TARGET=docker-registry:5000' \
  -e 'HTTPS_PORT=5000' \
  -e 'USERNAME=devops' \
  -e 'PASSWORD=secure' \
  -e 'CERT_PUBLIC_PATH=/certs/fullchain.pem' \
  -e 'CERT_PRIVATE_PATH=/certs/privkey.pem' \
  -e "ADD_HEADER='Docker-Distribution-Api-Version' 'registry/2.0' always" \
  -v '/certs:/certs:ro' \
  --link 'docker-registry:docker-registry' \
  justsml/ssl-proxy:latest

# ALT Options
# Create an ssl-proxy to point at the registry's port 5000 (via UPSTREAM_TARGET option - see below.)
docker run -d --restart=on-failure:5 \
  --name ssl-proxy \
  -p 5000:5000 \
  -e 'SERVER_NAME=hub.example.com' \
  -e 'UPSTREAM_TARGET=docker-registry:5000' \
  -e 'EXPIRES_DEFAULT=-1' \
  -e 'HTTPS_PORT=5000' \
  -e 'USERNAME=devops' \
  -e 'PASSWORD=secure' \
  -e 'CERT_PUBLIC_PATH=/certs/fullchain.pem' \
  -e 'CERT_PRIVATE_PATH=/certs/privkey.pem' \
  -e "ADD_HEADER='Docker-Distribution-Api-Version' 'registry/2.0' always" \
  -v '/certs:/certs:ro' \
  --link 'docker-registry:docker-registry' \
  justsml/ssl-proxy:latest
Secure Rancher Server Example
# Update Cached Docker Images
docker pull rancher/server:latest
docker pull justsml/ssl-proxy:latest

# Start Rancher w/ default local port 8080
docker run -d --restart=always \
  --name rancher-server \
  -v /data/rancher/mysql:/var/lib/mysql \
  rancher/server:latest

# Create an ssl-proxy with certs in /certs, (w/o user/pass auth) to point at the local rancher-server's port 8080
docker run -d --restart=always \
  --name rancher-proxy \
  -p 8080:8080 \
  -e 'HTTPS_PORT=8080' \
  -e 'SERVER_NAME=_' \
  -e 'UPSTREAM_TARGET=rancher-server:8080' \
  -e 'CERT_PUBLIC_PATH=/certs/fullchain.pem' \
  -e 'CERT_PRIVATE_PATH=/certs/privkey.pem' \
  -v '/certs:/certs:ro' \
  --link 'rancher-server:rancher-server' \
  justsml/ssl-proxy:latest

Secure Rancher Server Example using Docker Compose
version: '2'
services:
  ssl-proxy:
    image: justsml/ssl-proxy:latest
    environment:
    - HTTPS_PORT=8080
    - SERVER_NAME=rancher.example.com
    - UPSTREAM_TARGET=rancher-server:8080
    - CERT_PUBLIC_PATH=/certs/fullchain.pem
    - CERT_PRIVATE_PATH=/certs/privkey.pem
    volumes:
    - /certs:/certs:ro
    links:
    - 'rancher-server:rancher-server'
    ports: [ '8080:8080' ]
  rancher-server:
    image: rancher/server:latest
    expose: [ '8080' ]
    volumes:
    - /data/rancher/mysql:/var/lib/mysql
Client Verification Example
# Start an nginx server that responds with the incoming request's headers on port 8080
docker run -d --restart=always \
  --name http-server \
  brndnmtthws/nginx-echo-headers

# Create an ssl-proxy with certs in /certs, requiring a client certificate auth, to point at the local http-server's port 8080 and include the client certificate's subject as an http header
docker run -d --restart=always \
  --name verification-proxy \
  -p 443:443 \
  -e 'SERVER_NAME=verification.example.com' \
  -e 'UPSTREAM_TARGET=http-server:8080' \
  -e 'CERT_PUBLIC_PATH=/certs/fullchain.pem' \
  -e 'CERT_PRIVATE_PATH=/certs/privkey.pem' \
  -e 'SSL_VERIFY_CLIENT=on' \
  -e 'CERT_CLIENT_PATH=/certs/clientchain.pem' \
  -e 'ADD_PROXY_HEADER=X-Ssl-Client-Subject $ssl_client_s_dn' \
  -v '/certs:/certs:ro' \
  --link 'http-server:http-server' \
  justsml/ssl-proxy:latest

Arguments

NameDefault/ReqdNotes
CERT_AUTOOptionalSet to true to automatically request certificate for $SERVER_NAME - caution: don't exceed let's encrypts API limits.
CERT_PUBLIC_PATHReqd. PEM fileBind-mount certificate files to container path /certs - Or override path w/ this var.
CERT_PRIVATE_PATHReqd. PEM fileBind-mount certificate files to container path /certs - Or override path w/ this var.
SERVER_NAMERequiredPrimary domain name. Not restricting.
CORS_ORIGINOptionalCORS origin to use for Access-Control-Allow-Origin header. Defaults to SERVER_NAME.
UPSTREAM_TARGETRequiredHTTP target host:port. Typically an internally routable address. e.g. localhost:9090 or rancher-server:8080
HTTPS_PORT443/RequiredNeeded for URL rewriting.
ALLOW_RC4Not setBackwards Compatible Option Required for Java 6 or WinXP/IE8
EXPIRES_DEFAULTNot setSet to apply a default expiration value for nginx location /. Useful for app & caching proxies. (For app use -1 and for caching proxy something like 6h)
USERNAMEadminBoth PASSWORD and USERNAME must be set in order to use Basic authorization
PASSWORDBoth PASSWORD and USERNAME must be set in order to use Basic authorization
PASSWD_PATH/etc/nginx/.htpasswdAlternate auth support (don't combine with USERNAME/PASSWORD) Bind-mount a custom path to /etc/nginx/.htpasswd
SSL_VERIFY_CLIENTNot setSet to verify client certificates (may be on, off, optional, or optional_no_ca). If set and not optional_no_ca, CERT_CLIENT_PATH must be set.
CERT_CLIENT_PATHNot setNeeded for client certificate verification. This cert must be PEM-encoded and contain the trusted CA and Intermediate CA certs.
ADD_HEADERNot setUseful for tagging routes in your infrastructure.
ADD_PROXY_HEADERNot setUseful for providing metadata to the upstream server.
SERVER_NAMES_HASH_SIZE32Maximum size of server name. Set it to 64/128/... if nginx fails to start with could not build server_names_hash, you should increase server_names_hash_bucket_size error message.
PROXY_HEADER_HOSTOptionalThe host value that will be set in the request header. Defaults to the nginx variable, '$host'. Set this value (e.g., to the nginx variable, '$http_host') if including the port number in the Host header is important.

Contributing / Dev Notes

WORK IN PROGRESS:

  1. HTTPS -> HTTPS proxying support. AKA End-to-end TLS. (skipped due to underwhelming performance and extra complexity in the bash startup script.)
  2. Better CORS support: multi host name
  3. haproxy alt version
# Publish 'latest' version
docker build -t ssl-proxy:latest .
docker tag ssl-proxy:latest justsml/ssl-proxy:latest
docker push justsml/ssl-proxy:latest
# Push a tagged version:
# docker tag ssl-proxy:latest justsml/ssl-proxy:v1.0.1
# docker push justsml/ssl-proxy:v1.0.1

# Remember to docker pull on servers
docker pull justsml/ssl-proxy:latest

# Local testing:
docker build -t ssl-proxy:latest .
docker rm -f TEST-ssl-proxy
docker run --rm \
  --name TEST-ssl-proxy \
  -v ~/certs/xray:/certs \
  -p 5000:5000 \
  -e 'HTTPS_PORT=5000' \
  -e 'USERNAME=devops' \
  -e 'PASSWORD=secure' \
  -e 'SERVER_NAME=hub.example.com' \
  -e 'UPSTREAM_TARGET=www.google.com:80' \
  -e 'CERT_PUBLIC_PATH=/certs/fullchain.pem' \
  -e 'CERT_PRIVATE_PATH=/certs/privkey.pem' \
  ssl-proxy:latest


Tag summary

Content type

Image

Digest

Size

19.2 MB

Last updated

about 5 years ago

docker pull justsml/ssl-proxy