-
-
Save mattiaslundberg/ba214a35060d3c8603e9b1ec8627d349 to your computer and use it in GitHub Desktop.
Ansible playbook to setup HTTPS using Let's encrypt on nginx. | |
The Ansible playbook installs everything needed to serve static files from a nginx server over HTTPS. | |
The server pass A rating on [SSL Labs](https://www.ssllabs.com/). | |
To use: | |
1. Install [Ansible](https://www.ansible.com/) | |
2. Setup an Ubuntu 16.04 server accessible over ssh | |
3. Create `/etc/ansible/hosts` according to template below and change example.com to your domain | |
4. Copy the rest of the files to an empty directory (`playbook.yml` in the root of that folder and the rest in the `templates` subfolder) | |
5. Run `ansible-playbook playbook.yml` | |
6. Copy your (static HTML) code to `/var/www/example.com` (`example.com` replaced with your domain) | |
7. Restart nginx (`systemctl restart nginx`) |
[letsencrypt] | |
example.com ansible_user=root [email protected] domain_name=example.com |
--- | |
- hosts: letsencrypt | |
become: true | |
gather_facts: no | |
pre_tasks: | |
- raw: apt-get install -y python-simplejson | |
tasks: | |
- name: Upgrade system | |
apt: upgrade=dist update_cache=yes | |
- name: Install nginx | |
apt: name=nginx state=latest | |
- name: install letsencrypt | |
apt: name=letsencrypt state=latest | |
- name: create letsencrypt directory | |
file: name=/var/www/letsencrypt state=directory | |
- name: Remove default nginx config | |
file: name=/etc/nginx/sites-enabled/default state=absent | |
- name: Install system nginx config | |
template: | |
src: templates/nginx.conf.j2 | |
dest: /etc/nginx/nginx.conf | |
- name: Install nginx site for letsencrypt requests | |
template: | |
src: templates/nginx-http.j2 | |
dest: /etc/nginx/sites-enabled/http | |
- name: Reload nginx to activate letsencrypt site | |
service: name=nginx state=restarted | |
- name: Create letsencrypt certificate | |
shell: letsencrypt certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }} | |
args: | |
creates: /etc/letsencrypt/live/{{ domain_name }} | |
- name: Generate dhparams | |
shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048 | |
args: | |
creates: /etc/nginx/dhparams.pem | |
- name: Install nginx site for specified site | |
template: | |
src: templates/nginx-le.j2 | |
dest: /etc/nginx/sites-enabled/le | |
- name: Reload nginx to activate specified site | |
service: name=nginx state=restarted | |
- name: Add letsencrypt cronjob for cert renewal | |
cron: | |
name: letsencrypt_renewal | |
special_time: weekly | |
job: letsencrypt --renew certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }} && service nginx reload |
server_tokens off; | |
server { | |
listen 80 default_server; | |
server_name {{ domain_name }}; | |
location /.well-known/acme-challenge { | |
root /var/www/letsencrypt; | |
try_files $uri $uri/ =404; | |
} | |
location / { | |
rewrite ^ https://{{ domain_name }}$request_uri? permanent; | |
} | |
} | |
add_header X-Frame-Options SAMEORIGIN; | |
add_header X-Content-Type-Options nosniff; | |
add_header X-XSS-Protection "1; mode=block"; | |
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-src 'none'; object-src 'none'"; | |
# HTTPS server | |
# | |
server { | |
listen 443 ssl default deferred; | |
server_name {{ domain_name }}; | |
ssl on; | |
ssl_certificate /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem; | |
ssl_certificate_key /etc/letsencrypt/live/{{ domain_name }}/privkey.pem; | |
ssl_trusted_certificate /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem; | |
ssl_session_cache shared:SSL:50m; | |
ssl_session_timeout 5m; | |
ssl_stapling on; | |
ssl_stapling_verify on; | |
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; | |
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; | |
ssl_dhparam /etc/nginx/dhparams.pem; | |
ssl_prefer_server_ciphers on; | |
root /var/www/{{ domain_name }}; | |
index index.html index.htm; | |
location / { | |
try_files $uri $uri/ =404; | |
} | |
} |
user www-data; | |
worker_processes 4; | |
pid /run/nginx.pid; | |
events { | |
worker_connections 768; | |
} | |
http { | |
sendfile on; | |
tcp_nopush on; | |
tcp_nodelay on; | |
keepalive_timeout 65; | |
types_hash_max_size 2048; | |
include /etc/nginx/mime.types; | |
default_type application/octet-stream; | |
access_log /var/log/nginx/access.log; | |
error_log /var/log/nginx/error.log; | |
gzip on; | |
gzip_disable "msie6"; | |
include /etc/nginx/conf.d/*.conf; | |
include /etc/nginx/sites-enabled/*; | |
} |
Certbot instructions here:
https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx
This is amazing. Worked without any major modifications on ubuntu 19.10 on a raspberry pi.
I did the following changes
- Changed hosts to localhost
- Removed inventory file
- Renamed the template files to fix their names after the download
- Modified the SSL config to be a reverse proxy
- Moved variables from inventory file into vars in the playbook
- ran the playbook with ansible-playbook playbook.yml
My playbook:
---
- hosts: localhost
become: true
gather_facts: no
vars:
domain_name: www.example.com
letsencrypt_email: [email protected]
tasks:
- name: Install nginx
apt:
name: nginx
state: latest
- name: install letsencrypt
apt:
name: letsencrypt
state: latest
- name: create letsencrypt directory
file:
name: /var/www/letsencrypt
state: directory
- name: Remove default nginx config
file:
name: /etc/nginx/sites-enabled/default
state: absent
- name: Install system nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Install nginx site for letsencrypt requests
template:
src: nginx-http.j2
dest: /etc/nginx/sites-enabled/http
- name: Reload nginx to activate letsencrypt site
service:
name: nginx
state: restarted
- name: Create letsencrypt certificate
shell: letsencrypt certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }}
args:
creates: /etc/letsencrypt/live/{{ domain_name }}
- name: Generate dhparams
shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048
args:
creates: /etc/nginx/dhparams.pem
- name: Install nginx site for specified site
template:
src: nginx-le.j2
dest: /etc/nginx/sites-enabled/le
- name: Reload nginx to activate specified site
service: name=nginx state=restarted
- name: Add letsencrypt cronjob for cert renewal
cron:
name: letsencrypt_renewal
special_time: weekly
job: letsencrypt --renew certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }} && service nginx reload
@diablozzq this is great. what if need to handle 2 sub domains
example: domain_name: aaa.example.com
and domain_name_2: bbbb.example.com
@diablozzq this is great. what if need to handle 2 sub domains
example:
domain_name: aaa.example.com
anddomain_name_2: bbbb.example.com
you can do like this: -d www.aname.com -d api.aname.com -d api2.aname.com
also you can use wildcard way
Thanks for this!
FYI, on my Ubuntu 16.04.6 server with certbot 0.27.0
, I had to change the cronjob from
job: letsencrypt --renew certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }} && service nginx reload
to
job: letsencrypt --renew-by-default certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos -d {{ domain_name }} && service nginx reload
Thank you man! This saved me hours!
pre_tasks:
- raw: apt-get install -y python-simplejson
for Gentoo replace
pre_tasks:
- raw: emerge -v dev-python/simplejson
thanks man! amazing work.
Great stuff man, thanks a lot!
why u not using proxy nginx with buffer?
thanks for this! nowadays python-simplejson
is python3-simplejson
(tested on debian 11)
--renew-by-default
thanks for the tip
Can you share the command need to run in playbook for certbot (i'm using ubuntu)