Compare commits

...

9 commits

39 changed files with 629 additions and 9 deletions

5
fotos.yaml Normal file
View file

@ -0,0 +1,5 @@
---
- hosts: fotos
roles:
- common
- photos

View file

@ -13,3 +13,6 @@ trusted_ranges:
- { v: ipv6, cidr: "fe80::/10" }
- { v: ipv6, cidr: "2a02:166b:92::/64" }
node_exporter: no
mqtt_internal_host: mqtt.bitlair.nl
mqtt_public_host: bitlair.nl

View file

@ -1 +0,0 @@
mqtt_internal_public_host: bitlair.nl

3
group_vars/www.yaml Normal file
View file

@ -0,0 +1,3 @@
acme_bootstrap_certs: yes
acme_san_domains:
- [ bitlair.nl, wiki.bitlair.nl, www.bitlair.nl ]

View file

@ -3,6 +3,9 @@ all:
raspi:
hosts:
bank-pi.bitlair.nl:
kvm:
hosts:
kvm3.bitlair.nl:
debian:
children:
bank:

View file

@ -0,0 +1,8 @@
---
- name: Configure auto-upgrades
template:
src: apt-minimal
dest: /etc/apt/apt.conf.d/20minimal
owner: root
group: root
mode: 0644

View file

@ -0,0 +1,28 @@
---
- name: Install source list
template:
src: stable-sources.list
dest: /etc/apt/sources.list
owner: root
group: root
mode: 0644
- name: Remove backports
file:
path: /etc/apt/sources.list.d/backports.list
state: absent
- name: update
apt:
update_cache: yes
- name: full-upgrade
apt:
upgrade: full
- name: Reboot
reboot:
- name: autoremove
apt:
autoremove: yes

View file

@ -1,4 +1,8 @@
---
- tags: [ debian-upgrade, never ]
import_tasks: debian-upgrade.yaml
when: ansible_facts['distribution_release'] != "bookworm"
- tags: debian_backports
import_tasks: debian-backports.yaml

View file

@ -0,0 +1,4 @@
# Managed by Ansible
APT::Install-Recommends "0";
APT::Install-Suggests "0";

View file

@ -0,0 +1,8 @@
deb http://deb.debian.org/debian bookworm main non-free-firmware
deb-src http://deb.debian.org/debian bookworm main non-free-firmware
deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware
deb-src http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main non-free-firmware

View file

@ -1,7 +1,7 @@
# Managed by Ansible
connection public-bridge
address {{ mqtt_internal_public_host }}
address {{ mqtt_public_host }}
topic bitlair/state out
topic bitlair/state/djo out
@ -11,3 +11,4 @@ topic bitlair/wifi/+/online out
topic bitlair/climate/# out
topic bitlair/humidity/+ out
topic bitlair/lasercutter/+ out
topic bitlair/photos out

View file

@ -1,7 +1,7 @@
loglevel: INFO
mqtt:
host: mqtt.bitlair.nl
host: {{ mqtt_internal_host }}
sounds:
directory: /opt/sounds

View file

@ -0,0 +1,3 @@
photos_mqtt_host: "{{ mqtt_internal_host }}"
photos_mqtt_topic: bitlair/photos
photos_path: /opt/wip

View file

@ -0,0 +1,12 @@
---
- name: restart photo-gallery
systemd:
name: photo-gallery
state: restarted
daemon_reload: true
- name: restart photos2mqtt
systemd:
name: photos2mqtt
state: restarted
daemon_reload: true

View file

@ -0,0 +1,6 @@
---
- tags: photos_gallery
import_tasks: photo-gallery.yaml
- tags: photos_mqtt
import_tasks: photos2mqtt.yaml

View file

@ -0,0 +1,24 @@
---
- name: Clone source
git:
repo: https://github.com/bitlair/photo-gallery.git
version: master
dest: /opt/photo-gallery
accept_hostkey: yes
notify: restart photo-gallery
- name: Install photo-gallery service file
template:
src: photo-gallery.service
dest: /etc/systemd/system/photo-gallery.service
owner: root
group: root
mode: 0644
notify: restart photo-gallery
- name: Start photo-gallery
systemd:
name: photo-gallery
state: started
enabled: yes
daemon_reload: true

View file

