feat: add initial setup for pearl server
parent
2ae759025c
commit
824d7b8a12
15
README.md
15
README.md
|
@ -1,8 +1,16 @@
|
||||||
# Raspberry Pi NAS
|
# Homelab
|
||||||
|
|
||||||
Ansible configuration repository for my Raspberry Pi's.
|
Ansible configuration repository for my homelab.
|
||||||
|
|
||||||
## Initial setup for new systems
|
## Servers
|
||||||
|
|
||||||
|
* `pi`: Raspberry Pi's
|
||||||
|
* `ruby`
|
||||||
|
* `sapphire`
|
||||||
|
* `hetzner`: Hetzner VPS servers
|
||||||
|
* `pearl`
|
||||||
|
|
||||||
|
## Initial setup for new Raspberry Pi
|
||||||
|
|
||||||
1. Flash [Debian Raspberry Pi](https://raspi.debian.net/) on the SD card.
|
1. Flash [Debian Raspberry Pi](https://raspi.debian.net/) on the SD card.
|
||||||
2. Configure `/boot/firmware/sysconf.txt`
|
2. Configure `/boot/firmware/sysconf.txt`
|
||||||
|
@ -18,3 +26,4 @@ Ansible configuration repository for my Raspberry Pi's.
|
||||||
overwrites the one set in the hosts file
|
overwrites the one set in the hosts file
|
||||||
9. Run `ansible-playbook -i initial-hosts.ini first_run.yml`. This command will
|
9. Run `ansible-playbook -i initial-hosts.ini first_run.yml`. This command will
|
||||||
hang at the `restart networking` step; at this point you can Ctrl-C.
|
hang at the `restart networking` step; at this point you can Ctrl-C.
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,80 @@
|
||||||
# -*- mode: ruby -*-
|
# -*- mode: ruby -*-
|
||||||
# vi: set ft=ruby :
|
# vi: set ft=ruby :
|
||||||
|
|
||||||
|
# All Vagrant configuration is done below. The "2" in Vagrant.configure
|
||||||
|
# configures the configuration version (we support older styles for
|
||||||
|
# backwards compatibility). Please don't change it unless you know what
|
||||||
|
# you're doing.
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box = "generic/debian11"
|
# The most common configuration options are documented and commented below.
|
||||||
|
# For a complete reference, please see the online documentation at
|
||||||
|
# https://docs.vagrantup.com.
|
||||||
|
|
||||||
# Use the standard insecure SSH key
|
# Every Vagrant development environment requires a box. You can search for
|
||||||
config.ssh.insert_key = false
|
# boxes at https://vagrantcloud.com/search.
|
||||||
|
config.vm.box = "bento/debian-12"
|
||||||
|
|
||||||
# Don't mount the current directory in the VM
|
# Disable automatic box update checking. If you disable this, then
|
||||||
|
# boxes will only be checked for updates when the user runs
|
||||||
|
# `vagrant box outdated`. This is not recommended.
|
||||||
|
# config.vm.box_check_update = false
|
||||||
|
|
||||||
|
# Create a forwarded port mapping which allows access to a specific port
|
||||||
|
# within the machine from a port on the host machine. In the example below,
|
||||||
|
# accessing "localhost:8080" will access port 80 on the guest machine.
|
||||||
|
# NOTE: This will enable public access to the opened port
|
||||||
|
# config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||||
|
|
||||||
|
# Create a forwarded port mapping which allows access to a specific port
|
||||||
|
# within the machine from a port on the host machine and only allow access
|
||||||
|
# via 127.0.0.1 to disable public access
|
||||||
|
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
|
||||||
|
|
||||||
|
# Create a private network, which allows host-only access to the machine
|
||||||
|
# using a specific IP.
|
||||||
|
|
||||||
|
# Create a public network, which generally matched to bridged network.
|
||||||
|
# Bridged networks make the machine appear as another physical device on
|
||||||
|
# your network.
|
||||||
|
# config.vm.network "public_network"
|
||||||
|
|
||||||
|
# Share an additional folder to the guest VM. The first argument is
|
||||||
|
# the path on the host to the actual folder. The second argument is
|
||||||
|
# the path on the guest to mount the folder. And the optional third
|
||||||
|
# argument is a set of non-required options.
|
||||||
|
# config.vm.synced_folder "../data", "/vagrant_data"
|
||||||
|
|
||||||
|
# Disable the default share of the current code directory. Doing this
|
||||||
|
# provides improved isolation between the vagrant box and your host
|
||||||
|
# by making sure your Vagrantfile isn't accessible to the vagrant box.
|
||||||
|
# If you use this you may want to enable additional shared subfolders as
|
||||||
|
# shown above.
|
||||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||||
|
|
||||||
config.vm.define "alpha" do |n|
|
# Provider-specific configuration so you can fine-tune various
|
||||||
n.vm.hostname = "alpha.test"
|
# backing providers for Vagrant. These expose provider-specific options.
|
||||||
n.vm.network :private_network, ip: "192.168.56.5"
|
# Example for VirtualBox:
|
||||||
end
|
#
|
||||||
end
|
config.vm.provider "virtualbox" do |vb|
|
||||||
|
# Display the VirtualBox GUI when booting the machine
|
||||||
|
vb.gui = false
|
||||||
|
|
||||||
|
# Customize the amount of memory on the VM:
|
||||||
|
vb.memory = "4096"
|
||||||
|
end
|
||||||
|
|
||||||
|
config.vm.define "pearl" do |pearl|
|
||||||
|
config.vm.network "private_network", ip: "192.168.56.2"
|
||||||
|
end
|
||||||
|
#
|
||||||
|
# View the documentation for the provider you are using for more
|
||||||
|
# information on available options.
|
||||||
|
|
||||||
|
# Enable provisioning with a shell script. Additional provisioners such as
|
||||||
|
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
|
||||||
|
# documentation for more information about their specific syntax and use.
|
||||||
|
# config.vm.provision "shell", inline: <<-SHELL
|
||||||
|
# apt-get update
|
||||||
|
# apt-get install -y apache2
|
||||||
|
# SHELL
|
||||||
|
end
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[pearl]
|
|
||||||
192.168.56.2 ansible_ssh_user=vagrant ansible_ssh_private_key_file='.vagrant/machines/pearl/virtualbox/private_key'
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
pearl:
|
||||||
|
hosts:
|
||||||
|
192.168.56.2:
|
||||||
|
ansible_ssh_user: vagrant
|
||||||
|
ansible_ssh_private_key_file: '.vagrant/machines/pearl/virtualbox/private_key'
|
||||||
|
debian_version: 'trixie'
|
|
@ -9,6 +9,10 @@
|
||||||
- hosts: pearl
|
- hosts: pearl
|
||||||
become: true
|
become: true
|
||||||
roles:
|
roles:
|
||||||
# - 'any.common.enable-testing'
|
- 'any.common.debian-repositories'
|
||||||
- 'any.common.debian-user'
|
- 'any.common.debian-user'
|
||||||
|
- 'any.tools.default'
|
||||||
|
- 'any.tools.docker'
|
||||||
|
- 'any.tools.restic'
|
||||||
|
- 'any.tools.caddy'
|
||||||
tags: base
|
tags: base
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
---
|
---
|
||||||
- ansible.builtin.copy:
|
- name: Update sources list
|
||||||
src: 'sources.list'
|
ansible.builtin.template:
|
||||||
|
src: 'sources.list.j2'
|
||||||
dest: '/etc/apt/sources.list'
|
dest: '/etc/apt/sources.list'
|
||||||
owner: 'root'
|
owner: 'root'
|
||||||
group: 'root'
|
group: 'root'
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
|
register: res
|
||||||
|
|
||||||
- name: Upgrade all packages to the latest version in testing
|
- name: Upgrade all packages to the latest version in testing
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
upgrade: dist
|
upgrade: dist
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
cache_valid_time: 3600
|
cache_valid_time: 3600
|
||||||
|
when: 'res.changed'
|
||||||
|
|
||||||
- name: Clean up unused packages
|
- name: Clean up unused packages
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
autoremove: yes
|
autoremove: yes
|
||||||
|
when: 'res.changed'
|
|
@ -0,0 +1,10 @@
|
||||||
|
deb http://deb.debian.org/debian/ {{ debian_version }} main non-free-firmware
|
||||||
|
deb-src http://deb.debian.org/debian/ {{ debian_version }} main non-free-firmware
|
||||||
|
|
||||||
|
deb http://security.debian.org/debian-security {{ debian_version }}-security main non-free-firmware
|
||||||
|
deb-src http://security.debian.org/debian-security {{ debian_version }}-security main non-free-firmware
|
||||||
|
|
||||||
|
# {{ debian_version }}-updates, to get updates before a point release is made;
|
||||||
|
# see https://www.debian.org/doc/manuals/debian-reference/ch02.en.html#_updates_and_backports
|
||||||
|
deb http://deb.debian.org/debian/ {{ debian_version }}-updates main non-free-firmware
|
||||||
|
deb-src http://deb.debian.org/debian/ {{ debian_version }}-updates main non-free-firmware
|
|
@ -1,10 +0,0 @@
|
||||||
deb http://deb.debian.org/debian/ trixie main non-free-firmware
|
|
||||||
deb-src http://deb.debian.org/debian/ trixie main non-free-firmware
|
|
||||||
|
|
||||||
deb http://security.debian.org/debian-security trixie-security main non-free-firmware
|
|
||||||
deb-src http://security.debian.org/debian-security trixie-security main non-free-firmware
|
|
||||||
|
|
||||||
# trixie-updates, to get updates before a point release is made;
|
|
||||||
# see https://www.debian.org/doc/manuals/debian-reference/ch02.en.html#_updates_and_backports
|
|
||||||
deb http://deb.debian.org/debian/ trixie-updates main non-free-firmware
|
|
||||||
deb-src http://deb.debian.org/debian/ trixie-updates main non-free-firmware
|
|
|
@ -1,8 +1,9 @@
|
||||||
---
|
|
||||||
- name: Add Caddy GPG key
|
- name: Add Caddy GPG key
|
||||||
apt_key:
|
ansible.builtin.get_url:
|
||||||
url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key"
|
url: 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key'
|
||||||
state: present
|
dest: '/etc/apt/trusted.gpg.d/caddy.asc'
|
||||||
|
mode: '0644'
|
||||||
|
force: true
|
||||||
|
|
||||||
- name: Add Caddy repositories
|
- name: Add Caddy repositories
|
||||||
apt_repository:
|
apt_repository:
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
- name: Ensure common packages are installed
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
# Needed for handling GPG keys for repositories
|
||||||
|
- debian-keyring
|
||||||
|
- debian-archive-keyring
|
||||||
|
- apt-transport-https
|
||||||
|
- ca-certificates
|
||||||
|
- lsb-release
|
||||||
|
- gnupg
|
||||||
|
|
||||||
|
# Easy to edit files
|
||||||
|
- vim
|
||||||
|
- tmux
|
||||||
|
- htop
|
||||||
|
|
||||||
|
# Spam prevention
|
||||||
|
- fail2ban
|
||||||
|
|
||||||
|
# Disk monitoring
|
||||||
|
- smartmontools
|
||||||
|
|
||||||
|
# Periodic tasks
|
||||||
|
- cron
|
||||||
|
|
||||||
|
# General compression tools
|
||||||
|
- bzip2
|
||||||
|
- zip
|
||||||
|
|
||||||
|
# Working with BTRFS file systems
|
||||||
|
- btrfs-progs
|
||||||
|
|
||||||
|
- curl
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure cron service is enabled
|
||||||
|
service:
|
||||||
|
name: cron
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Ensure fail2ban service is enabled
|
||||||
|
service:
|
||||||
|
name: fail2ban
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Ensure Vim config is present
|
||||||
|
get_url:
|
||||||
|
url: 'https://r8r.be/vim'
|
||||||
|
dest: '{{ item.dest }}'
|
||||||
|
owner: "{{ item.user }}"
|
||||||
|
group: "{{ item.user }}"
|
||||||
|
mode: '644'
|
||||||
|
with_items:
|
||||||
|
- user: debian
|
||||||
|
dest: "/home/debian/.vimrc"
|
||||||
|
- user: root
|
||||||
|
dest: "/root/.vimrc"
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
- name: Ensure older Docker versions aren't installed.
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- docker
|
||||||
|
- docker-engine
|
||||||
|
- docker.io
|
||||||
|
- containerd
|
||||||
|
- runc
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Add Docker GPG key.
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: 'https://download.docker.com/linux/ubuntu/gpg'
|
||||||
|
dest: '/etc/apt/trusted.gpg.d/docker.asc'
|
||||||
|
mode: '0644'
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Add Docker PPA.
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
# https://gist.github.com/rbq/886587980894e98b23d0eee2a1d84933
|
||||||
|
repo: "deb https://download.docker.com/{{ ansible_system | lower }}/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Install Docker, docker-compose & cron.
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure Docker is running & enabled.
|
||||||
|
service:
|
||||||
|
name: docker
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Add Docker prune cronjob.
|
||||||
|
cron:
|
||||||
|
name: Prune the Docker system.
|
||||||
|
hour: 4
|
||||||
|
minute: 0
|
||||||
|
job: docker system prune -af
|
|
@ -0,0 +1,7 @@
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
33666438313237356564363136333933633035303531653464643766373434623834663736386463
|
||||||
|
3464643731366237633334616536613864396162353264360a316130333032316437393333396466
|
||||||
|
34356638393834316235633062646330336438376135346666663064303831666632353834663465
|
||||||
|
6636663930356138640a323433613263393939303833616637336436366630386133386338613736
|
||||||
|
34353433643539306238663638656539373731616238656635353561356632366332623532396465
|
||||||
|
3936373534643966616131616161633234663430633233653435
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
- name: Ensure download directory is present
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/opt/restic/{{ restic_version }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Ensure compressed binary is downloaded
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "https://github.com/restic/restic/releases/download/v{{ restic_version }}/restic_{{ restic_version }}_linux_arm64.bz2"
|
||||||
|
dest: "/opt/restic/{{ restic_version }}/restic-{{ restic_version }}.bz2"
|
||||||
|
register: res
|
||||||
|
|
||||||
|
- name: Ensure binary is decompressed
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: "bunzip2 -k /opt/restic/{{ restic_version }}/restic-{{ restic_version }}.bz2"
|
||||||
|
when: 'res.changed'
|
||||||
|
|
||||||
|
- name: Ensure binary is copied to correct location
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "/opt/restic/{{ restic_version }}/restic-{{ restic_version }}"
|
||||||
|
remote_src: true
|
||||||
|
dest: '/usr/local/bin/restic'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: '0755'
|
||||||
|
when: 'res.changed'
|
||||||
|
|
||||||
|
# - name: Ensure backup scripts directory is present
|
||||||
|
# ansible.builtin.file:
|
||||||
|
# path: '/etc/backups'
|
||||||
|
# state: directory
|
||||||
|
# mode: '0755'
|
||||||
|
|
||||||
|
# - name: Ensure Restic backups password file is present
|
||||||
|
# ansible.builtin.copy:
|
||||||
|
# src: 'restic_backups_passwd'
|
||||||
|
# dest: '/etc/backups/restic_backups_passwd'
|
||||||
|
# owner: root
|
||||||
|
# group: root
|
||||||
|
# mode: '0600'
|
||||||
|
|
||||||
|
# - name: Ensure backup-all script is present
|
||||||
|
# ansible.builtin.template:
|
||||||
|
# src: "backup-all.sh.j2"
|
||||||
|
# dest: '/etc/backups/backup-all.sh'
|
||||||
|
# owner: root
|
||||||
|
# group: root
|
||||||
|
# mode: '0644'
|
||||||
|
|
||||||
|
# - name: Ensure backup cronjob is enabled
|
||||||
|
# ansible.builtin.cron:
|
||||||
|
# name: 'Perform nightly backups'
|
||||||
|
# minute: '0'
|
||||||
|
# hour: '2'
|
||||||
|
# job: '/usr/bin/bash /etc/backups/backup-all.sh'
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This script sequentially executes all shell scripts matching
|
||||||
|
# /etc/backups/*.backup.sh, with environment variables configured to publish
|
||||||
|
# backups to the local Restic REST server.
|
||||||
|
|
||||||
|
# Get passed along to subcalls to bash
|
||||||
|
export RESTIC_REPOSITORY='rest:http://{{ groups['nas'][0] }}:8000/backups'
|
||||||
|
export RESTIC_PASSWORD_FILE='/etc/backups/restic_backups_passwd'
|
||||||
|
|
||||||
|
log_file='/tmp/backup-all.sh.log'
|
||||||
|
|
||||||
|
rm -f "$log_file"
|
||||||
|
|
||||||
|
for script in $(find /etc/backups -name '*.backup.sh'); do
|
||||||
|
T="$(date +%s)"
|
||||||
|
|
||||||
|
/usr/bin/bash "$script"
|
||||||
|
|
||||||
|
res="$?"
|
||||||
|
T="$(($(date +%s)-T))"
|
||||||
|
|
||||||
|
if [[ $res == 0 ]]; then
|
||||||
|
header='OK'
|
||||||
|
else
|
||||||
|
header="FAIL ($res)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf \
|
||||||
|
"%s: %s in %02dh%02dm%02ds\n" \
|
||||||
|
"$(basename "$script")" "$header" \
|
||||||
|
"$((T/3600%24))" "$((T/60%60))" "$((T%60))" \
|
||||||
|
>> "$log_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Prune older backups
|
||||||
|
/usr/local/bin/restic forget --keep-last 7 && \
|
||||||
|
/usr/local/bin/restic prune
|
||||||
|
|
||||||
|
# Send status notification
|
||||||
|
ntfy publish \
|
||||||
|
--title "Backups ($(hostname))" \
|
||||||
|
homelab "$(cat "$log_file")"
|
Loading…
Reference in New Issue