From 3847f187927639d3c2257cc35c0861d8a4586aea Mon Sep 17 00:00:00 2001 From: Benoit S Date: Sat, 30 Jan 2021 20:11:28 +0900 Subject: [PATCH] Init --- README.md | 7 +- files/haproxy.cfg | 89 ++++++++++++++++++++++++ files/lxd.yml | 29 ++++++++ files/nginx.default | 53 ++++++++++++++ files/ondemand.service | 14 ++++ files/set-cpufreq-performance | 38 ++++++++++ group_data/all.py | 0 inventory.py | 1 + setup-base.py | 127 ++++++++++++++++++++++++++++++++++ setup-haproxy.py | 88 +++++++++++++++++++++++ setup-zfs-and-lxd.py | 91 ++++++++++++++++++++++++ 11 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 files/haproxy.cfg create mode 100644 files/lxd.yml create mode 100644 files/nginx.default create mode 100644 files/ondemand.service create mode 100644 files/set-cpufreq-performance create mode 100644 group_data/all.py create mode 100644 inventory.py create mode 100644 setup-base.py create mode 100644 setup-haproxy.py create mode 100644 setup-zfs-and-lxd.py diff --git a/README.md b/README.md index 6968e08..29975ac 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ # lxdXX.benpro.fr -Pyinfra that deploy my LXD server. \ No newline at end of file +Pyinfra that deploy my LXD server. + +``` +pyinfra inventory.py setup-base.py +pyinfra inventory.py setup-zfs-and-lxd.py +``` diff --git a/files/haproxy.cfg b/files/haproxy.cfg new file mode 100644 index 0000000..e430f3c --- /dev/null +++ b/files/haproxy.cfg @@ -0,0 +1,89 @@ +global + log /dev/log local0 + log /dev/log local1 notice + chroot /var/lib/haproxy + stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners + stats timeout 30s + user haproxy + group haproxy + daemon + + # Default SSL material locations + ca-base /etc/ssl/certs + crt-base /etc/ssl/private + + ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/haproxy/dhparam + ssl-dh-param-file /etc/haproxy/dhparam + + +defaults + log global + mode http + option httplog + option dontlognull + timeout connect 5000 + timeout client 50000 + timeout server 50000 + errorfile 400 /etc/haproxy/errors/400.http + errorfile 403 /etc/haproxy/errors/403.http + errorfile 408 /etc/haproxy/errors/408.http + errorfile 500 /etc/haproxy/errors/500.http + errorfile 502 /etc/haproxy/errors/502.http + errorfile 503 /etc/haproxy/errors/503.http + errorfile 504 /etc/haproxy/errors/504.http + +frontend gitea-ssh + mode tcp + bind :22 + bind :::22 v6only + default_backend gitea-ssh + +backend gitea-ssh + mode tcp + server gitea 127.0.0.1:2222 check send-proxy + +frontend default + + bind :80 + bind :::80 v6only + bind :443 ssl crt /etc/ssl/haproxy/ strict-sni alpn h2,http/1.1 + bind :::443 v6only ssl crt /etc/ssl/haproxy/ strict-sni alpn h2,http/1.1 + + # HSTS (15768000 seconds = 6 months) + http-response set-header Strict-Transport-Security max-age=15768000 + reqadd X-Forwarded-Proto:\ https if { ssl_fc } + + # Let's Encrypt + acl letsencrypt path_dir -i /.well-known/acme-challenge + use_backend localhost if letsencrypt + + # mo-f.fr + acl mof hdr_end(host) -i mo-f.fr + use_backend mof if mof + + # play.benpro.fr + acl play hdr(host) -i play.benpro.fr + use_backend play if play + + #default_backend localhost + +backend localhost + option forwardfor + server localhost 127.0.0.1:8080 check send-proxy + +backend mof + # Benhind CloudFlare, X-Forwarded-For always setted, do not override + option forwardfor if-none + redirect scheme https if !{ ssl_fc } + server mof 127.0.0.1:8081 check + +backend play + option forwardfor + redirect scheme https if !{ ssl_fc } + server play 127.0.0.1:8096 check diff --git a/files/lxd.yml b/files/lxd.yml new file mode 100644 index 0000000..aacd0e8 --- /dev/null +++ b/files/lxd.yml @@ -0,0 +1,29 @@ +config: {} +networks: +- config: + ipv4.address: auto + ipv6.address: auto + description: "" + name: lxdbr0 + type: "" + project: default +storage_pools: +- config: + source: local + description: "" + name: default + driver: zfs +profiles: +- config: {} + description: "" + devices: + eth0: + name: eth0 + network: lxdbr0 + type: nic + root: + path: / + pool: default + type: disk + name: default +cluster: null diff --git a/files/nginx.default b/files/nginx.default new file mode 100644 index 0000000..a53a31f --- /dev/null +++ b/files/nginx.default @@ -0,0 +1,53 @@ +server { + listen 127.0.0.1:8080 default_server proxy_protocol; + set_real_ip_from 127.0.0.1; + real_ip_header proxy_protocol; + + # SSL configuration + # + # listen 443 ssl default_server; + # listen [::]:443 ssl default_server; + # + # Note: You should disable gzip for SSL traffic. + # See: https://bugs.debian.org/773332 + # + # Read up on ssl_ciphers to ensure a secure configuration. + # See: https://bugs.debian.org/765782 + # + # Self signed certs generated by the ssl-cert package + # Don't use them in a production server! + # + # include snippets/snakeoil.conf; + + root /var/www/html; + + # Add index.php to the list if you are using PHP + index index.html index.htm index.nginx-debian.html; + + server_name _; + + location / { + # First attempt to serve request as file, then + # as directory, then fall back to displaying a 404. + try_files $uri $uri/ =404; + } + + # pass PHP scripts to FastCGI server + # + #location ~ \.php$ { + # include snippets/fastcgi-php.conf; + # + # # With php-fpm (or other unix sockets): + # fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + # # With php-cgi (or other tcp sockets): + # fastcgi_pass 127.0.0.1:9000; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} + diff --git a/files/ondemand.service b/files/ondemand.service new file mode 100644 index 0000000..f832253 --- /dev/null +++ b/files/ondemand.service @@ -0,0 +1,14 @@ +[Unit] +Description=Set the CPU Frequency Scaling governor +ConditionVirtualization=no +ConditionPathExists=/sys/devices/system/cpu/online +# Don't run if we're going to start an Android LXC container on Ubuntu Touch +ConditionPathExists=!/etc/init/lxc-android-config.conf + +[Service] +Type=idle +ExecStart=/lib/systemd/set-cpufreq-performance + +[Install] +WantedBy=multi-user.target + diff --git a/files/set-cpufreq-performance b/files/set-cpufreq-performance new file mode 100644 index 0000000..375b38c --- /dev/null +++ b/files/set-cpufreq-performance @@ -0,0 +1,38 @@ +#! /bin/sh +# Set the CPU Frequency Scaling governor to "performance"/"powersave" where available +set -eu + +FIRSTCPU=`cut -f1 -d- /sys/devices/system/cpu/online` +AVAILABLE="/sys/devices/system/cpu/cpu$FIRSTCPU/cpufreq/scaling_available_governors" +DOWN_FACTOR="/sys/devices/system/cpu/cpufreq/performance/sampling_down_factor" + +[ -f $AVAILABLE ] || exit 0 + +read governors < $AVAILABLE +case $governors in + *performance*) + GOVERNOR="performance" + case $(uname -m) in + ppc64*) + SAMPLING=100 + ;; + esac + break + ;; + *) + exit 0 + ;; +esac + +[ -n "${GOVERNOR:-}" ] || exit 0 + +echo "Setting $GOVERNOR scheduler for all CPUs" + +for CPUFREQ in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +do + [ -f $CPUFREQ ] || continue + echo -n $GOVERNOR > $CPUFREQ +done +if [ -n "${SAMPLING:-}" ] && [ -f $DOWN_FACTOR ]; then + echo -n $SAMPLING > $DOWN_FACTOR +fi diff --git a/group_data/all.py b/group_data/all.py new file mode 100644 index 0000000..e69de29 diff --git a/inventory.py b/inventory.py new file mode 100644 index 0000000..2712441 --- /dev/null +++ b/inventory.py @@ -0,0 +1 @@ +my_hosts = ['lxd10.benpro.fr'] diff --git a/setup-base.py b/setup-base.py new file mode 100644 index 0000000..766bd16 --- /dev/null +++ b/setup-base.py @@ -0,0 +1,127 @@ +from pyinfra import host +from pyinfra.operations import apt, server, files, systemd + +SUDO = True + +server.user( + name='Add user benpro', + user='benpro', + groups=['sudo'], + public_keys='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFs7yO0auvwFL8HTLMUq6lET6DMYLhqhd32rqFfZUsjL openpgp:0xA32E99AD', + shell='/bin/bash', + present=True, +) + +server.hostname( + name='Set the hostname', + hostname='lxd10.benpro.fr', +) + +apt.update( + name='Update apt repositories', +) + +apt.upgrade( + name='Upgrade apt packages', +) + +apt.packages( + name='Install ufw', + packages=['ufw'], + update=False, +) + +server.shell( + name='Add ufw rules', + commands=['ufw limit 22', 'ufw limit 28', 'ufw allow 80', 'ufw allow 443'], +) + +server.shell( + name='Enable ufw', + commands=['yes | ufw enable'], +) + +files.line( + name='Set port 28 for SSH', + path='/etc/ssh/sshd_config', + line=r'Port .*', + replace='Port 28', +) + +systemd.service( + name='Reload sshd', + service='ssh.service', + reloaded=True, +) + +apt.packages( + name='Install packages', + packages=['zfsutils-linux', 'manpages', 'man', 'snapd', 'vim', 'file', 'parted', 'htop', 'ncdu', 'byobu', 'tcpdump', 'lm-sensors'], + update=False, +) + +if not host.fact.directory('/var/snap/lxd'): + server.shell( + name='Install lxd', + commands=['snap install lxd'], + ) + +if not host.fact.command('file -s /dev/sdc1 | grep swap || true'): + server.shell( + name='Create swap', + commands=['wipefs -a /dev/sdc1', 'mkswap /dev/sdc1'], + ) + +files.line( + name='Add swap to /etc/fstab', + path='/etc/fstab', + line='/dev/sdc1 none swap defaults 0 0', +) + +server.shell( + name='Enable swap', + commands=['swapon -a'], +) + +files.line( + name='Disable intel_pstate', + path='/etc/default/grub', + line='GRUB_CMDLINE_LINUX="intel_pstate=disable"', +) + +server.shell( + name='Reload grub', + commands=['update-grub'], +) + +files.put( + name='Install set-cpufreq-performance', + src='files/set-cpufreq-performance', + dest='/lib/systemd/set-cpufreq-performance', + user='root', + group='root', + mode='755', +) + +files.put( + name='Override systemd ondemand.service', + src='files/ondemand.service', + dest='/etc/systemd/system/ondemand.service', + user='root', + group='root', + mode='644', +) + +systemd.daemon_reload( + name='Reload systemd', + user_mode=False, +) + +systemd.service( + name='Restart and enable ondemand service', + service='ondemand.service', + running=True, + restarted=True, + enabled=True, +) + diff --git a/setup-haproxy.py b/setup-haproxy.py new file mode 100644 index 0000000..b020da1 --- /dev/null +++ b/setup-haproxy.py @@ -0,0 +1,88 @@ +from pyinfra import host +from pyinfra.operations import server, files, systemd, apt + +SUDO = True + +apt.packages( + name='Install packages', + packages=['certbot', 'haproxy', 'nginx'], + update=False, +) + +files.put( + name='Upload Nginx default vhost', + src='files/nginx.default', + dest='/etc/nginx/sites-available/default', + user='root', + group='root', + mode='644', +) + +systemd.service( + name='Restart and enable nginx service', + service='nginx.service', + running=True, + restarted=True, + enabled=True, +) + +files.put( + name='Upload HAProxy config', + src='files/haproxy.cfg', + dest='/etc/haproxy/haproxy.cfg', + user='root', + group='root', + mode='644', +) + +files.directory( + name='Ensure /etc/ssl/haproxy exists', + path='/etc/ssl/haproxy', + user='root', + group='root', + mode=700 +) + +if not host.fact.file('/etc/haproxy/dhparam'): + server.shell( + name='Generate dhparam', + commands=['openssl dhparam 2048 > /etc/haproxy/dhparam'] + ) + +systemd.service( + name='Restart and enable HAProxy service', + service='haproxy.service', + running=True, + restarted=True, + enabled=True, +) + +if not host.fact.directory('/etc/letsencrypt/live/mo-f.fr'): + server.shell( + name='Add certificate mo-f.fr', + commands=['certbot certonly --non-interactive --email certbot@benpro.fr --agree-tos --webroot --webroot-path /var/www/html/ -d mo-f.fr -d download.mo-f.fr -d ipv4.mo-f.fr -d oppai.mo-f.fr -d static-uploads.mo-f.fr -d www.mo-f.fr'], + ) + +if not host.fact.directory('/etc/letsencrypt/live/play.benpro.fr'): + server.shell( + name='Add certificate play.benpro.fr', + commands=['certbot certonly --non-interactive --email certbot@benpro.fr --agree-tos --webroot --webroot-path /var/www/html/ -d play.benpro.fr'], + ) + +if not host.fact.directory('/etc/letsencrypt/live/mo-f.fr'): + server.shell( + name='Add certificate mo-f.fr to HAProxy', + commands=['cat /etc/letsencrypt/live/mo-f.fr/fullchain.pem /etc/letsencrypt/live/mo-f.fr/privkey.pem > /etc/ssl/haproxy/mo-f.fr.pem'] + ) + +if not host.fact.directory('/etc/letsencrypt/live/play.benpro.fr'): + server.shell( + name='Add certificate play.benpro.fr to HAProxy', + commands=['cat /etc/letsencrypt/live/play.benpro.fr/fullchain.pem /etc/letsencrypt/live/play.benpro.fr/privkey.pem > /etc/ssl/haproxy/play.benpro.fr.pem'] + ) + +systemd.service( + name='Reload HAProxy service', + service='haproxy.service', + reloaded=True, +) diff --git a/setup-zfs-and-lxd.py b/setup-zfs-and-lxd.py new file mode 100644 index 0000000..a6dbbf1 --- /dev/null +++ b/setup-zfs-and-lxd.py @@ -0,0 +1,91 @@ +from pyinfra import host +from pyinfra.operations import server, files + +SUDO = True + +# This suppose you have: +# sda 8:0 0 2.7T 0 disk +# ├─sda1 8:1 0 512M 0 part +# │ └─md0 9:0 0 511M 0 raid1 /boot +# ├─sda2 8:2 0 40G 0 part +# │ └─md1 9:1 0 40G 0 raid1 / +# └─sda3 8:3 0 1M 0 part +# sdb 8:16 0 2.7T 0 disk +# ├─sdb1 8:17 0 512M 0 part +# │ └─md0 9:0 0 511M 0 raid1 /boot +# ├─sdb2 8:18 0 40G 0 part +# │ └─md1 9:1 0 40G 0 raid1 / +# └─sdb3 8:19 0 1M 0 part +# sdc 8:32 0 223.6G 0 disk +# └─sdc1 8:33 0 24G 0 part + +if not host.fact.command('lsblk | grep sda4 || true'): + server.shell( + name='Create sda4 for zpool', + commands=['sgdisk -n4:0:0 -t4:BF00 /dev/sda', 'partprobe'] + ) + +if not host.fact.command('lsblk | grep sdb4 || true'): + server.shell( + name='Create sdb4 for zpool', + commands=['sgdisk -n4:0:0 -t4:BF00 /dev/sdb', 'partprobe'] + ) + +if not host.fact.command('lsblk | grep sdc2 || true'): + server.shell( + name='Create sdc2 for ZFS cache L2ARC', + commands=['sgdisk -n2:0:0 -t2:FD00 /dev/sdc', 'partprobe'] + ) + +# zfs.key is not stored on GIT, but on KeePassXC +# When using new server be sure to set right disk ID +if not host.fact.command('zpool list local | grep local || true'): + server.shell( + name='Create ZFS pool', + commands=['zpool create -o ashift=12 -o autotrim=on -O encryption=aes-256-gcm -O keylocation=file:///etc/zfs.key -O keyformat=passphrase -O acltype=posixacl -O canmount=off -O dedup=on -O compression=lz4 -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa local mirror /dev/disk/by-id/ata-ST33000650NS_Z290FDG2-part4 /dev/disk/by-id/ata-ST33000650NS_Z290FEJQ-part4 cache /dev/disk/by-id/ata-INTEL_SSDSC2CW240A3_CVCV306301L3240CGN-part2'] + ) + +files.put( + name='Upload LXD config', + src='files/lxd.yml', + dest='/tmp/lxd.yml', + mode='644', +) + +if not host.fact.command('lxc storage list | grep local || true'): + server.shell( + name='Init LXD', + commands=['cat /tmp/lxd.yml | lxd init --preseed'] + ) + +if not host.fact.command('lxc storage volume list default | grep backups || true'): + server.shell( + name='Set LXD backups volumes', + commands=['lxc storage volume create default backups', 'lxc config set storage.backups_volume default/backups'] + ) + +if not host.fact.command('lxc storage volume list default | grep images || true'): + server.shell( + name='Set LXD images volumes', + commands=['lxc storage volume create default images', 'lxc config set storage.images_volume default/images'] + ) + +files.directory( + name='Ensure /var/backups/lxd exists', + path='/var/backups/lxd', + user='root', + group='root', + mode=700 +) + +if not host.fact.command('zfs list | grep exports || true'): + server.shell( + name='Create ZFS volume exports', + commands=['zfs create local/exports -o mountpoint=/var/backups/lxd'] + ) + +files.line( + name='Add info to motd', + path='/etc/motd', + line='`zfs load-key -a && systemctl start snap.lxd.daemon.service', +)