---
author: Alvie Rahman
date: \today
title: Setting Up Nginx and Let's Encrypt in Docker
tags: [ linux, docker, programming ]
---

# Setting Up Nginx and Let's Encrypt in Docker

This turned out to be way harder than I thought it would be.
I tried to follow
[this](https://pentacent.medium.com/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71)
post here but the `init-letsencrypt.sh` script didn't work for me.

Most of the content here is from that post.

## Create the necessary files

### `docker-compose.yaml`

Notice how `certbot`'s `entrypoint` field is commented out?
Yeah, that's one of the things that tripped me up.
When the autorenew entrypoint is specified, you can't perform one of the future steps.

```yaml
version: '3'

services:
  nginx:
    image: nginx:1.15-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./data/nginx:/etc/nginx/conf.d
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
  certbot:
    image: certbot/certbot
    # entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
```

### `data/nginx/app.conf`

Again, things are commented out in this file.
The SSL section is commented out as Nginx cannot start an SSL server without first having SSL
certificates but certbot won't give us SSL certificates unless we have a webserver (the certbot
Docker image supports hosting a standalone server for this purpose but that would mean changing
around the ports in `docker-compose.yaml`).

Also the 301 redirect in the port 80 section is commented out as we don't want to immediately
redirect certbot to a https URL we aren't listening for.

```
server {
    listen 80;
    server_name DOMAIN.NAME;

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

    location / {
        #return 301 https://$host$request_uri;
        proxy_pass http://example.com;
    }    
}

# server {
#     listen 443 ssl;
#     server_name DOMAIN.NAME;
#     
#     location / {
#         # anything you want can go in here, of course
#         proxy_pass http://example.com;
#     }
#     ssl_certificate /etc/letsencrypt/live/DOMAIN.NAME/fullchain.pem;
#     ssl_certificate_key /etc/letsencrypt/live/DOMAIN.NAME/privkey.pem;
#     include /etc/letsencrypt/options-ssl-nginx.conf;
#     ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# }
```

## Set your domain

Run the following command, replacing `REPLACEME` with your domain name:

```
sed -i 's/DOMAIN.NAME/REPLACEME/g' data/nginx/app.conf
```

## Get your first certificates

Run the following commands:

    docker-compose up -d nginx
    docker-compose run certbot certonly --webroot /var/www/certbot

Enter the information your are prompted for.

## Enable HTTPS on Nginx and auto renew certificates

1. Uncomment the commented out server block in `data/nginx/app.conf`.
2. Remove the `proxy_pass` line in the port 80 server block.
3. Uncomment the line starting with `return 301`
4. Restart Nginx (`docker-compose restart nginx`)
5. Uncomment line beginning with `entrypoint` in `docker-compose.yaml`
