Skip to content

Commit

Permalink
Automates SSL certification with Certbot
Browse files Browse the repository at this point in the history
  • Loading branch information
pgstevenson committed Mar 26, 2019
1 parent 3f8ab08 commit d262543
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 30 deletions.
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
RStudio
================

Definition of a containerized RStudio instance from:
A containerized RStudio instance from the rocker base image:

rocker/tidyverse:3.5.2

Container comes with a `nginx` reverse proxy (port 80 access on `localhost`)
This container comes with a `nginx` reverse proxy (access via. port 80)
and the Tidyverse collection of packages pre-installed by default.

By default, the running container will be secured with SSL encryption via.
Certbot. Some configuration will be required for the container to start, see
below; however, instructions are provided in `nginx.conf` to remove this security.

The `home/rstudio/projects`, `/usr/local/lib/R` and `/home/rstudio/.rstudio`
directories are configured as Docker volumes.

Expand Down Expand Up @@ -48,13 +52,18 @@ Default password: rstudio1

## HTTPS encryption

HTTPS encryption is enabled by default, which will requrie SSL
certificates to be created. SSL certificates can be generated following
these instructions by Let’s Encrypt <https://letsencrypt.org/>
[These instructions](https://medium.com/@pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71)
were used to set up a secure HTTPS connection to RStuido with Certbot SSL
certificates. Also see [here](https://github.com/wmnnd/nginx-certbot).

This will not work out of the box, the NGINX configuration file will need to be
updated with your domain name (which is required) at the indicated places in
`nginx.conf`. `init-letsencrypt.sh` also needs to be configured with your domain
names(s) and email address.

The `*.crt` and `*.key` should be put into the
`nginx/certs/example.com/` directory; change “example.com” to what is
relevant for your site.
The following commands will need to be run on the host machine in order to obtain
the first valid certificates: first run `chmod +x init-letsencrypt.sh` then
`sudo ./init-letsencrypt.sh`.

If HTTPS encription is not required then modifications can be made to
`nginx.conf` where indicated.
If HTTPS security is not wanted then you will need to remove the indicated chunks
of code in `nginx.conf`.
14 changes: 13 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
version: "3.6"

services:
nginx:
image: nginx:alpine
Expand All @@ -8,10 +9,21 @@ services:
- tki-net
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./certs:/root/certs/
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- 80:80
- 443:443
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

certbot:
image: certbot/certbot
container_name: certbot
restart: on-failure
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

rstudio:
image: rocker/tidyverse:3.5.2
Expand Down
75 changes: 75 additions & 0 deletions init-letsencrypt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

domains=(example.org www.example.org)
rsa_key_size=4096
data_path="./data/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits

if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi


if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi

echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:1024 -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo


echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo

echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo


echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
domain_args="$domain_args -d $domain"
done

# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac

# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi

docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo

echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload
37 changes: 18 additions & 19 deletions nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,32 @@ http {
server rstudio:8787;
}

server { # remove this server block if ssl certification is not wanted
#### START REMOVE - remove this block of code if SSL certification is not wanted ####
server {
listen 80;
server_name localhost;
server_name example.org; #### UPDATE example.org to your domain name ####
server_tokens off;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

location / {
return 301 https://$host$request_uri;
}
}
#### END REMOVE ####

server {
listen 443 ssl; # listen 80; # remove first "listen" statement if ssl certification is not wanted
server_name localhost;

#### START REMOVE - remove this block of code if SSL certification is not wanted

# Certificates - change these so they are relevant to the site
ssl_certificate /root/certs/example.com/example.com.crt; #### UPDATE THIS LINE ####
ssl_certificate_key /root/certs/example.com/example.com.key; #### UPDATE THIS LINE ####

# SSL optimization
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 180m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DHE+AES128:!ADH:!AECDH:!MD5;

#### END REMOVE
listen 443 SSL; # listen 80; #### remove "listen 443 SSL; #" statement if SSL certification is not wanted ####
server_name example.org; #### UPDATE example.org to your domain name ####

#### START REMOVE - remove this block of code if SSL certification is not wanted ####
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; #### UPDATE example.org to your domain name ####
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; #### UPDATE example.org to your domain name ####
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
#### END REMOVE ####

location / {
proxy_pass http://rstudio;
Expand Down

0 comments on commit d262543

Please sign in to comment.