Table of Contents
This is an Ansible playbook to set up, harden and configure an nginx webserver on Debian.
Features:
- Cloudinit config included
- Public Key only SSH
- Basic Linux hardening included
- Unprivileged & Sandboxed nginx server/user
- Auto SSL Certificates
This is built with Debian 12 but can be modified for different distros.
ssh-keygenssh-copy-id -i <public-key-location> root@<host>ansible-galaxy collection install -r requirements.yml -p ./collectionsAdd hostname, deployment user name, ssh key and timezone to ./example.cloudinit-debian.yml and rename file to cloudinit-debian.yml.
Change both IPs in ansible/inventory/example.hosts.ini and rename file to hosts.ini.
Customize ssh port and change ansible user to deployment user in ansible/group_vars/example.all.yml and rename file to all.yml.
Customize ssh port, domains, webroot and add admin mail and ssh private key location to ansible/group_vars/webserver/example.settings.yml and rename file.
Optionally change ACME authority inside ansible/roles/server/vars/main.yml if you want to use a different one than Let's Encrypt.
You will need a hash of your password, for example via mkpasswd. For rounds I choose a value above 100k but this barely matters (a strong password does though).
mkpasswd -m sha512crypt --rounds=<VALUE>Now see the example vault for the template. Add the name of your deployment user (same as in cloudinit), the hash of the password you chose and the pubkey (if you're not using cloudinit). Add the password to the nginx user and set Ansible's privilege escalation password to the deployment user's unhashed password.
ansible-vault create ansible/group_vars/webserver/vault.ymlOnly really recommended when using a passphrase-protected ssh key so that you don't have to reenter it every time you run a play.
eval "$(ssh-agent -s)"
ssh-add <private-key-location>ansible-playbook server_baseline.yml -i ./inventory/hosts.ini --ask-vault-pass
ansible-playbook server_config.yml -i ./inventory/hosts.ini --ask-vault-pass- Add website role
- Define recurring jobs to run tasks, mainly cert check/renewal and site update
- Add lab/test environment for dev
- Add maintenance user/admin, instead of giving deployment user all rights
To debug certificate issues, change the acme authority to the staging environment of Let's Encrypt (or your CA of choice). This prevents running into rate limits.
Change the acme authority variable to acme_authority: https://acme-staging-v02.api.letsencrypt.org/directory. I added a vars line to the include_role task.
openssl x509 -in /etc/nginx/ssl/webserver/fullchain.pem -noout -enddateecho | openssl s_client -connect <DOMAINNAME>:443 -servername <DOMAINNAME> 2>/dev/null \
| openssl x509 -noout -issuer -subject -datesopenssl s_client -connect <DOMAINNAME>:443 -servername <DOMAINNAME> -alpn h2 -brief </dev/null# HTTP/2
curl -vkI --http2 https://<DOMAINNAME>/
# Force HTTP/1.1
curl -vkI --http1.1 https://<DOMAINNAME>/If HTTP/1.1 works but HTTP/2 fails, it’s almost certainly the listener (listen 443 ssl http2; missing/duplicated), a buggy module combo (gzip/brotli/header munging), or a Content‑Length mismatch on compressed output.
If both fail the same way, it may be root/try_files/permissions.
To determine whether a problem is caused by HTTP/2, temporarily disable it by removing the http2 parameter from your TLS listener:
listen 443 ssl;sudo nginx -t && sudo systemctl reload nginxiptables -LContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the GNU GPLv3. See LICENSE for more information.