@ -0,0 +1,34 @@
---
- name: Install dependencies
apt:
name:
- make
- liblinux-inotify2-perl
- name: Install mqtt-simple
command: cpan Net::MQTT::Simple
- name: Install photos2mqtt
template:
src: photos2mqtt.pl
dest: /opt/photos2mqtt.pl
owner: root
group: root
mode: 0755
notify: restart photos2mqtt
- name: Install photos2mqtt service file
template:
src: photos2mqtt.service
dest: /etc/systemd/system/photos2mqtt.service
owner: root
group: root
mode: 0644
notify: restart photos2mqtt
- name: Start photos2mqtt
systemd:
name: photos2mqtt
state: started
enabled: yes
daemon_reload: true

View file

@ -0,0 +1,13 @@
# Managed by Ansible
[Unit]
Description=Gallery service
After=network.target
[Service]
ExecStart=/usr/bin/node /opt/photo-gallery/server.js
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,55 @@
#!/usr/bin/perl -w
# Managed by Ansible
use strict;
use Net::MQTT::Simple;
use Linux::Inotify2;
use POSIX qw(strftime);
use Time::HiRes qw(sleep time);
my $path = "{{ photos_path }}";
my $mqtt = Net::MQTT::Simple->new('{{ photos_mqtt_host }}');
my $inotify = new Linux::Inotify2 or die $!;
$inotify->blocking(0);
sub today {
return strftime "%Y%m%d", localtime;
}
sub watch_daydir {
my ($dn) = @_;
print "Watching $dn\n";
$inotify->watch($dn, IN_CREATE, sub {
my $event = shift;
$inotify->watch($event->fullname, IN_CLOSE_WRITE, sub {
my $event = shift;
my $fn = $event->fullname;
unless ($fn =~ m[^\.|/\.]) { # skip hidden files
print "New file written: $fn\n";
$mqtt->retain("{{ photos_mqtt_topic }}", $fn =~ s[^$path/][]r);
}
$event->w->cancel;
});
});
}
print "Watching $path\n";
$inotify->watch($path, IN_CREATE, sub {
my $event = shift;
my $dn = $event->fullname;
-d $dn or next;
watch_daydir($dn);
});
watch_daydir("$path/" . today());
while (1) {
$mqtt->tick(.05);
$inotify->poll;
sleep .1;
}

View file

@ -0,0 +1,16 @@
# Managed by Ansible
[Unit]
Description=Photos to MQTT
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10s
ExecStart=/usr/bin/perl /opt/photos2mqtt.pl
User=wip
[Install]
WantedBy=multi-user.target

View file

@ -13,6 +13,12 @@
state: restarted
daemon_reload: true
- name: restart irc-photos
systemd:
name: irc-photos
state: restarted
daemon_reload: true
- name: restart discord-bot
systemd:
name: discord-bot

View file

@ -4,7 +4,17 @@
name:
- python3-paho-mqtt
- python3-tz
# Not in apt, install manually: discord.py, discord_webhook
- virtualenv
- name: Create virtualenv
command: virtualenv /opt/miflora_exporter/.venv
args:
creates: /var/lib/discord-bot/.venv
- name: Install Python dependencies
shell: . .venv/bin/activate && pip install -r requirements.txt
args:
chdir: /var/lib/discord-bot
- name: Clone source
git:

View file

@ -28,3 +28,33 @@
state: started
enabled: yes
daemon_reload: true
- name: Create helpers dir
file:
path: /var/lib/irc-helpers
state: directory
- name: Install photos notification
template:
src: irc-photos.sh
dest: /var/lib/irc-helpers/photos.sh
owner: root
group: root
mode: 0755
notify: restart irc-photos
- name: Install photos notification service
template:
src: irc-photos.service
dest: /etc/systemd/system/irc-photos.service
owner: root
group: root
mode: 0644
notify: restart irc-photos
- name: Start irc-photos
systemd:
name: irc-photos
state: started
enabled: yes
daemon_reload: true

View file

@ -1,10 +1,14 @@
---
- name: Install mqtt-simple
command: cpan Net::MQTT::Simple
- name: Install dependencies
apt:
name: [ php-cli, php-snmp ]
name:
- php-cli
- php-snmp
- make
- name: Install mqtt-simple
command: cpan Net::MQTT::Simple
- name: Add user
user:

View file

