Skip to content

Instantly share code, notes, and snippets.

@jdforsythe
Last active August 10, 2020 20:18
Show Gist options
  • Save jdforsythe/09e9fd0dc7f75e7468fc48c9bc8b1598 to your computer and use it in GitHub Desktop.
Save jdforsythe/09e9fd0dc7f75e7468fc48c9bc8b1598 to your computer and use it in GitHub Desktop.
Develop With Local HTTPs Domains
#!/bin/bash
## https://gist.github.com/jdforsythe/09e9fd0dc7f75e7468fc48c9bc8b1598
##
## This will:
##
## 1. Install `mkcert` and create a self-signed CA and certificates for fake domains and trust them
## with the system's trust store. This allows you to develop using the same SSL/TLS techniques you
## would in production, bringing dev-prod parity and allowing things like cross-sub-domain secure
## cookies with CORS
## 2. Install `nginx`. This allows you to make requests to all the domains on port 443 as you would
## in production and nginx will proxy them to the port your app is running on locally. It also
## allows you to terminate the SSL/TLS at the proxy and only deal with HTTP in your applications.
## This simplifies your app and mimics the production scenario of terminating the SSL/TLS at a
## load balancer, API gateway, reverse proxy, etc.
## 3. Generate nginx configuration to set up the proxying and to add "secure" flag to every cookie.
## You can avoid the errors from your server applications that you can't add secure on HTTP requests
## by allowing nginx to add the flag using the generated proxy configuration. All of your cookies
## will then be set to secure. Restarts nginx with the new config.
## 4. Generates `hosts` file entries to map your fake subdomains to localhost and appends them to `/etc/hosts`
##
#####################################
## CONFIGURATION
#####################################
## Set the `DOMAIN` variable to the top level domain you want to work with (no "www", e.g. "example.test")
DOMAIN=example.test
## Set the `SUBDOMAINS` variable to a list of the local subdomains you want certificates for along with
## the port they will be running on, separated by a semicolon, e.g. 'www;4300'
declare -a SUBDOMAINS=(
'www;4300'
'app;4200'
'api;8080'
)
## The NGINX_PATH is the base `etc/nginx` folder. This should not need changed unless nginx changes
## its folder location
NGINX_PATH=/usr/local/etc/nginx/
## The NGINX_SERVER_PATH is the folder in the NGINX_PATH that the nginx configuration should go
## into. By default on homebrew install this is `/usr/local/etc/nginx/servers`
NGINX_SERVER_PATH=${NGINX_PATH}servers/
## These are the files output by mkcert. These should not need changed unless mkcert changes the
## default output filename schema
CERT_FILE=${DOMAIN}+4.pem
KEY_FILE=${DOMAIN}+4-key.pem
## The SSL_PATH is where the certificates will be stored, in a domain subfolder. You can change this
## if you wish
SSL_PATH=${NGINX_PATH}ssl/${DOMAIN}/
CONFIG_COMMENT=$(cat <<EOF
####################################################
## Config generated automatically
## https://gist.github.com/jdforsythe/09e9fd0dc7f75e7468fc48c9bc8b1598
####################################################
EOF
)
## Holds the nginx configuration
NGINX_CONF="${CONFIG_COMMENT}"
#####################################
## FUNCTIONS
#####################################
## Create an `upstream` block for each subdomain
set_nginx_upstream() {
NGINX_CONF+=$(cat <<EOF
upstream ${1} {
server 127.0.0.1:${2};
}
EOF
)
}
## Create a `server` block for each subdomain to terminate SSL and proxy
## to the corresponding `upstream`
set_nginx_server() {
NGINX_CONF+=$(cat <<EOF
server {
server_name ${1}.${DOMAIN};
listen 443 ssl;
ssl_certificate ${SSL_PATH}${CERT_FILE};
ssl_certificate_key ${SSL_PATH}${KEY_FILE};
location / {
proxy_pass http://${1};
proxy_cookie_path / "/; secure";
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host \$host:\$server_port;
proxy_set_header X-Forwarded-Server \$host;
}
}
EOF
)
}
dependencies() {
brew update
## install mkcert, nss, and nginx
brew install mkcert nginx
}
certificates() {
mkcert --install
## generate CA and certificate for *.domain.ext
mkcert $DOMAIN "*.${DOMAIN}" localhost 127.0.0.1 ::1
mkdir -p "$SSL_PATH"
mv $CERT_FILE "${SSL_PATH}${CERT_FILE}"
mv $KEY_FILE "${SSL_PATH}${KEY_FILE}"
}
nginx_config() {
for d in "${SUBDOMAINS[@]}"
do
IFS=";" read -r -a PARTS <<< "$d"
set_nginx_upstream "${PARTS[0]}" "${PARTS[1]}"
done;
for d in "${SUBDOMAINS[@]}"
do
IFS=";" read -r -a PARTS <<< "$d"
set_nginx_server "${PARTS[0]}"
done;
mkdir -p "${NGINX_SERVER_PATH}"
echo "$NGINX_CONF" > "${NGINX_SERVER_PATH}${DOMAIN}.conf"
## if you don't have nginx running as a service, run this instead:
## `nginx -s reload`
brew services restart nginx
}
hosts() {
HOSTS_FILE="${CONFIG_COMMENT}"
for d in "${SUBDOMAINS[@]}"
do
IFS=";" read -r -a PARTS <<< "$d"
SUBDOMAIN=${PARTS[0]}.${DOMAIN}
HOSTS_FILE+=$(cat <<EOF
127.0.0.1 ${SUBDOMAIN}
::1 ${SUBDOMAIN}
EOF
)
done;
HOSTS_FILE+=$(cat <<EOF
####################################################
EOF
)
echo "${HOSTS_FILE}" | sudo tee -a /etc/hosts
}
#####################################
## EXECUTION
#####################################
dependencies
certificates
nginx_config
hosts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment