Create and automatically renew website SSL certificates using the Let's Encrypt free certificate authority and its client certbot. Built on top of the Nginx server running on Debian. OpenSSL is used to create the Diffie-Hellman parameters used during the initial handshake.
This container requests SSL certificates from Let's Encrypt, with the help of their certbot script, which they provide for the absolutely bargain price of free! If you like what they do, please donate.
This repository was originally forked from @henridwyer
by @staticfloat
,
and is now forked again by me! I thought the container could be more autonomous
and stricter when it comes to checking that all files exist. In addition,
this container also allows for multiple server names when requesting
certificates (i.e. both example.com
and www.example.com
will be included in
the same certificate request if they are defined in the Nginx configuration
files).
-
This guide expects you to already own a domain which points at the correct IP address, and that you have both port
80
and443
correctly forwarded if you are behind NAT. Otherwise I recommend DuckDNS as a Dynamic DNS provider, and then either search on how to port forward on your router or maybe find it here. -
Tips on how to make a proper server config file, and how to create a simple test, can be found under the Good to Know section.
-
I don't think it is necessary to mention if you managed to find this repository, however, I have been proven wrong before so I want to make it clear that this is a Dockerfile which requires Docker to function.
This option is for if you have downloaded this entire repository.
Place any additional server configuration you desire inside the nginx_confd/
folder and run the following command in your terminal while residing inside
the src/
folder.
docker build --tag jonasal/nginx-certbot:latest .
This option is for if you make your own Dockerfile
.
This image exist on Docker Hub under jonasal/nginx-certbot
, which means you
can make your own Dockerfile
for a cleaner folder structure. Just add a
command where you copy in your own server configuration files.
FROM jonasal/nginx-certbot:latest
COPY conf.d/* /etc/nginx/conf.d/
Don't forget to build it!
docker build --tag jonasal/nginx-certbot:latest .
Irregardless what option you chose above you run it with the following command:
docker run -it --env CERTBOT_EMAIL=your@email.org -p 80:80 -p 443:443 \
-v nginx_secrets:/etc/letsencrypt jonasal/nginx-certbot:latest
The CERTBOT_EMAIL
environment variable is required by certbot for them to
contact you in case of security issues.
You should be able to detach from the container by pressing
Ctrl
+p
+Ctrl
+o
An example of a docker-compose.yaml
file can be found in the example
folder.
The default parameters that are found inside the .env
file will be overwritten
any environment variables you set in the .yaml
file.
version: '3'
services:
nginx-certbot:
build: .
restart: unless-stopped
environment:
- CERTBOT_EMAIL=your@email.org
- STAGING=0
- DHPARAM_SIZE=2048
- RSA_KEY_SIZE=2048
ports:
- 80:80
- 443:443
volumes:
- nginx_secrets:/etc/letsencrypt
volumes:
nginx_secrets:
You then build and start with the following commands. Just remember to
place any additional server configs you want inside the nginx_confd/
folder
beforehand.
docker-compose up --build
In case you are experimenting with setting this up I suggest you set the
environment variable STAGING=1
as this will change the challenge URL to
the staging one. This will not give you proper certificates, but it has
ridiculous high
rate limits compared to
the non-staging
production certificates.
Include it like this:
docker run -d --env CERTBOT_EMAIL=your@email.org --env STAGING=1 \
-p 80:80 -p 443:443 jonasal/nginx-certbot:latest
As an example of a barebone (but functional) SSL server in Nginx you can
look at the file example_server.conf
inside the example
directory. By
replacing 'yourdomain.org
' with your own domain you can actually use this
config to quickly test if things are working properly.
Place the modified config inside nginx_confd/
, build
the container and then
run it as described above
. Let it do
it's magic for a while, and then try to visit your domain. You should be greeted
with the string Let's Encrypt certificate successfully installed!
The script will go trough all configuration files it finds inside Nginx's
conf.d
folder, and create requests from the file's content. In every unique
file it will find the line that says
ssl_certificate_key /etc/letsencrypt/live/yourdomain.org/privkey.pem;
which means that the "primary domain" is yourdomain.org
. It will then find all
the lines that contain server_name
and make a list of all the words that exist
on the same line. So a file containing something like this:
server {
listen 443 ssl;
server_name yourdomain.org www.yourdomain.org;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.org/privkey.pem;
...
}
server {
listen 443 ssl;
server_name yourdomain.org sub.yourdomain.org;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.org/privkey.pem;
...
}
will share the same certificate, but the certbot command will include all listed domain variants. The limitation is that you should list all your listening servers that have the same primary domain in the same file. The certificate request from the above file will then become something like this:
certbot ... -d yourdomain.org -d www.yourdomain.org -d sub.yourdomain.org
Regarding the Diffie-Hellman parameter it is recommended that you have one for your server. However, you can make a config file without it and Nginx will work fine with ciphers that don't rely on Diffie-Hellman key exchange. (Info about ciphers).
The larger you make these parameters the longer it will take to generate them.
I was unlucky and it took me 65 minutes to generate a 4096 bit parameter on an
old 3.0GHz CPU. This will vary greatly between runs as some randomness is
involved. A 2048 bit parameter, which is still secure today, can probably be
calculated in about 3-5 minutes on a modern CPU. To modify the size of the
parameter you may set the DHPARAM_SIZE
environment variable. Default is 2048
if nothing is provided.
It is also possible to have all your server configs point to the same
Diffie-Hellman parameter on disk. There is no negative effects in doing this for
home use
[1]
[2].
For persistence you should place it inside the dedicated
folder /etc/letsencrypt/dhparams/
which is inside a Docker volume. There is
however no requirement to do so, as a missing parameter will be created where
the config file expects the file to be. This means that you may also create this
file on an external computer and mount it to any folder that is not under
/etc/letsencrypt/
as that will cause a double mount.
- Make both Nginx and the update script child processes of the entryscript.
- Container will now die along with Nginx like it should.
- The Diffie-Hellman parameters now have better permissions.
- Container now exist on Docker Hub under
jonasal/nginx-certbot:latest
- More documentation.
@JonasAlfredsson
enters the battle.- Diffie-Hellman parameters are now automatically generated.
- Nginx now handles everything http related, certbot set to webroot mode.
- Better checking to see if necessary files exist.
- Will now request a certificate that includes all domain variants listed
at the
server_name
line. - More extensive documentation.
- Ditch cron, it never liked me anway. Just use
sleep
and awhile
loop instead.
- Complete rewrite, build this image on top of the
nginx
image, and runcron
/certbot
alongsidenginx
so that we can have nginx configs dynamically enabled as we get SSL certificates.
- Add
nginx_auto_enable.sh
script to/etc/letsencrypt/
so that users can bring nginx up before SSL certs are actually available.
- Change the name to
docker-certbot-cron
, update documentation, strip out even more stuff I don't care about.
- Rip out a bunch of stuff because
@staticfloat
is a monster, and likes to do things his way
- Add support for webroot mode.
- Run certbot once with all domains.
- Upgraded to use certbot client
- Changed image to use alpine linux
- Initial release