@ -8,8 +8,10 @@ After=network.target
Type=simple
Restart=on-failure
RestartSec=10s
ExecStart=/var/lib/discord-bot/main.py
ExecStart=/var/lib/discord-bot/.venv/bin/python /var/lib/discord-bot/main.py
DynamicUser=true
Environment="MQTT_HOST={{ mqtt_internal_host }}"
Environment="DISCORD_WEBHOOK_URL={{ discord_webhook_url }}"
Environment="DISCORD_TOKEN={{ discord_token }}"
[Install]

View file

@ -0,0 +1,16 @@
# Managed by Ansible
[Unit]
Description=Bitlair IRC photos notification
After=network.target
Requires=irc-bot.service
[Service]
Type=simple
ExecStart=/bin/bash /var/lib/irc-helpers/photos.sh
Restart=on-failure
RestartSec=10s
DynamicUser=true
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,13 @@
#!/bin/basho
# Managed by Ansible
set -eu
set -o pipefail
mqtt-simple -h {{ mqtt_internal_host }} -s "bitlair/photos" |
while read event; do
path=$(echo $event | cut -d ' ' -f 2)
url="https://bitlair.nl/fotos/view/$path"
irc-say "WIP: $url"
done

View file

@ -1,4 +1,4 @@
mqtt_server = 'mqtt.bitlair.nl'
mqtt_server = '{{ mqtt_internal_host }}'
mqtt_port = 1883
spacestate_topic = 'bitlair/state'

View file

@ -0,0 +1,14 @@
---
- import_tasks: ../../common/handlers/main.yaml
- name: restart spaceapi
systemd:
name: spaceapi
state: restarted
daemon_reload: true
- name: restart mqtt2web
systemd:
name: mqtt2web
state: restarted
daemon_reload: true

View file

@ -0,0 +1,24 @@
---
- name: Install dependencies
apt:
name: [ python3-requests, python3-icalendar ]
- name: Clone source
git:
repo: https://github.com/bitlair/calendar-parser.git
version: main
dest: /usr/local/src/bitlair-calendar
accept_hostkey: yes
- name: Create user
user:
name: bitlair-calendar
home: /var/lib/bitlair-calendar
- name: Install cronjob
template:
src: calendar.cron
dest: /etc/cron.d/bitlair-calendar
owner: root
group: root
mode: 0644

12
roles/www/tasks/main.yaml Normal file
View file

@ -0,0 +1,12 @@
---
- tags: www_calendar
import_tasks: calendar.yaml
- tags: www_mediawiki
include_tasks: mediawiki.yaml
- tags: www_mqtt
include_tasks: mqtt.yaml
- tags: www_spaceapi
include_tasks: spaceapi.yaml

View file

@ -0,0 +1,21 @@
---
- name: Install dependencies
apt:
name:
- php-fpm
- name: Allow HTTP/HTTPS
iptables:
chain: INPUT
protocol: tcp
destination_port: "{{ item.port }}"
ctstate: NEW
jump: ACCEPT
ip_version: "{{ item.ip }}"
action: insert
with_items:
- { ip: ipv4, port: 80 }
- { ip: ipv4, port: 443 }
- { ip: ipv6, port: 80 }
- { ip: ipv6, port: 443 }
notify: persist iptables

45
roles/www/tasks/mqtt.yaml Normal file
View file

@ -0,0 +1,45 @@
---
- name: Install Mosquitto
apt:
name: mosquitto
- name: Allow MQTT
iptables:
chain: INPUT
protocol: tcp
destination_port: "{{ item.port }}"
ctstate: NEW
jump: ACCEPT
ip_version: "{{ item.ip }}"
action: insert
with_items:
- { ip: ipv4, port: 1883 }
- { ip: ipv6, port: 1883 }
notify: persist iptables
- name: Install mqtt-simple
command: cpan Net::MQTT::Simple
- name: Clone mqtt2web source
git:
repo: https://github.com/bitlair/mqtt2web.git
version: master
dest: /opt/mqtt2web
accept_hostkey: yes
notify: restart mqtt2web
- name: Install mqtt2web service file
template:
src: mqtt2web.service
dest: /etc/systemd/system/mqtt2web.service
owner: root
group: root
mode: 0644
notify: restart mqtt2web
- name: Enable mqtt2web
systemd:
name: mqtt2web
state: started
enabled: true
daemon_reload: true

View file

