-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 73cd3ef
Showing
17 changed files
with
643 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
inventory | ||
Caddyfile | ||
ansible.cfg | ||
host_vars/*.yml | ||
roles/reverse_proxy/files/caddy_override.conf | ||
|
||
.vscode/ | ||
public_keys/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Caddy reverse proxy setup with Crowdsec plugin | ||
|
||
This Ansible repo sets up a Caddy reverse proxy for my homelab services. It integrates with the Crowdsec plugin that runs on my OPNsense box. | ||
|
||
## How? | ||
|
||
Dustin Casto wrote an outstanding guide on this setup on [his website](https://homenetworkguy.com/how-to/set-up-caddy-reverse-proxy-with-lets-encrypt-and-crowdsec-using-opnsense-lapi/). I automated it with Ansible. | ||
|
||
Caddy runs on a VM in [Proxmox](https://www.proxmox.com/en/) on a DMZ network. I access it via [Tailscale](https://tailscale.com/), and it redirects me to the desired service. | ||
|
||
Every service runs with a valid HTTPS certificate. I use a wildcard certificate because it's easier to manage. I also found that retrieving certificates for each subdomain is very unreliable on my network and might take hours. | ||
|
||
I also do some SSH hardening and set up a UFW firewall. | ||
|
||
## Prerequisites | ||
|
||
1. Cloudflare account with an API key with permissions: `Zone.Zone Read` and `Zone.DNS Edit`. You need to set up this key `roles/reverse_proxy/files/caddy_override.conf` file | ||
2. I use OPNsense as my firewall. However, t should be possible to modify this playbook to just install and set up Caddy. | ||
3. A domain name. Since we want valid HTTPS certificates. | ||
4. Ubuntu. This set-up has been tested on Ubuntu 24.04, but should work on any Debian-based system. | ||
5. Public key for SSH authentication is set in the root of the repository in the `files/ansible.pub` file. | ||
|
||
### Set up Crowdsec on OPNsense | ||
|
||
This repo assumes that you have set up Crowdsec on OPNsense according to [Dustin's guide](https://homenetworkguy.com/how-to/set-up-caddy-reverse-proxy-with-lets-encrypt-and-crowdsec-using-opnsense-lapi/). During the playbook's run, it will pause and ask you to validate the Caddy machine in OPNsense. Make sure you do it as described in the guide. | ||
|
||
### Set up Cloudflare | ||
|
||
This repo builds Caddy with the Cloudflare plugin to perform the DNS-01 challenge to validate that you own a domain. [This guide](https://homenetworkguy.com/how-to/replace-opnsense-web-ui-self-signed-certificate-with-lets-encrypt/) might be helpful | ||
|
||
## Variables and files | ||
|
||
Define your host variables in `host_vars/caddyDMZ.yml`. The comments in the example file should be helpful. | ||
|
||
Set up your [Caddyfile](https://caddyserver.com/docs/caddyfile). | ||
|
||
Set up `caddy_override.conf`. It only contais Cloudflare API token. Keep it **safe**! | ||
|
||
Remove the `.example` suffix from the provided files. | ||
|
||
## How to run? | ||
|
||
1. Provided you have Ansible installed and `inventory` and `ansible.cfg` files created, you need to run `ansible-playbook bootsrap.yml`. It will create a specified Ansible user and give it `sudo` rights. From now on, you can run any Ansible playbook as this user. | ||
2. Run `ansible-playbook caddy.yml`. | ||
|
||
## Things to keep in mind | ||
|
||
1. I use `unattended-upgrades` to upgrade the system. It also _might_ reboot if it's necessary after the update. That's not ideal if you want 100% availability and stability because things can break after an update. Ubuntu is a rather stable system, and I only automatically install security updates; it _should_ not break after a reboot. | ||
2. I took steps to harden SSH and set up a firewall, but it is not a super-protected system. I do not expose any ports on my home network and use public key authentication for SSH, so this security level works for me. | ||
3. If you are inside your home network, you can set up OPNsense to override IP address that are returned by DNS. Now, if you request `service.example.com`, you will not query a remote DNS server, and the domain will resolve immediately to your local IP. See [Unbound DNS Override Aliases in OPNsense](https://homenetworkguy.com/how-to/create-unbound-dns-override-aliases-in-opnsense/) for more information. | ||
|
||
## What's missing? | ||
|
||
This is still work-in-progress. I use [Tailscale](https://tailscale.com) to access my network. Currently, I install and set up Tailscale manually. | ||
|
||
## 🙌 Thanks | ||
|
||
1. Dustin Casto for the amazing guide, [Set Up a Caddy Reverse Proxy with Let's Encrypt and CrowdSec Using OPNsense LAPI](https://homenetworkguy.com/how-to/set-up-caddy-reverse-proxy-with-lets-encrypt-and-crowdsec-using-opnsense-lapi/), this repo is based. | ||
2. Jay LaCroix's excellent [Ansible video series](https://www.youtube.com/playlist?list=PLqyUgadpThTL1guZCdGy7H8V4snPrpj8t). | ||
3. Jim's Garage for [changing the way I create new VMs](https://youtu.be/Kv6-_--y5CM). | ||
4. Software developers whose work made this repo possible. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--- | ||
- hosts: all | ||
become: true | ||
pre_tasks: | ||
- name: Update packages (Ubuntu) | ||
tags: always | ||
ansible.builtin.apt: | ||
update_cache: true | ||
upgrade: true | ||
|
||
- hosts: all | ||
become: true | ||
tasks: | ||
- name: Create ansbile user | ||
tags: always | ||
ansible.builtin.user: | ||
name: "{{ ansible_user }}" | ||
group: root | ||
state: present | ||
- name: Add SSH key for ansible user | ||
tags: always | ||
ansible.posix.authorized_key: | ||
user: "{{ ansible_user }}" | ||
key: "{{ item }}" | ||
with_file: | ||
public_keys/ansible.pub | ||
- name: Add sudoers file for ansible user | ||
tags: always | ||
ansible.builtin.copy: | ||
src: "{{ sudoers_ansible }}" | ||
dest: "{{ sudoers_ansible_path }}" | ||
owner: root | ||
group: root | ||
mode: "0440" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: caddy | ||
become: true | ||
roles: | ||
- base | ||
- reverse_proxy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
hedgehog ALL=(ALL) NOPASSWD: ALL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
ansible_user: # ansible user that will manage the server | ||
sudoers_ansible: # sudoers file for ansible user to give sudo rights | ||
sudoers_ansible_path: /etc/sudoers.d/<ansible_user> # destination path to place sudoers file | ||
ssh_users: "ansible_user" # set users that allowed SSH access to server (at least ansible_user) | ||
ssh_template_file: sshd_config_ubuntu.j2 # template for hardened sshd_config | ||
lapi_endpoint: http://192.168.1.1:8080 # Local API of Crowdsec bouncer on OPNsense |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
APT::Periodic::Update-Package-Lists "1"; | ||
APT::Periodic::Unattended-Upgrade "1"; | ||
APT::Periodic::AutocleanInterval "7"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
- name: restart_unattended_upgrades | ||
ansible.builtin.service: | ||
name: unattended-upgrades | ||
state: restarted | ||
|
||
- name: restart_ssh | ||
ansible.builtin.service: | ||
name: ssh | ||
state: restarted | ||
|
||
- name: reload_ufw | ||
community.general.ufw: | ||
state: reloaded |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
- name: Install essential packages | ||
tags: always | ||
ansible.builtin.apt: | ||
name: "{{ item }}" | ||
state: latest | ||
loop: | ||
- unattended-upgrades | ||
|
||
- name: Enable unattended-upgrades autoclean | ||
tags: always | ||
ansible.builtin.copy: | ||
src: 20auto-upgrades | ||
dest: /etc/apt/apt.conf.d/20auto-upgrades | ||
owner: root | ||
group: root | ||
notify: restart_unattended_upgrades | ||
|
||
- name: Enable automatic reboot after upgrade without confirmation | ||
ansible.builtin.lineinfile: | ||
path: /etc/apt/apt.conf.d/50unattended-upgrades | ||
regexp: ^//Unattended-Upgrade::Automatic-Reboot "false"; | ||
line: Unattended-Upgrade::Automatic-Reboot "true"; | ||
notify: restart_unattended_upgrades | ||
|
||
- name: Set automatic reboot time | ||
ansible.builtin.lineinfile: | ||
path: /etc/apt/apt.conf.d/50unattended-upgrades | ||
regexp: ^//Unattended-Upgrade::Automatic-Reboot-Time | ||
line: Unattended-Upgrade::Automatic-Reboot-Time "05:00"; | ||
notify: restart_unattended_upgrades | ||
|
||
- name: Generate sshd_config from template | ||
tags: ssh | ||
template: | ||
src: "{{ ssh_template_file }}" | ||
dest: /etc/ssh/sshd_config | ||
owner: root | ||
group: root | ||
mode: "0644" | ||
notify: restart_ssh | ||
|
||
- name: Limit access to ssh port | ||
tags: ufw | ||
community.general.ufw: | ||
rule: limit | ||
src: 192.168.10.0/24 | ||
port: "22" | ||
proto: tcp | ||
|
||
- name: Allow all access to http port | ||
tags: ufw | ||
community.general.ufw: | ||
rule: allow | ||
port: "80" | ||
proto: tcp | ||
|
||
- name: Allow all access to https port | ||
tags: ufw | ||
community.general.ufw: | ||
rule: allow | ||
port: "443" | ||
proto: tcp | ||
|
||
- name: Deny other incoming traffic and enable UFW | ||
tags: ufw | ||
community.general.ufw: | ||
state: enabled | ||
policy: deny | ||
direction: incoming | ||
|
||
- name: Disable UFW IPv6 | ||
tags: ufw | ||
ansible.builtin.lineinfile: | ||
path: /etc/default/ufw | ||
regexp: ^IPV6= | ||
line: IPV6=no | ||
notify: | ||
- reload_ufw |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
|
||
# This is the sshd server system-wide configuration file. See | ||
# sshd_config(5) for more information. | ||
|
||
# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games | ||
|
||
# The strategy used for options in the default sshd_config shipped with | ||
# OpenSSH is to specify options with their default value where | ||
# possible, but leave them commented. Uncommented options override the | ||
# default value. | ||
|
||
Include /etc/ssh/sshd_config.d/*.conf | ||
|
||
AllowUsers {{ ssh_users }} | ||
|
||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
|
||
HostKey /etc/ssh/ssh_host_rsa_key | ||
HostKey /etc/ssh/ssh_host_ed25519_key | ||
#HostKey /etc/ssh/ssh_host_ecdsa_key | ||
|
||
# Ciphers and keying | ||
#RekeyLimit default none | ||
|
||
# Cryptography | ||
{{ 'Ciphers ' ~ ssh_ciphers|join(',') }} | ||
{{ 'MACs ' ~ ssh_macs|join(',') }} | ||
{{ 'KexAlgorithms ' ~ ssh_kex|join(',') }} | ||
{{ 'HostKeyAlgorithms ' ~ ssh_client_host_key_algorithms|join(',') }} | ||
{{ 'PubkeyAcceptedAlgorithms ' ~ ssh_pubkey_accepted_algorithms|join(',') }} | ||
|
||
# Logging | ||
#SyslogFacility AUTH | ||
#LogLevel INFO | ||
|
||
# Authentication | ||
# -------------- | ||
LoginGraceTime 30s | ||
PermitRootLogin no | ||
StrictModes yes | ||
MaxAuthTries 3 | ||
MaxSessions 10 | ||
MaxStartups 10:30:60 | ||
|
||
IgnoreRhosts yes | ||
IgnoreUserKnownHosts yes | ||
HostbasedAuthentication no | ||
|
||
AuthenticationMethods publickey | ||
|
||
# To disable tunneled clear text passwords, change to no here! | ||
PermitEmptyPasswords no | ||
PasswordAuthentication no | ||
|
||
#PubkeyAuthentication yes | ||
|
||
# Kerberos options | ||
KerberosAuthentication no | ||
KerberosOrLocalPasswd no | ||
KerberosTicketCleanup yes | ||
|
||
# Network | ||
# ------- | ||
TCPKeepAlive no | ||
ClientAliveInterval 300 | ||
ClientAliveCountMax 3 | ||
|
||
# Disable tunneling | ||
PermitTunnel no | ||
|
||
AllowAgentForwarding no | ||
AllowTcpForwarding no | ||
|
||
GatewayPorts no | ||
X11Forwarding no | ||
X11UseLocalhost yes | ||
|
||
# Miscellaneous | ||
# ------- | ||
|
||
Compression no | ||
PrintMotd no | ||
|
||
# no default banner path | ||
Banner false | ||
|
||
# Expect .ssh/authorized_keys2 to be disregarded by default in future. | ||
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 | ||
|
||
#AuthorizedPrincipalsFile none | ||
|
||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
|
||
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts | ||
# Change to yes if you don't trust ~/.ssh/known_hosts for | ||
# HostbasedAuthentication | ||
# Don't read the user's ~/.rhosts and ~/.shosts files | ||
|
||
|
||
# Change to yes to enable challenge-response passwords (beware issues with | ||
# some PAM modules and threads) | ||
KbdInteractiveAuthentication no | ||
|
||
|
||
# GSSAPI options | ||
#GSSAPIAuthentication no | ||
#GSSAPICleanupCredentials yes | ||
#GSSAPIStrictAcceptorCheck yes | ||
#GSSAPIKeyExchange no | ||
|
||
# Set this to 'yes' to enable PAM authentication, account processing, | ||
# and session processing. If this is enabled, PAM authentication will | ||
# be allowed through the KbdInteractiveAuthentication and | ||
# PasswordAuthentication. Depending on your PAM configuration, | ||
# PAM authentication via KbdInteractiveAuthentication may bypass | ||
# the setting of "PermitRootLogin prohibit-password". | ||
# If you just want the PAM account and session checks to run without | ||
# PAM authentication, then enable this but set PasswordAuthentication | ||
# and KbdInteractiveAuthentication to 'no'. | ||
UsePAM yes | ||
|
||
#X11DisplayOffset 10 | ||
#PermitTTY yes | ||
#PrintLastLog yes | ||
#PermitUserEnvironment no | ||
#PidFile /run/sshd.pid | ||
#PermitTunnel no | ||
#ChrootDirectory none | ||
#VersionAddendum none | ||
|
||
# Allow client to pass locale environment variables | ||
AcceptEnv LANG LC_* | ||
|
||
# override default of no subsystems | ||
Subsystem sftp /usr/lib/openssh/sftp-server | ||
|
||
# Example of overriding settings on a per-user basis | ||
#Match User anoncvs | ||
# X11Forwarding no | ||
# AllowTcpForwarding no | ||
# PermitTTY no | ||
# ForceCommand cvs server |
Oops, something went wrong.