@ -0,0 +1,24 @@
---
- name: Clone spaceapi source
git:
repo: https://github.com/bitlair/spaceapi.git
version: master
dest: /opt/spaceapi
accept_hostkey: yes
notify: restart spaceapi
- name: Install spaceapi service file
template:
src: spaceapi.service
dest: /etc/systemd/system/spaceapi.service
owner: root
group: root
mode: 0644
notify: restart spaceapi
- name: Enable spaceapi
systemd:
name: spaceapi
state: started
enabled: true
daemon_reload: true

View file

@ -0,0 +1,6 @@
# Managed by Ansible
SHELL=/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
42 * * * * bitlair-calendar /usr/local/src/bitlair-calendar/calendarparser.py /var/lib/bitlair-calendar/events.ics

View file

@ -0,0 +1,3 @@
{
"m.server": "matrix.bitlair.nl"
}

View file

@ -0,0 +1,15 @@
# Managed by Ansible
[Unit]
Description=MQTT to Web
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10s
ExecStart=/usr/bin/perl /opt/mqtt2web/mqtt2web.pl
DynamicUser=true
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,131 @@
# Managed by Ansible
server {
listen 80 default_server;
listen 443 ssl default_server;
listen [::]:80 default_server;
listen [::]:443 ssl default_server;
server_name bitlair.nl wiki.bitlair.nl www.bitlair.nl;
root /opt/bitlair-wiki/;
{% if acme_bootstrap_certs %}
include "snippets/snakeoil.conf";
{% else %}
ssl_certificate "/var/lib/dehydrated/certs/{{ www_domain }}/fullchain.pem";
ssl_certificate_key "/var/lib/dehydrated/certs/{{ www_domain }}/privkey.pem";
{% endif %}
# SSL settings from https://cipherli.st/ - AK47 15 jan 2017
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
client_max_body_size 32m;
client_body_timeout 60;
index index.php;
# mqtt2web
location = /mqtt {
proxy_pass http://localhost:8080/mqtt;
include proxy_params;
proxy_buffering off;
proxy_cache off;
proxy_http_version 1.1;
proxy_set_header Connection '';
chunked_transfer_encoding off;
}
# Space API
location = /statejson {
proxy_pass http://localhost:8888;
include proxy_params;
add_header 'Access-Control-Allow-Origin' '*';
}
# Photo gallery
location = /fotos {
return 302 $scheme://bitlair.nl/fotos/;
}
location ~* ^/fotos/(.*)$ {
proxy_pass http://192.168.88.22:4567/$1$is_args$args;
}
location ~ ^/state/(.+)$ {
alias /opt/spaceapi/assets/$1;
}
location = /events.ics {
alias /var/lib/bitlair-calendar/events.ics;
}
location ~ ^/(cache|maintenance|vendor|extensions)/ {
deny all;
}
location = /api.php {
deny all;
}
# Legacy space API stuff.
location ~ ^/(putconfig|putjson|putstate|state|statejson)\.php$ {
root "/opt/legacy/";
fastcgi_pass unix:/run/php/php-fpm.sock;
include fastcgi.conf;
}
location ~ ^/(bitlair.svg|bitlair_closed.png|bitlair_open.png|state|statejson)$ {
root "/opt/legacy/";
}
location ~ ^/wp-content {
root "/opt/legacy/";
}
location = /statejson.php {
rewrite ^.+$ /statejson;
}
# Mediawiki
location / {
try_files $uri $uri/ @rewrite;
}
location ~ \.php$ {
try_files $uri @rewrite;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?title=$1$args;
}
location ~ \.(png|css|ico|pdf|flv|jpe?g|gif|js|css)$ {
try_files $uri @rewrite;
expires 1M;
}
location = /_.gif {
expires max;
empty_gif;
}
# Legacy: redirect old prefix.
location /Pages/ {
rewrite ^/Pages/(.*) https://$server_name/$1$args redirect;
}
# Matrix realm delegation
location = /.well-known/matrix/server {
add_header "Content-Type" "application/json";
add_header "Access-Control-Allow-Origin" "*";
alias /opt/matrix-delegation.json;
}
include "snippets/acme.conf";
}

View file

@ -0,0 +1,15 @@
# Managed by Ansible
[Unit]
Description=Space API
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10s
ExecStart=/usr/bin/python3 /opt/spaceapi/server.py
DynamicUser=true
[Install]
WantedBy=multi-user.target