Compare commits

..

9 commits

Author SHA1 Message Date
cdf79c2bd8
wip 2023-08-01 17:13:41 +02:00
13e52027cf
wip 2023-08-01 17:13:41 +02:00
96c2df1c09
wip 2023-08-01 17:13:41 +02:00
cadb32cffd
wip 2023-08-01 17:13:41 +02:00
8b296ba6db
wip 2023-08-01 17:13:41 +02:00
b1ea126c2a
wip 2023-08-01 17:13:41 +02:00
1bf795c262
wip 2023-08-01 17:13:41 +02:00
3546633969
wip 2023-08-01 17:13:41 +02:00
f8f500718b
wip 2023-08-01 17:13:41 +02:00
119 changed files with 724 additions and 1895 deletions

2
.envrc
View file

@ -1,7 +1,5 @@
#!/usr/bin/env bash
PATH_add bin
source_env ~/.local/share/direnv/pyenv
source_env ~/.local/share/direnv/venv
source_env ~/.local/share/direnv/bundlewrap

View file

@ -37,12 +37,3 @@ fi
telegraf: execd for daemons
TEST
# git signing
git config --global gpg.format ssh
git config --global commit.gpgsign true
git config user.name CroneKorkN
git config user.email i@ckn.li
git config user.signingkey "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILMVroYmswD4tLk6iH+2tvQiyaMe42yfONDsPDIdFv6I"

195
bin/dnssec Executable file
View file

@ -0,0 +1,195 @@
#!/usr/bin/env python3
# https://medium.com/iocscan/how-dnssec-works-9c652257be0
# https://de.wikipedia.org/wiki/RRSIG_Resource_Record
# https://metebalci.com/blog/a-minimum-complete-tutorial-of-dnssec/
# https://bind9.readthedocs.io/en/latest/dnssec-guide.html
from sys import argv
from os.path import realpath, dirname
from bundlewrap.repo import Repository
from base64 import b64decode, urlsafe_b64encode
from cryptography.utils import int_to_bytes
from cryptography.hazmat.primitives import serialization as crypto_serialization
from struct import pack, unpack
from hashlib import sha1, sha256
from json import dumps
from cache_to_disk import cache_to_disk
def long_to_base64(n):
return urlsafe_b64encode(int_to_bytes(n, None)).decode()
zone = argv[1]
repo = Repository(dirname(dirname(realpath(__file__))))
flags = 256
protocol = 3
algorithm = 8
algorithm_name = 'RSASHA256'
# ZSK/KSK DNSKEY
#
# https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers
# https://crypto.stackexchange.com/a/21104
def generate_signing_key_pair(zone, salt):
privkey = repo.libs.rsa.generate_deterministic_rsa_private_key(
b64decode(str(repo.vault.random_bytes_as_base64_for(f'dnssec {salt} ' + zone)))
)
public_exponent = privkey.private_numbers().public_numbers.e
modulo = privkey.private_numbers().public_numbers.n
private_exponent = privkey.private_numbers().d
prime1 = privkey.private_numbers().p
prime2 = privkey.private_numbers().q
exponent1 = privkey.private_numbers().dmp1
exponent2 = privkey.private_numbers().dmq1
coefficient = privkey.private_numbers().iqmp
dnskey = ''.join(privkey.public_key().public_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PublicFormat.SubjectPublicKeyInfo
).decode().split('\n')[1:-2])
return {
'dnskey': dnskey,
'dnskey_record': f'{zone}. IN DNSKEY {flags} {protocol} {algorithm} {dnskey}',
'privkey': privkey,
'privkey_file': {
'Private-key-format': 'v1.3',
'Algorithm': f'{algorithm} ({algorithm_name})',
'Modulus': long_to_base64(modulo),
'PublicExponent': long_to_base64(public_exponent),
'PrivateExponent': long_to_base64(private_exponent),
'Prime1': long_to_base64(prime1),
'Prime2': long_to_base64(prime2),
'Exponent1': long_to_base64(exponent1),
'Exponent2': long_to_base64(exponent2),
'Coefficient': long_to_base64(coefficient),
'Created': 20230428110109,
'Publish': 20230428110109,
'Activate': 20230428110109,
},
}
# DS
#
# https://gist.github.com/wido/4c6288b2f5ba6d16fce37dca3fc2cb4a#file-dnskey_to_dsrecord-py-L40
def _calc_ds(zone, flags, protocol, algorithm, dnskey):
if zone.endswith('.') is False:
zone += '.'
signature = bytes()
for i in zone.split('.'):
signature += pack('B', len(i)) + i.encode()
signature += pack('!HBB', int(flags), int(protocol), int(algorithm))
signature += b64decode(dnskey)
return {
'sha1': sha1(signature).hexdigest().upper(),
'sha256': sha256(signature).hexdigest().upper(),
}
def _calc_keyid(flags, protocol, algorithm, dnskey):
st = pack('!HBB', int(flags), int(protocol), int(algorithm))
st += b64decode(dnskey)
cnt = 0
for idx in range(len(st)):
s = unpack('B', st[idx:idx+1])[0]
if (idx % 2) == 0:
cnt += s << 8
else:
cnt += s
return ((cnt & 0xFFFF) + (cnt >> 16)) & 0xFFFF
def dnskey_to_ds(zone, flags, protocol, algorithm, dnskey):
keyid = _calc_keyid(flags, protocol, algorithm, dnskey)
ds = _calc_ds(zone, flags, protocol, algorithm, dnskey)
return[
f"{zone}. IN DS {str(keyid)} {str(algorithm)} 1 {ds['sha1'].lower()}",
f"{zone}. IN DS {str(keyid)} {str(algorithm)} 2 {ds['sha256'].lower()}",
]
# Result
#@cache_to_disk(30)
def generate_dnssec_for_zone(zone):
zsk_data = generate_signing_key_pair(zone, salt='zsk')
ksk_data = generate_signing_key_pair(zone, salt='ksk')
ds_records = dnskey_to_ds(zone, flags, protocol, algorithm, ksk_data['dnskey'])
return {
'zsk_data': zsk_data,
'ksk_data': ksk_data,
'ds_records': ds_records,
}
print(
generate_dnssec_for_zone(zone),
)
# #########################
# from dns import rrset, rdatatype, rdata
# from dns.rdataclass import IN
# from dns.dnssec import sign, make_dnskey
# from dns.name import Name
# from dns.rdtypes.IN.A import A
# data = generate_dnssec_for_zone(zone)
# zone_name = Name(f'{zone}.'.split('.'))
# assert zone_name.is_absolute()
# # rrset = rrset.from_text_list(
# # name=Name(['test']).derelativize(zone_name),
# # origin=zone_name,
# # relativize=False,
# # ttl=60,
# # rdclass=IN,
# # rdtype=rdatatype.from_text('A'),
# # text_rdatas=[
# # '100.2.3.4',
# # '10.0.0.55',
# # ],
# # )
# rrset = rrset.from_rdata_list(
# name=Name(['test']).derelativize(zone_name),
# ttl=60,
# rdatas=[
# rdata.from_text(
# rdclass=IN,
# rdtype=rdatatype.from_text('A'),
# origin=zone_name,
# tok='1.2.3.4',
# relativize=False,
# ),
# A(IN, rdatatype.from_text('A'), '10.20.30.40')
# ],
# )
# # for e in rrset:
# # print(e.is_absolute())
# dnskey = make_dnskey(
# public_key=data['zsk_data']['privkey'].public_key(),
# algorithm=algorithm,
# flags=flags,
# protocol=protocol,
# )
# sign(
# rrset=rrset,
# private_key=data['zsk_data']['privkey'],
# signer=Name(f'{zone}.'),
# dnskey=dnskey,
# lifetime=99999,
# )

47
bin/test Executable file
View file

@ -0,0 +1,47 @@
import dns.zone
import dns.rdatatype
import dns.rdataclass
import dns.dnssec
# Define the zone name and domain names
zone_name = 'example.com.'
a_name = 'www.example.com.'
txt_name = 'example.com.'
mx_name = 'example.com.'
# Define the DNSKEY algorithm and size
algorithm = 8
key_size = 2048
# Generate the DNSSEC key pair
keypair = dns.dnssec.make_dnskey(algorithm, key_size)
# Create the zone
zone = dns.zone.Zone(origin=zone_name)
# Add A record to zone
a_rrset = zone.get_rdataset(a_name, rdtype=dns.rdatatype.A, create=True)
a_rrset.add(dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1')
# Add TXT record to zone
txt_rrset = zone.get_rdataset(txt_name, rdtype=dns.rdatatype.TXT, create=True)
txt_rrset.add(dns.rdataclass.IN, dns.rdatatype.TXT, 'Hello, world!')
# Add MX record to zone
mx_rrset = zone.get_rdataset(mx_name, rdtype=dns.rdatatype.MX, create=True)
mx_rrset.add(dns.rdataclass.IN, dns.rdatatype.MX, '10 mail.example.com.')
# Create the DNSKEY record for the zone
key_name = f'{keypair.name}-K{keypair.fingerprint()}'
dnskey_rrset = dns.rrset.RRset(name=keypair.name, rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.DNSKEY)
dnskey_rrset.ttl = 86400
dnskey_rrset.add(dns.rdataclass.IN, dns.rdatatype.DNSKEY, keypair.key, key_name=key_name)
# Add the DNSKEY record to the zone
zone.replace_rdataset(keypair.name, dnskey_rrset)
# Sign the zone with the DNSSEC key pair
dns.dnssec.sign_zone(zone, keypair, inception=0, expiration=3600)
# Print the resulting zone with the RRSIG records
print(zone.to_text())

View file

@ -10,6 +10,7 @@ nodes = [
for node in sorted(repo.nodes_in_group('debian'))
if not node.dummy
]
reboot_nodes = []
print('updating nodes:', sorted(node.name for node in nodes))
@ -23,13 +24,14 @@ for node in nodes:
print(node.run('DEBIAN_FRONTEND=noninteractive apt update').stdout.decode())
print(node.run('DEBIAN_FRONTEND=noninteractive apt list --upgradable').stdout.decode())
if int(node.run('DEBIAN_FRONTEND=noninteractive apt list --upgradable 2> /dev/null | grep upgradable | wc -l').stdout.decode()):
print(node.run('DEBIAN_FRONTEND=noninteractive apt -qy full-upgrade').stdout.decode())
print(node.run('DEBIAN_FRONTEND=noninteractive apt -y dist-upgrade').stdout.decode())
reboot_nodes.append(node)
# REBOOT IN ORDER
wireguard_servers = [
node
for node in nodes
for node in reboot_nodes
if node.has_bundle('wireguard')
and (
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen <
@ -39,7 +41,7 @@ wireguard_servers = [
wireguard_s2s = [
node
for node in nodes
for node in reboot_nodes
if node.has_bundle('wireguard')
and (
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen ==
@ -49,7 +51,7 @@ wireguard_s2s = [
everything_else = [
node
for node in nodes
for node in reboot_nodes
if not node.has_bundle('wireguard')
]
@ -60,11 +62,8 @@ for node in [
*wireguard_s2s,
*wireguard_servers,
]:
print('rebooting', node.name)
try:
if node.run('test -e /var/run/reboot-required', may_fail=True).return_code == 0:
print('rebooting', node.name)
print(node.run('systemctl reboot').stdout.decode())
else:
print('not rebooting', node.name)
print(node.run('systemctl reboot').stdout.decode())
except Exception as e:
print(e)

View file

@ -5,17 +5,9 @@ from os.path import realpath, dirname
from sys import argv
from ipaddress import ip_network, ip_interface
if len(argv) != 3:
print(f'usage: {argv[0]} <node> <client>')
exit(1)
repo = Repository(dirname(dirname(realpath(__file__))))
server_node = repo.get_node(argv[1])
if argv[2] not in server_node.metadata.get('wireguard/clients'):
print(f'client {argv[2]} not found in: {server_node.metadata.get("wireguard/clients").keys()}')
exit(1)
data = server_node.metadata.get(f'wireguard/clients/{argv[2]}')
vpn_network = ip_interface(server_node.metadata.get('wireguard/my_ip')).network
@ -28,7 +20,9 @@ for peer in server_node.metadata.get('wireguard/s2s').values():
if not ip_network(network).subnet_of(vpn_network):
allowed_ips.append(ip_network(network))
conf = f'''
conf = \
f'''>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[Interface]
PrivateKey = {repo.libs.wireguard.privkey(data['peer_id'])}
ListenPort = 51820
@ -41,12 +35,11 @@ PresharedKey = {repo.libs.wireguard.psk(data['peer_id'], server_node.metadata.ge
AllowedIPs = {', '.join(str(client_route) for client_route in sorted(allowed_ips))}
Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:51820
PersistentKeepalive = 10
'''
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'''
print(conf)
print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
if input("print qrcode? [Yn]: ").upper() in ['', 'Y']:
if input("print qrcode? [yN]: ").upper() == 'Y':
import pyqrcode
print(pyqrcode.create(conf).terminal(quiet_zone=1))

View file

@ -23,12 +23,12 @@ directories = {
'action:apt_update',
},
},
# '/etc/apt/listchanges.conf.d': {
# 'purge': True,
# 'triggers': {
# 'action:apt_update',
# },
# },
'/etc/apt/listchanges.conf.d': {
'purge': True,
'triggers': {
'action:apt_update',
},
},
'/etc/apt/preferences.d': {
'purge': True,
'triggers': {
@ -50,15 +50,9 @@ files = {
'action:apt_update',
},
},
'/etc/apt/sources.list': {
'content': '# managed by bundlewrap\n',
'triggers': {
'action:apt_update',
},
'/etc/apt/listchanges.conf': {
'content': repo.libs.ini.dumps(node.metadata.get('apt/list_changes')),
},
# '/etc/apt/listchanges.conf': {
# 'content': repo.libs.ini.dumps(node.metadata.get('apt/list_changes')),
# },
'/usr/lib/nagios/plugins/check_apt_upgradable': {
'mode': '0755',
},
@ -66,7 +60,7 @@ files = {
actions = {
'apt_update': {
'command': 'apt-get update',
'command': 'apt-get update -o APT::Update::Error-Mode=any',
'needed_by': {
'pkg_apt:',
},

View file

@ -1,24 +1,13 @@
defaults = {
'apt': {
'packages': {
'apt-listchanges': {
'installed': False,
},
},
'config': {
'DPkg': {
'Pre-Install-Pkgs': {
'/usr/sbin/dpkg-preconfigure --apt || true',
},
'Post-Invoke': {
# keep package cache empty
'/bin/rm -f /var/cache/apt/archives/*.deb || true',
},
'Options': {
# https://unix.stackexchange.com/a/642541/357916
'--force-confold',
'--force-confdef',
},
},
'APT': {
'NeverAutoRemove': {
@ -40,13 +29,7 @@ defaults = {
'metapackages',
'tasks',
},
'Move-Autobit-Sections': {
'oldlibs',
},
'Update': {
# https://unix.stackexchange.com/a/653377/357916
'Error-Mode': 'any',
},
'Move-Autobit-Sections': 'oldlibs',
},
},
'sources': {},
@ -133,45 +116,45 @@ def unattended_upgrades(metadata):
}
# @metadata_reactor.provides(
# 'apt/config',
# 'apt/list_changes',
# )
# def listchanges(metadata):
# return {
# 'apt': {
# 'config': {
# 'DPkg': {
# 'Pre-Install-Pkgs': {
# '/usr/bin/apt-listchanges --apt || test $? -lt 10',
# },
# 'Tools': {
# 'Options': {
# '/usr/bin/apt-listchanges': {
# 'Version': '2',
# 'InfoFD': '20',
# },
# },
# },
# },
# 'Dir': {
# 'Etc': {
# 'apt-listchanges-main': 'listchanges.conf',
# 'apt-listchanges-parts': 'listchanges.conf.d',
# },
# },
# },
# 'list_changes': {
# 'apt': {
# 'frontend': 'pager',
# 'which': 'news',
# 'email_address': 'root',
# 'email_format': 'text',
# 'confirm': 'false',
# 'headers': 'false',
# 'reverse': 'false',
# 'save_seen': '/var/lib/apt/listchanges.db',
# },
# },
# },
# }
@metadata_reactor.provides(
'apt/config',
'apt/list_changes',
)
def listchanges(metadata):
return {
'apt': {
'config': {
'DPkg': {
'Pre-Install-Pkgs': {
'/usr/bin/apt-listchanges --apt || test $? -lt 10',
},
},
'Tools': {
'Options': {
'/usr/bin/apt-listchanges': {
'Version': '2',
'InfoFD': '20',
},
},
},
'Dir': {
'Etc': {
'apt-listchanges-main': 'listchanges.conf',
'apt-listchanges-parts': 'listchanges.conf.d',
},
},
},
'list_changes': {
'apt': {
'frontend': 'pager',
'which': 'news',
'email_address': 'root',
'email_format': 'text',
'confirm': 'false',
'headers': 'false',
'reverse': 'false',
'save_seen': '/var/lib/apt/listchanges.db',
},
},
},
}

View file

@ -36,7 +36,7 @@ for dataset in config['datasets']:
if snapshot_datetime < two_days_ago:
days_ago = (now - snapshot_datetime).days
errors.add(f'dataset "{dataset}" has not been backed up for {days_ago} days')
errors.add(f'dataset "{dataset}" has no backups sind {days_ago} days')
continue
if errors:

View file

@ -25,8 +25,7 @@ def backup_freshness_check(metadata):
'datasets': {
f"{other_node.metadata.get('id')}/{dataset}"
for other_node in repo.nodes
if not other_node.dummy
and other_node.has_bundle('backup')
if other_node.has_bundle('backup')
and other_node.has_bundle('zfs')
and other_node.metadata.get('backup/server') == metadata.get('backup-freshness-check/server')
for dataset, options in other_node.metadata.get('zfs/datasets').items()

View file

@ -35,7 +35,6 @@ def zfs(metadata):
for other_node in repo.nodes:
if (
not other_node.dummy and
other_node.has_bundle('backup') and
other_node.metadata.get('backup/server') == node.name
):

View file

@ -1,31 +1,13 @@
#!/bin/bash
set -u
set -exu
# FIXME: inelegant
% if wol_command:
${wol_command}
% endif
exit=0
failed_paths=""
for path in $(jq -r '.paths | .[]' < /etc/backup/config.json)
do
echo backing up $path
/opt/backup/backup_path "$path"
# set exit to 1 if any backup fails
if [ $? -ne 0 ]
then
echo ERROR: backing up $path failed >&2
exit=5
failed_paths="$failed_paths $path"
fi
done
if [ $exit -ne 0 ]
then
echo "ERROR: failed to backup paths: $failed_paths" >&2
fi
exit $exit

View file

@ -1,6 +1,6 @@
#!/bin/bash
set -eu
set -exu
path=$1
uuid=$(jq -r .client_uuid < /etc/backup/config.json)

29
bundles/bind/README.md Normal file
View file

@ -0,0 +1,29 @@
## DNSSEC
https://wiki.debian.org/DNSSEC%20Howto%20for%20BIND%209.9+#The_signing_part
https://blog.apnic.net/2021/11/02/dnssec-provisioning-automation-with-cds-cdnskey-in-the-real-world/
https://gist.github.com/wido/4c6288b2f5ba6d16fce37dca3fc2cb4a
```python
import dns.dnssec
algorithm = dns.dnssec.RSASHA256
```
```python
import cryptography
pk = cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key(key_size=2048, public_exponent=65537)
```
## Nomenclature
### parent
DNSKEY:
the public key
DS
### sub
ZSK/KSK:
https://www.cloudflare.com/de-de/dns/dnssec/how-dnssec-works/

View file

@ -19,7 +19,7 @@ directories[f'/var/lib/bind'] = {
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -29,7 +29,7 @@ files['/etc/default/bind9'] = {
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -43,7 +43,7 @@ files['/etc/bind/named.conf'] = {
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -63,7 +63,7 @@ files['/etc/bind/named.conf.options'] = {
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -93,7 +93,7 @@ files['/etc/bind/named.conf.local'] = {
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -106,7 +106,7 @@ for view_name, view_conf in master_node.metadata.get('bind/views').items():
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -127,7 +127,7 @@ for view_name, view_conf in master_node.metadata.get('bind/views').items():
'svc_systemd:bind9',
],
'triggers': [
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
],
}
@ -139,6 +139,6 @@ actions['named-checkconf'] = {
'unless': 'named-checkconf -z',
'needs': [
'svc_systemd:bind9',
'svc_systemd:bind9:reload',
'svc_systemd:bind9:restart',
]
}

View file

@ -1,10 +1,6 @@
from shlex import quote
defaults = {
'build-ci': {},
}
@metadata_reactor.provides(
'users/build-ci/authorized_users',
'sudoers/build-ci',
@ -22,7 +18,7 @@ def ssh_keys(metadata):
},
'sudoers': {
'build-ci': {
f"/usr/bin/chown -R build-ci\\:{quote(ci['group'])} {quote(ci['path'])}"
f"/usr/bin/chown -R build-ci\:{quote(ci['group'])} {quote(ci['path'])}"
for ci in metadata.get('build-ci').values()
}
},

View file

@ -9,7 +9,7 @@ defaults = {
'crystal': {
# https://software.opensuse.org/download.html?project=devel%3Alanguages%3Acrystal&package=crystal
'urls': {
'http://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_Testing/',
'https://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_Testing/',
},
'suites': {
'/',

View file

@ -6,7 +6,7 @@ ssl_cert = </var/lib/dehydrated/certs/${node.metadata.get('mailserver/hostname')
ssl_key = </var/lib/dehydrated/certs/${node.metadata.get('mailserver/hostname')}/privkey.pem
ssl_dh = </etc/dovecot/dhparam.pem
ssl_client_ca_dir = /etc/ssl/certs
mail_location = maildir:${node.metadata.get('mailserver/maildir')}/%u:INDEX=${node.metadata.get('mailserver/maildir')}/index/%u
mail_location = maildir:~
mail_plugins = fts fts_xapian
namespace inbox {

View file

@ -20,10 +20,6 @@ directories = {
'owner': 'vmail',
'group': 'vmail',
},
'/var/vmail/index': {
'owner': 'vmail',
'group': 'vmail',
},
'/var/vmail/sieve': {
'owner': 'vmail',
'group': 'vmail',

View file

@ -0,0 +1,6 @@
# directories = {
# '/var/lib/downloads': {
# 'owner': 'downloads',
# 'group': 'www-data',
# }
# }

View file

@ -1,23 +0,0 @@
Pg Pass workaround: set manually:
```
root@freescout /ro psql freescout
psql (15.6 (Debian 15.6-0+deb12u1))
Type "help" for help.
freescout=# \password freescout
Enter new password for user "freescout":
Enter it again:
freescout=#
\q
```
# problems
# check if /opt/freescout/.env is resettet
# ckeck `psql -h localhost -d freescout -U freescout -W`with pw from .env
# chown -R www-data:www-data /opt/freescout
# sudo su - www-data -c 'php /opt/freescout/artisan freescout:clear-cache' -s /bin/bash
# javascript funny? `sudo su - www-data -c 'php /opt/freescout/artisan storage:link' -s /bin/bash`
# benutzer bilder weg? aus dem backup holen: `/opt/freescout/.zfs/snapshot/zfs-auto-snap_hourly-2024-11-22-1700/storage/app/public/users` `./customers`

View file

@ -1,66 +0,0 @@
# https://github.com/freescout-helpdesk/freescout/wiki/Installation-Guide
run_as = repo.libs.tools.run_as
php_version = node.metadata.get('php/version')
directories = {
'/opt/freescout': {
'owner': 'www-data',
'group': 'www-data',
# chown -R www-data:www-data /opt/freescout
},
}
actions = {
# 'clone_freescout': {
# 'command': run_as('www-data', 'git clone https://github.com/freescout-helpdesk/freescout.git /opt/freescout'),
# 'unless': 'test -e /opt/freescout/.git',
# 'needs': [
# 'pkg_apt:git',
# 'directory:/opt/freescout',
# ],
# },
# 'pull_freescout': {
# 'command': run_as('www-data', 'git -C /opt/freescout fetch origin dist && git -C /opt/freescout reset --hard origin/dist && git -C /opt/freescout clean -f'),
# 'unless': run_as('www-data', 'git -C /opt/freescout fetch origin && git -C /opt/freescout status -uno | grep -q "Your branch is up to date"'),
# 'needs': [
# 'action:clone_freescout',
# ],
# 'triggers': [
# 'action:freescout_artisan_update',
# f'svc_systemd:php{php_version}-fpm.service:restart',
# ],
# },
# 'freescout_artisan_update': {
# 'command': run_as('www-data', 'php /opt/freescout/artisan freescout:after-app-update'),
# 'triggered': True,
# 'needs': [
# f'svc_systemd:php{php_version}-fpm.service:restart',
# 'action:pull_freescout',
# ],
# },
}
# svc_systemd = {
# f'freescout-cron.service': {},
# }
# files = {
# '/opt/freescout/.env': {
# # https://github.com/freescout-helpdesk/freescout/blob/dist/.env.example
# # Every time you are making changes in .env file, in order changes to take an effect you need to run:
# # ´sudo su - www-data -c 'php /opt/freescout/artisan freescout:clear-cache' -s /bin/bash´
# 'owner': 'www-data',
# 'content': '\n'.join(
# f'{k}={v}' for k, v in
# sorted(node.metadata.get('freescout/env').items())
# ) + '\n',
# 'needs': [
# 'directory:/opt/freescout',
# 'action:clone_freescout',
# ],
# },
# }
#sudo su - www-data -s /bin/bash -c 'php /opt/freescout/artisan freescout:create-user --role admin --firstName M --lastName W --email freescout@freibrief.net --password gyh.jzv2bnf6hvc.HKG --no-interaction'
#sudo su - www-data -s /bin/bash -c 'php /opt/freescout/artisan freescout:create-user --role admin --firstName M --lastName W --email freescout@freibrief.net --password gyh.jzv2bnf6hvc.HKG --no-interaction'

View file

@ -1,121 +0,0 @@
from base64 import b64decode
# hash: SCRAM-SHA-256$4096:tQNfqQi7seqNDwJdHqCHbg==$r3ibECluHJaY6VRwpvPqrtCjgrEK7lAkgtUO8/tllTU=:+eeo4M0L2SowfyHFxT2FRqGzezve4ZOEocSIo11DATA=
database_password = repo.vault.password_for(f'{node.name} postgresql freescout').value
defaults = {
'apt': {
'packages': {
'git': {},
'php': {},
'php-pgsql': {},
'php-fpm': {},
'php-mbstring': {},
'php-xml': {},
'php-imap': {},
'php-zip': {},
'php-gd': {},
'php-curl': {},
'php-intl': {},
},
},
'freescout': {
'env': {
'APP_TIMEZONE': 'Europe/Berlin',
'DB_CONNECTION': 'pgsql',
'DB_HOST': '127.0.0.1',
'DB_PORT': '5432',
'DB_DATABASE': 'freescout',
'DB_USERNAME': 'freescout',
'DB_PASSWORD': database_password,
'APP_KEY': 'base64:' + repo.vault.random_bytes_as_base64_for(f'{node.name} freescout APP_KEY', length=32).value
},
},
'php': {
'php.ini': {
'cgi': {
'fix_pathinfo': '0',
},
},
},
'postgresql': {
'roles': {
'freescout': {
'password_hash': repo.libs.postgres.generate_scram_sha_256(
database_password,
b64decode(repo.vault.random_bytes_as_base64_for(f'{node.name} postgres freescout', length=16).value.encode()),
),
},
},
'databases': {
'freescout': {
'owner': 'freescout',
},
},
},
# 'systemd': {
# 'units': {
# f'freescout-cron.service': {
# 'Unit': {
# 'Description': 'Freescout Cron',
# 'After': 'network.target',
# },
# 'Service': {
# 'User': 'www-data',
# 'Nice': 10,
# 'ExecStart': f"/usr/bin/php /opt/freescout/artisan schedule:run"
# },
# 'Install': {
# 'WantedBy': {
# 'multi-user.target'
# }
# },
# }
# },
# },
'systemd-timers': {
'freescout-cron': {
'command': '/usr/bin/php /opt/freescout/artisan schedule:run',
'when': '*-*-* *:*:00',
'RuntimeMaxSec': '180',
'user': 'www-data',
},
},
'zfs': {
'datasets': {
'tank/freescout': {
'mountpoint': '/opt/freescout',
},
},
},
}
@metadata_reactor.provides(
'freescout/env/APP_URL',
)
def freescout(metadata):
return {
'freescout': {
'env': {
'APP_URL': 'https://' + metadata.get('freescout/domain') + '/',
},
},
}
@metadata_reactor.provides(
'nginx/vhosts',
)
def nginx(metadata):
return {
'nginx': {
'vhosts': {
metadata.get('freescout/domain'): {
'content': 'freescout/vhost.conf',
},
},
},
}

View file

@ -2,13 +2,10 @@ from os.path import join
from bundlewrap.utils.dicts import merge_dict
version = node.metadata.get('gitea/version')
assert not version.startswith('v')
arch = node.metadata.get('system/architecture')
version = version=node.metadata.get('gitea/version')
downloads['/usr/local/bin/gitea'] = {
# https://forgejo.org/releases/
'url': f'https://codeberg.org/forgejo/forgejo/releases/download/v{version}/forgejo-{version}-linux-{arch}',
'url': f'https://dl.gitea.io/gitea/{version}/gitea-{version}-linux-amd64',
'sha256_url': '{url}.sha256',
'triggers': {
'svc_systemd:gitea:restart',
@ -48,7 +45,6 @@ files['/etc/gitea/app.ini'] = {
),
),
'owner': 'git',
'mode': '0600',
'context': node.metadata['gitea'],
'triggers': {
'svc_systemd:gitea:restart',

View file

@ -11,20 +11,7 @@ defaults = {
},
},
'gitea': {
'conf': {
'DEFAULT': {
'WORK_PATH': '/var/lib/gitea',
},
'database': {
'DB_TYPE': 'postgres',
'HOST': 'localhost:5432',
'NAME': 'gitea',
'USER': 'gitea',
'PASSWD': database_password,
'SSL_MODE': 'disable',
'LOG_SQL': 'false',
},
},
'conf': {},
},
'postgresql': {
'roles': {
@ -96,6 +83,15 @@ def conf(metadata):
'INTERNAL_TOKEN': repo.vault.password_for(f'{node.name} gitea internal_token'),
'SECRET_KEY': repo.vault.password_for(f'{node.name} gitea security_secret_key'),
},
'database': {
'DB_TYPE': 'postgres',
'HOST': 'localhost:5432',
'NAME': 'gitea',
'USER': 'gitea',
'PASSWD': database_password,
'SSL_MODE': 'disable',
'LOG_SQL': 'false',
},
'service': {
'NO_REPLY_ADDRESS': f'noreply.{domain}',
},
@ -118,7 +114,7 @@ def nginx(metadata):
'content': 'nginx/proxy_pass.conf',
'context': {
'target': 'http://127.0.0.1:3500',
},
}
},
},
},

View file

@ -26,20 +26,14 @@ actions['reset_grafana_admin_password'] = {
directories = {
'/etc/grafana': {},
'/etc/grafana/provisioning': {
'owner': 'grafana',
'group': 'grafana',
},
'/etc/grafana/provisioning': {},
'/etc/grafana/provisioning/datasources': {
'purge': True,
},
'/etc/grafana/provisioning/dashboards': {
'purge': True,
},
'/var/lib/grafana': {
'owner': 'grafana',
'group': 'grafana',
},
'/var/lib/grafana': {},
'/var/lib/grafana/dashboards': {
'owner': 'grafana',
'group': 'grafana',
@ -53,8 +47,6 @@ directories = {
files = {
'/etc/grafana/grafana.ini': {
'content': repo.libs.ini.dumps(node.metadata.get('grafana/config')),
'owner': 'grafana',
'group': 'grafana',
'triggers': [
'svc_systemd:grafana-server:restart',
],
@ -64,8 +56,6 @@ files = {
'apiVersion': 1,
'datasources': list(node.metadata.get('grafana/datasources').values()),
}),
'owner': 'grafana',
'group': 'grafana',
'triggers': [
'svc_systemd:grafana-server:restart',
],
@ -82,8 +72,6 @@ files = {
},
}],
}),
'owner': 'grafana',
'group': 'grafana',
'triggers': [
'svc_systemd:grafana-server:restart',
],
@ -172,8 +160,6 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
files[f'/var/lib/grafana/dashboards/{monitored_node.name}.json'] = {
'content': json.dumps(dashboard, indent=4),
'owner': 'grafana',
'group': 'grafana',
'triggers': [
'svc_systemd:grafana-server:restart',
]

View file

@ -1,23 +0,0 @@
https://github.com/home-assistant/supervised-installer?tab=readme-ov-file
https://github.com/home-assistant/os-agent/tree/main?tab=readme-ov-file#using-home-assistant-supervised-on-debian
https://docs.docker.com/engine/install/debian/
https://www.home-assistant.io/installation/linux#install-home-assistant-supervised
https://github.com/home-assistant/supervised-installer
https://github.com/home-assistant/architecture/blob/master/adr/0014-home-assistant-supervised.md
DATA_SHARE=/usr/share/hassio dpkg --force-confdef --force-confold -i homeassistant-supervised.deb
neu debian
ha installieren
gucken ob geht
dann bw drüberbügeln
https://www.home-assistant.io/integrations/http/#ssl_certificate
`wget "$(curl -L https://api.github.com/repos/home-assistant/supervised-installer/releases/latest | jq -r '.assets[0].browser_download_url')" -O homeassistant-supervised.deb && dpkg -i homeassistant-supervised.deb`

View file

@ -1,30 +0,0 @@
from shlex import quote
version = node.metadata.get('homeassistant/os_agent_version')
directories = {
'/usr/share/hassio': {},
}
actions = {
'install_os_agent': {
'command': ' && '.join([
f'wget -O /tmp/os-agent.deb https://github.com/home-assistant/os-agent/releases/download/{quote(version)}/os-agent_{quote(version)}_linux_aarch64.deb',
'DEBIAN_FRONTEND=noninteractive dpkg -i /tmp/os-agent.deb',
]),
'unless': f'test "$(apt -qq list os-agent | cut -d" " -f2)" = "{quote(version)}"',
'needs': {
'pkg_apt:',
'zfs_dataset:tank/homeassistant',
},
},
'install_homeassistant_supervised': {
'command': 'wget -O /tmp/homeassistant-supervised.deb https://github.com/home-assistant/supervised-installer/releases/latest/download/homeassistant-supervised.deb && apt install /tmp/homeassistant-supervised.deb',
'unless': 'apt -qq list homeassistant-supervised | grep -q "installed"',
'needs': {
'action:install_os_agent',
},
},
}

View file

@ -1,65 +0,0 @@
defaults = {
'apt': {
'packages': {
# homeassistant-supervised
'apparmor': {},
'bluez': {},
'cifs-utils': {},
'curl': {},
'dbus': {},
'jq': {},
'libglib2.0-bin': {},
'lsb-release': {},
'network-manager': {},
'nfs-common': {},
'systemd-journal-remote': {},
'systemd-resolved': {},
'udisks2': {},
'wget': {},
# docker
'docker-ce': {},
'docker-ce-cli': {},
'containerd.io': {},
'docker-buildx-plugin': {},
'docker-compose-plugin': {},
},
'sources': {
# docker: https://docs.docker.com/engine/install/debian/#install-using-the-repository
'docker': {
'urls': {
'https://download.docker.com/linux/debian',
},
'suites': {
'{codename}',
},
'components': {
'stable',
},
},
},
},
'zfs': {
'datasets': {
'tank/homeassistant': {
'mountpoint': '/usr/share/hassio',
'needed_by': {
'directory:/usr/share/hassio',
},
},
},
},
}
@metadata_reactor.provides(
'nginx/vhosts',
)
def nginx(metadata):
return {
'nginx': {
'vhosts': {
metadata.get('homeassistant/domain'): {
'content': 'homeassistant/vhost.conf',
},
},
},
}

View file

@ -0,0 +1,20 @@
users = {
'homeassistant': {
'home': '/var/lib/homeassistant',
},
}
directories = {
'/var/lib/homeassistant': {
'owner': 'homeassistant',
},
'/var/lib/homeassistant/config': {
'owner': 'homeassistant',
},
'/var/lib/homeassistant/venv': {
'owner': 'homeassistant',
},
}
# https://wiki.instar.com/de/Software/Linux/Home_Assistant/

View file

@ -0,0 +1,20 @@
defaults = {
'apt': {
'packages': {
'python3': {},
'python3-dev': {},
'python3-pip': {},
'python3-venv': {},
'libffi-dev': {},
'libssl-dev': {},
'libjpeg-dev': {},
'zlib1g-dev': {},
'autoconf': {},
'build-essential': {},
'libopenjp2-7': {},
'libtiff5': {},
'libturbojpeg0-dev': {},
'tzdata': {},
},
},
}

View file

@ -13,9 +13,9 @@ apply Notification "mail-icingaadmin" to Host {
user_groups = host.vars.notification.mail.groups
users = host.vars.notification.mail.users
//interval = 2h
//vars.notification_logtosyslog = true
assign where host.vars.notification.mail
}
@ -25,9 +25,9 @@ apply Notification "mail-icingaadmin" to Service {
user_groups = host.vars.notification.mail.groups
users = host.vars.notification.mail.users
//interval = 2h
//vars.notification_logtosyslog = true
assign where host.vars.notification.mail
}

View file

@ -269,7 +269,7 @@ svc_systemd = {
'icinga2.service': {
'needs': [
'pkg_apt:icinga2-ido-pgsql',
'svc_systemd:postgresql.service',
'svc_systemd:postgresql',
],
},
}

View file

@ -11,7 +11,7 @@ defaults = {
'php-imagick': {},
'php-pgsql': {},
'icingaweb2': {},
#'icingaweb2-module-monitoring': {}, # ?
'icingaweb2-module-monitoring': {},
},
'sources': {
'icinga': {

View file

@ -1,21 +0,0 @@
from json import dumps
from bundlewrap.metadata import MetadataJSONEncoder
files = {
'/etc/kea/kea-dhcp4.conf': {
'content': dumps(node.metadata.get('kea'), indent=4, sort_keys=True, cls=MetadataJSONEncoder),
'triggers': [
'svc_systemd:kea-dhcp4-server:restart',
],
},
}
svc_systemd = {
'kea-dhcp4-server': {
'needs': [
'pkg_apt:kea-dhcp4-server',
'file:/etc/kea/kea-dhcp4.conf',
'svc_systemd:systemd-networkd:restart',
],
},
}

View file

@ -1,96 +0,0 @@
from ipaddress import ip_interface, ip_network
hashable = repo.libs.hashable.hashable
defaults = {
'apt': {
'packages': {
'kea-dhcp4-server': {},
},
},
'kea': {
'Dhcp4': {
'interfaces-config': {
'interfaces': set(),
},
'lease-database': {
'type': 'memfile',
'lfc-interval': 3600
},
'subnet4': set(),
'loggers': set([
hashable({
'name': 'kea-dhcp4',
'output_options': [
{
'output': 'syslog',
}
],
'severity': 'INFO',
}),
]),
},
},
}
@metadata_reactor.provides(
'kea/Dhcp4/interfaces-config/interfaces',
'kea/Dhcp4/subnet4',
)
def subnets(metadata):
subnet4 = set()
interfaces = set()
reservations = set(
hashable({
'hw-address': network_conf['mac'],
'ip-address': str(ip_interface(network_conf['ipv4']).ip),
})
for other_node in repo.nodes
for network_conf in other_node.metadata.get('network', {}).values()
if 'mac' in network_conf
)
for network_name, network_conf in metadata.get('network').items():
dhcp_server_config = network_conf.get('dhcp_server_config', None)
if dhcp_server_config:
_network = ip_network(dhcp_server_config['subnet'])
subnet4.add(hashable({
'subnet': dhcp_server_config['subnet'],
'pools': [
{
'pool': f'{dhcp_server_config['pool_from']} - {dhcp_server_config['pool_to']}',
},
],
'option-data': [
{
'name': 'routers',
'data': dhcp_server_config['router'],
},
{
'name': 'domain-name-servers',
'data': '10.0.10.2',
},
],
'reservations': set(
reservation
for reservation in reservations
if ip_interface(reservation['ip-address']).ip in _network
),
}))
interfaces.add(network_conf.get('interface', network_name))
return {
'kea': {
'Dhcp4': {
'interfaces-config': {
'interfaces': interfaces,
},
'subnet4': subnet4,
},
},
}

View file

@ -1,36 +1,36 @@
hostname "CroneKorkN : ${name}"
sv_contact "admin@sublimity.de"
// assign serevr to steam group
sv_steamgroup "${','.join(steamgroups)}"
rcon_password "${rcon_password}"
// no annoying message of the day
motd_enabled 0
// enable cheats
sv_cheats 1
// allow inconsistent files on clients (weapon mods for example)
sv_consistency 0
// connect from internet
sv_lan 0
// join game at any point
sv_allow_lobby_connect_only 0
// allowed modes
sv_gametypes "coop,realism,survival,versus,teamversus,scavenge,teamscavenge"
// network
sv_minrate 30000
sv_maxrate 60000
sv_mincmdrate 66
sv_maxcmdrate 101
// logging
sv_logsdir "logs-${name}" //Folder in the game directory where server logs will be stored.
log on //Creates a logfile (on | off)
sv_logecho 0 //default 0; Echo log information to the console.

View file

@ -56,7 +56,6 @@ for domain in node.metadata.get('letsencrypt/domains').keys():
'unless': f'/etc/dehydrated/letsencrypt-ensure-some-certificate {domain} true',
'needs': {
'file:/etc/dehydrated/letsencrypt-ensure-some-certificate',
'pkg_apt:dehydrated',
},
'needed_by': {
'svc_systemd:nginx',

View file

@ -1,41 +0,0 @@
from shlex import quote
def generate_sysctl_key_value_pairs_from_json(json_data, parents=[]):
if isinstance(json_data, dict):
for key, value in json_data.items():
yield from generate_sysctl_key_value_pairs_from_json(value, [*parents, key])
elif isinstance(json_data, list):
raise ValueError(f"List not supported: '{json_data}'")
else:
# If it's a leaf node, yield the path
yield (parents, json_data)
key_value_pairs = generate_sysctl_key_value_pairs_from_json(node.metadata.get('sysctl'))
files= {
'/etc/sysctl.conf': {
'content': '\n'.join(
sorted(
f"{'.'.join(path)}={value}"
for path, value in key_value_pairs
),
),
'triggers': [
'svc_systemd:systemd-sysctl.service:restart',
],
},
}
svc_systemd = {
'systemd-sysctl.service': {},
}
for path, value in key_value_pairs:
actions[f'reload_sysctl.conf_{path}'] = {
'command': f"sysctl --values {'.'.join(path)} | grep -q {quote('^'+value+'$')}",
'needs': [
f'action:systemd-sysctl.service',
f'action:systemd-sysctl.service:restart',
],
}

View file

@ -1,3 +0,0 @@
defaults = {
'sysctl': {},
}

View file

@ -20,19 +20,18 @@ files = {
}
actions = {
'systemd-locale': {
'command': f'localectl set-locale LANG="{default_locale}"',
'unless': f'localectl | grep -Fi "system locale" | grep -Fi "{default_locale}"',
'triggers': {
'action:locale-gen',
},
},
'locale-gen': {
'command': 'locale-gen',
'triggered': True,
'needs': {
'pkg_apt:locales',
'action:systemd-locale',
},
},
'systemd-locale': {
'command': f'localectl set-locale LANG="{default_locale}"',
'unless': f'localectl | grep -Fi "system locale" | grep -Fi "{default_locale}"',
'preceded_by': {
'action:locale-gen',
},
},
}

View file

@ -2,5 +2,5 @@
cd "$OLDPWD"
export BW_ITEM_WORKERS=$(expr "$(sysctl -n hw.logicalcpu)" '*' 12 '/' 10)
export BW_ITEM_WORKERS=$(expr "$(nproc)" '*' 15 '/' 10)
export BW_NODE_WORKERS=$(expr 320 '/' "$BW_ITEM_WORKERS")

View file

@ -2,5 +2,7 @@
cd "$OLDPWD"
PATH_add "/opt/homebrew/opt/gnu-sed/libexec/gnubin"
PATH_add "/opt/homebrew/opt/grep/libexec/gnubin"
GNU_PATH="$HOME/.local/gnu_bin"
mkdir -p "$GNU_PATH"
test -f "$GNU_PATH/sed" || ln -s "$(which gsed)" "$GNU_PATH/sed"
PATH_add "$GNU_PATH"

View file

@ -10,7 +10,6 @@ password required pam_deny.so
session required pam_permit.so
EOT
sudo xcodebuild -license accept
xcode-select --install
git -C ~/.zsh/oh-my-zsh pull
@ -18,7 +17,7 @@ git -C ~/.zsh/oh-my-zsh pull
brew upgrade
brew upgrade --cask --greedy
pyenv install --skip-existing
pyenv install --keep-existing
sudo softwareupdate -ia --verbose
@ -42,5 +41,3 @@ fi
sudo systemsetup -setremotelogin on # enable ssh
pip install --upgrade pip
# https://sysadmin-journal.com/apache-directory-studio-on-the-apple-m1/

View file

@ -5,5 +5,5 @@ cd "$OLDPWD"
if test -f .venv/bin/python && test "$(realpath .venv/bin/python)" != "$(realpath "$(pyenv which python)")"
then
echo "rebuilding venv für new python version"
rm -rf .venv .pip_upgrade_timestamp
rm -rf .venv
fi

View file

@ -3,7 +3,7 @@
cd "$OLDPWD"
python3 -m venv .venv
source .venv/bin/activate
source ./.venv/bin/activate
PATH_add .venv/bin
NOW=$(date +%s)
@ -19,9 +19,5 @@ if test "$DELTA" -gt 86400
then
python3 -m pip --require-virtualenv install pip wheel --upgrade
python3 -m pip --require-virtualenv install -r requirements.txt --upgrade
if test -e optional-requirements.txt
then
python3 -m pip --require-virtualenv install -r optional-requirements.txt --upgrade
fi
date +%s > .pip_upgrade_timestamp
fi

View file

@ -1,9 +1,6 @@
export PATH=~/.bin:$PATH
export PATH=~/.cargo/bin:$PATH
export ZSH=~/.zsh/oh-my-zsh
export ZSH_HOSTNAME='sm'
ZSH_THEME="bw"
ZSH_THEME="ckn"
HIST_STAMPS="yyyy/mm/dd"
plugins=(
zsh-autosuggestions
@ -13,6 +10,13 @@ source $ZSH/oh-my-zsh.sh
ulimit -S -n 24000
sshn() {
ssh "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
}
pingn() {
ping "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
}
antivir() {
printf 'scanning for viruses' && sleep 1 && printf '.' && sleep 1 && printf '.' && sleep 1 && printf '.' &&
sleep 1 && echo '\nyour computer is safe!'
@ -22,12 +26,3 @@ eval "$(rbenv init -)"
eval "$(pyenv init -)"
eval "$(direnv hook zsh)"
eval "$(op completion zsh)"; compdef _op op
# //S/M
sshn() {
ssh "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
}
pingn() {
ping "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
}

View file

@ -1,12 +1,3 @@
# brew install
actions['brew_install'] = {
'command': '/opt/homebrew/bin/brew install ' + ' '.join(node.metadata.get('brew')),
'unless': f"""PKGS=$(/opt/homebrew/bin/brew leaves); for p in {' '.join(node.metadata.get('brew'))}; do grep -q "$p" <<< $PKGS || exit 9; done"""
}
# bw init
directories['/Users/mwiegand/.config/bundlewrap/lock'] = {}
# home
@ -22,12 +13,6 @@ files['/Users/mwiegand/.bin/macbook-update'] = {
'mode': '755',
}
with open(f'{repo.path}/bundles/zsh/files/bw.zsh-theme') as f:
files['/Users/mwiegand/.zsh/oh-my-zsh/themes/bw.zsh-theme'] = {
'content': f.read(),
'mode': '0644',
}
# direnv
directories['/Users/mwiegand/.local/share/direnv'] = {}
@ -36,7 +21,6 @@ files['/Users/mwiegand/.local/share/direnv/pyenv'] = {}
files['/Users/mwiegand/.local/share/direnv/venv'] = {}
files['/Users/mwiegand/.local/share/direnv/bundlewrap'] = {}
##################
for element in [*files.values(), *directories.values()]:

View file

@ -1,3 +1 @@
defaults = {
'brew': {},
}
defaults = {}

View file

@ -1,6 +1,6 @@
<?php
// https://raw.githubusercontent.com/Radiergummi/autodiscover/master/autodiscover/autodiscover.php
/********************************
* Autodiscover responder
@ -8,45 +8,45 @@
* This PHP script is intended to respond to any request to http(s)://mydomain.com/autodiscover/autodiscover.xml.
* If configured properly, it will send a spec-complient autodiscover XML response, pointing mail clients to the
* appropriate mail services.
* If you use MAPI or ActiveSync, stick with the Autodiscover service your mail server provides for you. But if
* If you use MAPI or ActiveSync, stick with the Autodiscover service your mail server provides for you. But if
* you use POP/IMAP servers, this will provide autoconfiguration to Outlook, Apple Mail and mobile devices.
*
* To work properly, you'll need to set the service (sub)domains below in the settings section to the correct
* To work properly, you'll need to set the service (sub)domains below in the settings section to the correct
* domain names, adjust ports and SSL.
*/
//get raw POST data so we can extract the email address
$request = file_get_contents("php://input");
// optional debug log
# file_put_contents( 'request.log', $request, FILE_APPEND );
// retrieve email address from client request
preg_match( "/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email );
// check for invalid mail, to prevent XSS
if (filter_var($email[1], FILTER_VALIDATE_EMAIL) === false) {
throw new Exception('Invalid E-Mail provided');
}
// get domain from email address
$domain = substr( strrchr( $email[1], "@" ), 1 );
/**************************************
* Port and server settings below *
**************************************/
// IMAP settings
$imapServer = 'imap.' . $domain; // imap.example.com
$imapPort = 993;
$imapSSL = true;
// SMTP settings
$smtpServer = 'smtp.' . $domain; // smtp.example.com
$smtpPort = 587;
$smtpSSL = true;
//set Content-Type
header( 'Content-Type: application/xml' );
?>
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>

View file

@ -33,12 +33,6 @@ defaults = {
'mountpoint': '/var/vmail',
'compression': 'on',
},
'tank/vmail/index': {
'mountpoint': '/var/vmail/index',
'compression': 'on',
'com.sun:auto-snapshot': 'false',
'backup': False,
},
},
},
}

View file

@ -1 +0,0 @@
https://mariadb.com/kb/en/systemd/#configuring-mariadb-to-write-the-error-log-to-syslog

View file

@ -1,11 +0,0 @@
% for section, options in sorted(conf.items()):
[${section}]
% for key, value in sorted(options.items()):
% if value is None:
${key}
% else:
${key} = ${value}
% endif
% endfor
% endfor

View file

@ -1,91 +0,0 @@
from shlex import quote
def mariadb(sql, **kwargs):
kwargs_string = ''.join(f" --{k} {v}" for k, v in kwargs.items())
return f"mariadb{kwargs_string} -Bsr --execute {quote(sql)}"
directories = {
'/var/lib/mysql': {
'owner': 'mysql',
'group': 'mysql',
'needs': [
'zfs_dataset:tank/mariadb',
],
'needed_by': [
'pkg_apt:mariadb-server',
'pkg_apt:mariadb-client',
],
},
}
files = {
'/etc/mysql/conf.d/override.conf': {
'context': {
'conf': node.metadata.get('mariadb/conf'),
},
'content_type': 'mako',
},
}
svc_systemd = {
'mariadb.service': {
'needs': [
'pkg_apt:mariadb-server',
'pkg_apt:mariadb-client',
],
},
}
actions = {
'mariadb_sec_remove_anonymous_users': {
'command': mariadb("DELETE FROM mysql.global_priv WHERE User=''"),
'unless': mariadb("SELECT count(0) FROM mysql.global_priv WHERE User = ''") + " | grep -q '^0$'",
'needs': [
'svc_systemd:mariadb.service',
],
'triggers': [
'svc_systemd:mariadb.service:restart',
],
},
'mariadb_sec_remove_remote_root': {
'command': mariadb("DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"),
'unless': mariadb("SELECT count(0) FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')") + " | grep -q '^0$'",
'needs': [
'svc_systemd:mariadb.service',
],
'triggers': [
'svc_systemd:mariadb.service:restart',
],
},
}
for db, conf in node.metadata.get('mariadb/databases', {}).items():
actions[f'mariadb_create_database_{db}'] = {
'command': mariadb(f"CREATE DATABASE {db}"),
'unless': mariadb(f"SHOW DATABASES LIKE '{db}'") + f" | grep -q '^{db}$'",
'needs': [
'svc_systemd:mariadb.service',
],
}
actions[f'mariadb_user_{db}_create'] = {
'command': mariadb(f"CREATE USER {db}"),
'unless': mariadb(f"SELECT User FROM mysql.user WHERE User = '{db}'") + f" | grep -q '^{db}$'",
'needs': [
f'action:mariadb_create_database_{db}',
],
}
pw = conf['password']
actions[f'mariadb_user_{db}_password'] = {
'command': mariadb(f"SET PASSWORD FOR {db} = PASSWORD('{conf['password']}')"),
'unless': f'echo {quote(pw)} | mariadb -u {db} -e quit -p',
'needs': [
f'action:mariadb_user_{db}_create',
],
}
actions[f'mariadb_grant_privileges_to_{db}'] = {
'command': mariadb(f"GRANT ALL PRIVILEGES ON {db}.* TO '{db}'", database=db),
'unless': mariadb(f"SHOW GRANTS FOR {db}") + f" | grep -q '^GRANT ALL PRIVILEGES ON `{db}`.* TO `{db}`@`%`'",
'needs': [
f'action:mariadb_user_{db}_create',
],
}

View file

@ -1,45 +0,0 @@
defaults = {
'apt': {
'packages': {
'mariadb-server': {
'needs': {
'zfs_dataset:tank/mariadb',
},
},
'mariadb-client': {
'needs': {
'zfs_dataset:tank/mariadb',
},
},
},
},
'mariadb': {
'databases': {},
'conf': {
# https://www.reddit.com/r/zfs/comments/u1xklc/mariadbmysql_database_settings_for_zfs
'mysqld': {
'skip-innodb_doublewrite': None,
'innodb_flush_method': 'fsync',
'innodb_doublewrite': '0',
'innodb_use_atomic_writes': '0',
'innodb_use_native_aio': '0',
'innodb_read_io_threads': '10',
'innodb_write_io_threads': '10',
'innodb_buffer_pool_size': '26G',
'innodb_flush_log_at_trx_commit': '1',
'innodb_log_file_size': '1G',
'innodb_flush_neighbors': '0',
'innodb_fast_shutdown': '2',
},
},
},
'zfs': {
'datasets': {
'tank/mariadb': {
'mountpoint': '/var/lib/mysql',
'recordsize': '16384',
'atime': 'off',
},
},
},
}

View file

@ -5,89 +5,38 @@ defaults = {
}
@metadata_reactor.provides(
'network',
)
def dhcp(metadata):
networks = {}
for network_name, network_conf in metadata.get('network').items():
_interface = ip_interface(network_conf['ipv4'])
_ip = _interface.ip
_network = _interface.network
_hosts = list(_network.hosts())
if network_conf.get('dhcp_server', False):
networks[network_name] = {
'dhcp_server_config': {
'subnet': str(_network),
'pool_from': str(_hosts[len(_hosts)//2]),
'pool_to': str(_hosts[-3]),
'router': str(_ip),
'domain-name-servers': str(_ip),
}
}
return {
'network': networks,
}
@metadata_reactor.provides(
'systemd/units',
)
def units(metadata):
units = {}
for network_name, network_conf in metadata.get('network').items():
interface_type = network_conf.get('type', None)
# network
units[f'{network_name}.network'] = {
for type, network in metadata.get('network').items():
units[f'{type}.network'] = {
'Match': {
'Name': network_name if interface_type == 'vlan' else network_conf['interface'],
'Name': network['interface'],
},
'Network': {
'DHCP': network_conf.get('dhcp', 'no'),
'IPv6AcceptRA': network_conf.get('dhcp', 'no'),
'VLAN': set(network_conf.get('vlans', set()))
'DHCP': network.get('dhcp', 'no'),
'IPv6AcceptRA': network.get('dhcp', 'no'),
}
}
# type
if interface_type:
units[f'{network_name}.network']['Match']['Type'] = interface_type
# ips
for i in [4, 6]:
if network_conf.get(f'ipv{i}', None):
units[f'{network_name}.network'].update({
if network.get(f'ipv{i}', None):
units[f'{type}.network'].update({
f'Address#ipv{i}': {
'Address': network_conf[f'ipv{i}'],
'Address': network[f'ipv{i}'],
},
})
if f'gateway{i}' in network_conf:
units[f'{network_name}.network'].update({
if f'gateway{i}' in network:
units[f'{type}.network'].update({
f'Route#ipv{i}': {
'Gateway': network_conf[f'gateway{i}'],
'Gateway': network[f'gateway{i}'],
'GatewayOnlink': 'yes',
}
})
# as vlan
if interface_type == 'vlan':
units[f"{network_name}.netdev"] = {
'NetDev': {
'Name': network_name,
'Kind': 'vlan',
},
'VLAN': {
'Id': network_conf['id'],
}
}
return {
'systemd': {

View file

@ -29,8 +29,8 @@ defaults = {
'exclude': [
'^appdata_',
'^updater-',
'^nextcloud\\.log',
'^updater\\.log',
'^nextcloud\.log',
'^updater\.log',
'^[^/]+/cache',
'^[^/]+/files_versions',
'^[^/]+/files_trashbin',
@ -123,9 +123,9 @@ def config(metadata):
],
'cache_path': '/var/lib/nextcloud/.cache',
'upgrade.disable-web': True,
'memcache.local': '\\OC\\Memcache\\Redis',
'memcache.locking': '\\OC\\Memcache\\Redis',
'memcache.distributed': '\\OC\\Memcache\\Redis',
'memcache.local': '\OC\Memcache\Redis',
'memcache.locking': '\OC\Memcache\Redis',
'memcache.distributed': '\OC\Memcache\Redis',
'redis': {
'host': '/var/run/redis/nextcloud.sock'
},
@ -142,7 +142,6 @@ def config(metadata):
'versions_retention_obligation': 'auto, 90',
'simpleSignUpLink.shown': False,
'allow_local_remote_servers': True, # FIXME?
'maintenance_window_start': 1, # https://docs.nextcloud.com/server/29/admin_manual/configuration_server/background_jobs_configuration.html#maintenance-window-start
},
},
}

View file

@ -1,6 +1,6 @@
pid /var/run/nginx.pid;
user www-data;
worker_processes ${worker_processes};
worker_processes 10;
% for module in sorted(modules):
load_module modules/ngx_${module}_module.so;
@ -21,9 +21,6 @@ http {
server_names_hash_bucket_size 128;
tcp_nopush on;
client_max_body_size 32G;
ssl_dhparam "/etc/ssl/certs/dhparam.pem";
# dont show nginx version
server_tokens off;
% if node.has_bundle('php'):
upstream php-handler {

View file

@ -32,7 +32,6 @@ files = {
'content_type': 'mako',
'context': {
'modules': node.metadata.get('nginx/modules'),
'worker_processes': node.metadata.get('vm/cores'),
},
'triggers': {
'svc_systemd:nginx:restart',
@ -77,7 +76,7 @@ files = {
actions = {
'nginx-generate-dhparam': {
'command': 'openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096',
'command': 'openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048',
'unless': 'test -f /etc/ssl/certs/dhparam.pem',
},
}

View file

@ -73,6 +73,7 @@ def dns(metadata):
@metadata_reactor.provides(
'letsencrypt/domains',
'letsencrypt/reload_after',
)
def letsencrypt(metadata):
return {

View file

@ -1,7 +1,5 @@
from os.path import join, exists
from re import sub
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from base64 import b64decode

View file

@ -1,3 +1,9 @@
from os.path import join
import json
from bundlewrap.utils.dicts import merge_dict
version = node.metadata.get('php/version')
files = {
@ -15,7 +21,7 @@ files = {
f'pkg_apt:php{version}-fpm',
},
'triggers': {
f'svc_systemd:php{version}-fpm.service:restart',
f'svc_systemd:php{version}-fpm:restart',
},
},
f'/etc/php/{version}/fpm/pool.d/www.conf': {
@ -27,13 +33,13 @@ files = {
f'pkg_apt:php{version}-fpm',
},
'triggers': {
f'svc_systemd:php{version}-fpm.service:restart',
f'svc_systemd:php{version}-fpm:restart',
},
},
}
svc_systemd = {
f'php{version}-fpm.service': {
f'php{version}-fpm': {
'needs': {
'pkg_apt:',
f'file:/etc/php/{version}/fpm/php.ini',

View file

@ -113,7 +113,7 @@ def php_ini(metadata):
'opcache.revalidate_freq': '60',
},
}
return {
'php': {
'php.ini': {
@ -145,7 +145,7 @@ def www_conf(metadata):
'pm': 'dynamic',
'pm.max_children': int(threads*2),
'pm.start_servers': int(threads),
'pm.min_spare_servers': max([1, int(threads/2)]),
'pm.min_spare_servers': int(threads/2),
'pm.max_spare_servers': int(threads),
'pm.max_requests': int(threads*32),
},

View file

@ -44,9 +44,7 @@ smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_restriction_classes = mua_sender_restrictions, mua_client_restrictions, mua_helo_restrictions
mua_client_restrictions = permit_sasl_authenticated, reject
mua_sender_restrictions = permit_sasl_authenticated, reject
## MS Outlook, incompatible with reject_non_fqdn_hostname and/or reject_invalid_hostname
## https://unix.stackexchange.com/a/91753/357916
mua_helo_restrictions = permit_mynetworks, permit
mua_helo_restrictions = permit_mynetworks, reject_non_fqdn_hostname, reject_invalid_hostname, permit
smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332
non_smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332

View file

@ -86,8 +86,6 @@ if node.has_bundle('telegraf'):
'needs': [
'pkg_apt:acl',
'svc_systemd:postfix',
'svc_systemd:postfix:reload',
'svc_systemd:postfix:restart',
],
}
actions['postfix_setfacl_default_telegraf'] = {
@ -96,7 +94,5 @@ if node.has_bundle('telegraf'):
'needs': [
'pkg_apt:acl',
'svc_systemd:postfix',
'svc_systemd:postfix:reload',
'svc_systemd:postfix:restart',
],
}

View file

@ -12,7 +12,7 @@ directories = {
'zfs_dataset:tank/postgresql',
],
'needed_by': [
'svc_systemd:postgresql.service',
'svc_systemd:postgresql',
],
}
}
@ -25,19 +25,16 @@ files = {
) + '\n',
'owner': 'postgres',
'group': 'postgres',
'needs': [
'pkg_apt:postgresql',
],
'needed_by': [
'svc_systemd:postgresql.service',
'svc_systemd:postgresql',
],
'triggers': [
'svc_systemd:postgresql.service:restart',
'svc_systemd:postgresql:restart',
],
},
}
svc_systemd['postgresql.service'] = {
svc_systemd['postgresql'] = {
'needs': [
'pkg_apt:postgresql',
],
@ -46,13 +43,13 @@ svc_systemd['postgresql.service'] = {
for user, config in node.metadata.get('postgresql/roles').items():
postgres_roles[user] = merge_dict(config, {
'needs': [
'svc_systemd:postgresql.service',
'svc_systemd:postgresql',
],
})
for database, config in node.metadata.get('postgresql/databases').items():
postgres_dbs[database] = merge_dict(config, {
'needs': [
'svc_systemd:postgresql.service',
'svc_systemd:postgresql',
],
})

View file

@ -6,11 +6,7 @@ root_password = repo.vault.password_for(f'{node.name} postgresql root')
defaults = {
'apt': {
'packages': {
'postgresql': {
'needs': {
'zfs_dataset:tank/postgresql',
},
},
'postgresql': {},
},
},
'backup': {
@ -58,25 +54,6 @@ def conf(metadata):
}
@metadata_reactor.provides(
'apt/config/APT/NeverAutoRemove',
)
def apt(metadata):
return {
'apt': {
'config': {
'APT': {
'NeverAutoRemove': {
# https://github.com/credativ/postgresql-common/blob/master/pg_updateaptconfig#L17-L21
f"^postgresql.*-{metadata.get('postgresql/version')}",
},
},
},
},
}
@metadata_reactor.provides(
'zfs/datasets',
)

View file

@ -1,25 +0,0 @@
from shlex import quote
directories = {
'/opt/pyenv': {},
'/opt/pyenv/install': {},
}
git_deploy = {
'/opt/pyenv/install': {
'repo': 'https://github.com/pyenv/pyenv.git',
'rev': 'master',
'needs': {
'directory:/opt/pyenv/install',
},
},
}
for version in node.metadata.get('pyenv/versions'):
actions[f'pyenv_install_{version}'] = {
'command': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv install {quote(version)}',
'unless': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv versions --bare | grep -Fxq {quote(version)}',
'needs': {
'git_deploy:/opt/pyenv/install',
},
}

View file

@ -1,23 +0,0 @@
defaults = {
'apt': {
'packages': {
'build-essential': {},
'libssl-dev': {},
'zlib1g-dev': {},
'libbz2-dev': {},
'libreadline-dev': {},
'libsqlite3-dev': {},
'curl': {},
'libncurses-dev': {},
'xz-utils': {},
'tk-dev': {},
'libxml2-dev': {},
'libxmlsec1-dev': {},
'libffi-dev': {},
'liblzma-dev': {},
},
},
'pyenv': {
'versions': set(),
},
}

View file

@ -1,3 +0,0 @@
- Homematic > Settings > Control panel > Security > SSH > active & set password
- ssh to node > `ssh-copy-id -o StrictHostKeyChecking=no root@{homematic}`
- Homematic > Settings > Control panel > Security > Automatic forwarding to HTTPS > active

View file

@ -1,3 +1,6 @@
from shlex import quote
@metadata_reactor.provides(
'letsencrypt/domains',
)
@ -17,6 +20,8 @@ def letsencrypt(metadata):
'systemd-timers/raspberrymatic-cert',
)
def systemd_timers(metadata):
domain = metadata.get('raspberrymatic-cert/domain')
return {
'systemd-timers': {
'raspberrymatic-cert': {

View file

@ -6,16 +6,80 @@ $config['enable_installer'] = true;
/* Local configuration for Roundcube Webmail */
// ----------------------------------
// SQL DATABASE
// ----------------------------------
// Database connection string (DSN) for read+write operations
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
// Currently supported db_providers: mysql, pgsql, sqlite, mssql or sqlsrv
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
// NOTE: for SQLite use absolute path: 'sqlite:////full/path/to/sqlite.db?mode=0646'
$config['db_dsnw'] = '${database['provider']}://${database['user']}:${database['password']}@${database['host']}/${database['name']}';
$config['imap_host'] = 'localhost';
$config['smtp_host'] = 'tls://localhost';
// ----------------------------------
// IMAP
// ----------------------------------
// The mail host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %s - domain name after the '@' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %t = domain.tld
// WARNING: After hostname change update of mail_host column in users table is
// required to match old user data records with the new host.
$config['default_host'] = 'localhost';
// ----------------------------------
// SMTP
// ----------------------------------
// SMTP server host (for sending mails).
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// If left blank, the PHP mail() function is used
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
$config['smtp_server'] = 'tls://localhost';
// SMTP username (if required) if you use %u as the username Roundcube
// will use the current username for login
$config['smtp_user'] = '%u';
// SMTP password (if required) if you use %p as the password Roundcube
// will use the current user's password for login
$config['smtp_pass'] = '%p';
// provide an URL where a user can get support for this Roundcube installation
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
$config['support_url'] = '';
// this key is used to encrypt the users imap password which is stored
// in the session record (and the client cookie if remember password is enabled).
// please provide a string of exactly 24 chars.
$config['des_key'] = '${des_key}';
// Name your service. This is displayed on the login screen and in the window title
$config['product_name'] = '${product_name}';
// ----------------------------------
// PLUGINS
// ----------------------------------
// List of active plugins (in plugins/ directory)
$config['plugins'] = array(${', '.join(f'"{plugin}"' for plugin in plugins)});
// the default locale setting (leave empty for auto-detection)
// RFC1766 formatted language name like en_US, de_DE, de_CH, fr_FR, pt_BR
$config['language'] = 'de_DE';
// https://serverfault.com/a/991304
$config['smtp_conn_options'] = array(
'ssl' => array(
'verify_peer' => false,

View file

@ -14,4 +14,4 @@ $config['password_dovecotpw'] = '/usr/bin/sudo /usr/bin/doveadm pw';
$config['password_dovecotpw_method'] = 'ARGON2ID';
$config['password_dovecotpw_with_method'] = true;
$config['password_db_dsn'] = 'pgsql://mailserver:${mailserver_db_password}@localhost/mailserver';
$config['password_query'] = "UPDATE users SET password = %P FROM domains WHERE domains.id = users.domain_id AND domains.name = %d AND users.name = %l";
$config['password_query'] = "UPDATE users SET password=%D FROM domains WHERE domains.id = domain_id AND domains.name = %d AND users.name = %l";

View file

@ -1,8 +1,7 @@
assert node.has_bundle('php')
assert node.has_bundle('mailserver')
roundcube_version = node.metadata.get('roundcube/version')
php_version = node.metadata.get('php/version')
version = node.metadata.get('roundcube/version')
directories = {
'/opt/roundcube': {
@ -23,9 +22,9 @@ directories = {
}
files[f'/tmp/roundcube-{roundcube_version}.tar.gz'] = {
files[f'/tmp/roundcube-{version}.tar.gz'] = {
'content_type': 'download',
'source': f'https://github.com/roundcube/roundcubemail/releases/download/{roundcube_version}/roundcubemail-{roundcube_version}-complete.tar.gz',
'source': f'https://github.com/roundcube/roundcubemail/releases/download/{version}/roundcubemail-{version}-complete.tar.gz',
'triggered': True,
}
actions['delete_roundcube'] = {
@ -33,18 +32,18 @@ actions['delete_roundcube'] = {
'triggered': True,
}
actions['extract_roundcube'] = {
'command': f'tar xfvz /tmp/roundcube-{roundcube_version}.tar.gz --strip 1 -C /opt/roundcube',
'unless': f'grep -q "Version {roundcube_version}" /opt/roundcube/index.php',
'command': f'tar xfvz /tmp/roundcube-{version}.tar.gz --strip 1 -C /opt/roundcube',
'unless': f'grep -q "Version {version}" /opt/roundcube/index.php',
'preceded_by': [
'action:delete_roundcube',
f'file:/tmp/roundcube-{roundcube_version}.tar.gz',
f'file:/tmp/roundcube-{version}.tar.gz',
],
'needs': [
'directory:/opt/roundcube',
],
'triggers': [
'action:chown_roundcube',
'action:composer_lock_reset',
'action:composer_install',
],
}
actions['chown_roundcube'] = {
@ -65,9 +64,6 @@ files['/opt/roundcube/config/config.inc.php'] = {
'needs': [
'action:chown_roundcube',
],
'triggers': [
f'svc_systemd:php{php_version}-fpm.service:restart',
],
}
files['/opt/roundcube/plugins/password/config.inc.php'] = {
'source': 'password.config.inc.php',
@ -79,16 +75,7 @@ files['/opt/roundcube/plugins/password/config.inc.php'] = {
'action:chown_roundcube',
],
}
actions['composer_lock_reset'] = {
'command': 'rm /opt/roundcube/composer.lock',
'triggered': True,
'needs': [
'action:chown_roundcube',
],
'triggers': [
'action:composer_install',
],
}
actions['composer_install'] = {
'command': "cp /opt/roundcube/composer.json-dist /opt/roundcube/composer.json && su www-data -s /bin/bash -c '/usr/bin/composer -d /opt/roundcube install'",
'triggered': True,

View file

@ -21,4 +21,3 @@ ClientAliveInterval 30
ClientAliveCountMax 5
AcceptEnv LANG
Subsystem sftp /usr/lib/openssh/sftp-server
HostKey /etc/ssh/ssh_host_managed_key

View file

@ -51,14 +51,14 @@ files = {
],
'skip': dont_touch_sshd,
},
'/etc/ssh/ssh_host_managed_key': {
'/etc/ssh/ssh_host_ed25519_key': {
'content': node.metadata.get('ssh/host_key/private') + '\n',
'mode': '0600',
'triggers': [
'svc_systemd:ssh:restart'
],
},
'/etc/ssh/ssh_host_managed_key.pub': {
'/etc/ssh/ssh_host_ed25519_key.pub': {
'content': node.metadata.get('ssh/host_key/public') + '\n',
'mode': '0644',
'triggers': [

View file

@ -34,19 +34,18 @@ defaults = {
)
def systemd_timer(metadata):
return {
# steam python login is broken: https://github.com/ValvePython/steam/issues/442
# 'systemd-timers': {
# f'steam-chat-logger': {
# 'command': '/opt/steam_chat_logger/steam_chat_logger.py',
# 'when': 'hourly',
# 'user': 'steam_chat_logger',
# 'env': {
# 'DB_NAME': 'steam_chat_logger',
# 'DB_USER': 'steam_chat_logger',
# 'DB_PASSWORD': metadata.get('postgresql/roles/steam_chat_logger/password'),
# **metadata.get('steam_chat_logger'),
# },
# 'working_dir': '/var/lib/steam_chat_logger',
# },
# },
'systemd-timers': {
f'steam-chat-logger': {
'command': '/opt/steam_chat_logger/steam_chat_logger.py',
'when': 'hourly',
'user': 'steam_chat_logger',
'env': {
'DB_NAME': 'steam_chat_logger',
'DB_USER': 'steam_chat_logger',
'DB_PASSWORD': metadata.get('postgresql/roles/steam_chat_logger/password'),
**metadata.get('steam_chat_logger'),
},
'working_dir': '/var/lib/steam_chat_logger',
},
},
}

View file

@ -1,7 +1,7 @@
files = {
'/etc/systemd/journald.conf.d/managed.conf': {
'content': repo.libs.systemd.generate_unitfile({
'Journal': node.metadata.get('systemd-journald'),
'Jorunal': node.metadata.get('systemd-journald'),
}),
'triggers': {
'svc_systemd:systemd-journald:restart',

View file

@ -42,8 +42,6 @@ def systemd(metadata):
units[f'{name}.service']['Service']['SuccessExitStatus'] = config['success_exit_status']
if config.get('kill_mode'):
units[f'{name}.service']['Service']['KillMode'] = config['kill_mode']
if config.get('RuntimeMaxSec'):
units[f'{name}.service']['Service']['RuntimeMaxSec'] = config['RuntimeMaxSec']
services[f'{name}.timer'] = {}

View file

@ -9,7 +9,7 @@ files = {
node.metadata.get('telegraf/config'),
cls=MetadataJSONEncoder,
)),
sort_keys=True,
sort_keys=True
),
'triggers': [
'svc_systemd:telegraf:restart',

View file

@ -7,8 +7,6 @@ defaults = {
# needed by crystal plugins:
'libgc-dev': {},
'libevent-dev': {},
# crystal based (procio, pressure_stall):
'libpcre3': {},
},
'sources': {
'influxdata': {
@ -58,7 +56,7 @@ defaults = {
'procstat': {h({
'interval': '60s',
'pattern': '.',
'fieldinclude': [
'fieldpass': [
'cpu_usage',
'memory_rss',
],

View file

@ -1 +0,0 @@
https://developer.wordpress.org/advanced-administration/upgrade/upgrading/

View file

@ -1,25 +0,0 @@
#!/bin/bash
SITE=$1
VERSION=$(php -r "require('/opt/$SITE/wp-includes/version.php'); echo \$wp_version;")
STATUS=$(curl -ssL http://api.wordpress.org/core/stable-check/1.0/ | jq -r '.["'$VERSION'"]')
echo "WordPress $VERSION is '$STATUS'"
if [[ "$STATUS" == latest ]]
then
exit 0
elif [[ "$STATUS" == outdated ]]
then
exit 1
elif [[ "$STATUS" == insecure ]]
then
if test -f /etc/nginx/sites/$SITE
then
rm /etc/nginx/sites/$SITE
systemctl restart nginx
fi
exit 2
else
exit 2
fi

View file

@ -1,5 +0,0 @@
<?php
require_once '${path}/wp-includes/version.php';
echo "$wp_version";

View file

@ -1,12 +0,0 @@
files = {
'/usr/lib/nagios/plugins/check_wordpress_insecure': {
'mode': '0750',
},
}
for site, conf in node.metadata.get('wordpress').items():
directories[f'/opt/{site}'] = {
'owner': 'www-data',
'group': 'www-data',
'mode': '0755',
}

View file

@ -1,92 +0,0 @@
defaults = {
'php': {
'php.ini': {
'cgi': {
'fix_pathinfo': '0',
},
},
},
}
@metadata_reactor.provides(
'wordpress',
)
def wordpress(metadata):
return {
'wordpress': {
site: {
'db_password': repo.vault.password_for(f"wordpress {site} db").value,
}
for site in metadata.get('wordpress')
},
}
@metadata_reactor.provides(
'mariadb/databases',
)
def mariadb(metadata):
return {
'mariadb': {
'databases': {
site: {
'password': metadata.get(f'wordpress/{site}/db_password')
}
for site in metadata.get('wordpress')
},
},
}
@metadata_reactor.provides(
'nginx/vhosts'
)
def vhost(metadata):
return {
'nginx': {
'vhosts': {
conf['domain']: {
'content': 'wordpress/vhost.conf',
'context': {
'root': f'/opt/{site}',
},
}
for site, conf in metadata.get('wordpress').items()
},
},
}
@metadata_reactor.provides(
'zfs/datasets',
)
def zfs(metadata):
return {
'zfs': {
'datasets': {
f'tank/{site}': {
'mountpoint': f'/opt/{site}',
}
for site in metadata.get('wordpress')
},
},
}
@metadata_reactor.provides(
'monitoring/services',
)
def check_insecure(metadata):
return {
'monitoring': {
'services': {
f'wordpress {site} insecure': {
'vars.command': f'/usr/lib/nagios/plugins/check_wordpress_insecure {site}',
'check_interval': '30m',
'vars.sudo': True,
}
for site in metadata.get('wordpress')
},
},
}

View file

@ -6,7 +6,6 @@ files = {
'/etc/cron.weekly/zfs-auto-snapshot': {'delete': True, 'needs': {'pkg_apt:zfs-auto-snapshot'}},
'/etc/cron.monthly/zfs-auto-snapshot': {'delete': True, 'needs': {'pkg_apt:zfs-auto-snapshot'}},
'/etc/modprobe.d/zfs.conf': {
'content_type': 'text',
'content': '\n'.join(
f'options zfs {k}={v}'
for k, v in node.metadata.get('zfs/kernel_params').items()

View file

@ -122,7 +122,10 @@ def backup(metadata):
'apt/packages'
)
def headers(metadata):
arch = metadata.get('system/architecture')
if node.in_group('raspberry-pi'):
arch = 'arm64'
else:
arch = 'amd64'
return {
'apt': {

View file

@ -34,16 +34,7 @@ function zsh_exitcode_color {
echo "%(?:%{$fg_bold[green]%}:%{$fg_bold[red]%})"
}
function zsh_hostname {
if [ -z "$ZSH_HOSTNAME" ]
then
hostname -s
else
echo "$ZSH_HOSTNAME"
fi
}
PROMPT='$(zsh_root_color)$(whoami)%{$reset_color%}@$(zsh_exitcode_color)$(zsh_hostname) %{$fg[cyan]%}$(zsh_spwd)%{$reset_color%} $(git_prompt_info)'
PROMPT='$(zsh_root_color)$(whoami)%{$reset_color%}@$(zsh_exitcode_color)$(hostname -s) %{$fg[cyan]%}$(zsh_spwd)%{$reset_color%} $(git_prompt_info)'
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "

View file

@ -9,7 +9,6 @@ directories = {
]
},
'/etc/zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions': {
'mode': '0755',
'needs': [
f"git_deploy:/etc/zsh/oh-my-zsh",
]
@ -28,30 +27,14 @@ git_deploy = {
}
files = {
'/etc/zsh/zprofile': {
'mode': '0755',
},
'/etc/zsh/zprofile': {},
'/etc/zsh/oh-my-zsh/themes/bw.zsh-theme': {
'mode': '0755',
'needs': [
f"git_deploy:/etc/zsh/oh-my-zsh",
]
},
}
actions = {
'chown_oh_my_zsh': {
'command': 'chmod -R 755 /etc/zsh/oh-my-zsh',
'triggered': True,
'triggered_by': [
"git_deploy:/etc/zsh/oh-my-zsh",
"git_deploy:/etc/zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions",
"file:/etc/zsh/zprofile",
"file:/etc/zsh/oh-my-zsh/themes/bw.zsh-theme",
],
},
}
for name, user_config in node.metadata.get('users').items():
if user_config.get('shell', None) == '/usr/bin/zsh':
files[join(user_config['home'], '.zshrc')] = {

View file

@ -1,62 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth
lqqwp028AqyY+PRfVMtSYMbjuQuu5byyKR01BbqYhuS3jtqQmljZ/bJvXqnmiVXh
38UuLa+z077PxyxQhu5BbqntTPQMfiyqEiU+BKbq2WmANUKQf+1AmZY/IruOXbnq
L4C1+gJ8vfmXQt99npCaxEjaNRVYfOS8QcixNzHUYnb6emjlANyEVlZzeqo7XKl7
UrwV5inawTSzWNvtjEjj4nJL8NsLwscpLPQUhTQ+7BbQXAwAmeHCUTQIvvWXqw0N
cmhh4HgeQscQHYgOJjjDVfoY5MucvglbIgCqfzAHW9jxmRL4qbMZj+b1XoePEtht
ku4bIQN1X5P07fNWzlgaRL5Z4POXDDZTlIQ/El58j9kp4bnWRCJW0lya+f8ocodo
vZZ+Doi+fy4D5ZGrL4XEcIQP/Lv5uFyf+kQtl/94VFYVJOleAv8W92KdgDkhTcTD
G7c0tIkVEKNUq48b3aQ64NOZQW7fVjfoKwEZdOqPE72Pa45jrZzvUFxSpdiNk2tZ
XYukHjlxxEgBdC/J3cMMNRE1F4NCA3ApfV1Y7/hTeOnmDuDYwr9/obA8t016Yljj
q5rdkywPf4JF8mXUW5eCN1vAFHxeg9ZWemhBtQmGxXnw9M+z6hWwc6ahmwARAQAB
tCtEb2NrZXIgUmVsZWFzZSAoQ0UgZGViKSA8ZG9ja2VyQGRvY2tlci5jb20+iQI3
BBMBCgAhBQJYrefAAhsvBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEI2BgDwO
v82IsskP/iQZo68flDQmNvn8X5XTd6RRaUH33kXYXquT6NkHJciS7E2gTJmqvMqd
tI4mNYHCSEYxI5qrcYV5YqX9P6+Ko+vozo4nseUQLPH/ATQ4qL0Zok+1jkag3Lgk
jonyUf9bwtWxFp05HC3GMHPhhcUSexCxQLQvnFWXD2sWLKivHp2fT8QbRGeZ+d3m
6fqcd5Fu7pxsqm0EUDK5NL+nPIgYhN+auTrhgzhK1CShfGccM/wfRlei9Utz6p9P
XRKIlWnXtT4qNGZNTN0tR+NLG/6Bqd8OYBaFAUcue/w1VW6JQ2VGYZHnZu9S8LMc
FYBa5Ig9PxwGQOgq6RDKDbV+PqTQT5EFMeR1mrjckk4DQJjbxeMZbiNMG5kGECA8
g383P3elhn03WGbEEa4MNc3Z4+7c236QI3xWJfNPdUbXRaAwhy/6rTSFbzwKB0Jm
ebwzQfwjQY6f55MiI/RqDCyuPj3r3jyVRkK86pQKBAJwFHyqj9KaKXMZjfVnowLh
9svIGfNbGHpucATqREvUHuQbNnqkCx8VVhtYkhDb9fEP2xBu5VvHbR+3nfVhMut5
G34Ct5RS7Jt6LIfFdtcn8CaSas/l1HbiGeRgc70X/9aYx/V/CEJv0lIe8gP6uDoW
FPIZ7d6vH+Vro6xuWEGiuMaiznap2KhZmpkgfupyFmplh0s6knymuQINBFit2ioB
EADneL9S9m4vhU3blaRjVUUyJ7b/qTjcSylvCH5XUE6R2k+ckEZjfAMZPLpO+/tF
M2JIJMD4SifKuS3xck9KtZGCufGmcwiLQRzeHF7vJUKrLD5RTkNi23ydvWZgPjtx
Q+DTT1Zcn7BrQFY6FgnRoUVIxwtdw1bMY/89rsFgS5wwuMESd3Q2RYgb7EOFOpnu
w6da7WakWf4IhnF5nsNYGDVaIHzpiqCl+uTbf1epCjrOlIzkZ3Z3Yk5CM/TiFzPk
z2lLz89cpD8U+NtCsfagWWfjd2U3jDapgH+7nQnCEWpROtzaKHG6lA3pXdix5zG8
eRc6/0IbUSWvfjKxLLPfNeCS2pCL3IeEI5nothEEYdQH6szpLog79xB9dVnJyKJb
VfxXnseoYqVrRz2VVbUI5Blwm6B40E3eGVfUQWiux54DspyVMMk41Mx7QJ3iynIa
1N4ZAqVMAEruyXTRTxc9XW0tYhDMA/1GYvz0EmFpm8LzTHA6sFVtPm/ZlNCX6P1X
zJwrv7DSQKD6GGlBQUX+OeEJ8tTkkf8QTJSPUdh8P8YxDFS5EOGAvhhpMBYD42kQ
pqXjEC+XcycTvGI7impgv9PDY1RCC1zkBjKPa120rNhv/hkVk/YhuGoajoHyy4h7
ZQopdcMtpN2dgmhEegny9JCSwxfQmQ0zK0g7m6SHiKMwjwARAQABiQQ+BBgBCAAJ
BQJYrdoqAhsCAikJEI2BgDwOv82IwV0gBBkBCAAGBQJYrdoqAAoJEH6gqcPyc/zY
1WAP/2wJ+R0gE6qsce3rjaIz58PJmc8goKrir5hnElWhPgbq7cYIsW5qiFyLhkdp
YcMmhD9mRiPpQn6Ya2w3e3B8zfIVKipbMBnke/ytZ9M7qHmDCcjoiSmwEXN3wKYI
mD9VHONsl/CG1rU9Isw1jtB5g1YxuBA7M/m36XN6x2u+NtNMDB9P56yc4gfsZVES
KA9v+yY2/l45L8d/WUkUi0YXomn6hyBGI7JrBLq0CX37GEYP6O9rrKipfz73XfO7
JIGzOKZlljb/D9RX/g7nRbCn+3EtH7xnk+TK/50euEKw8SMUg147sJTcpQmv6UzZ
cM4JgL0HbHVCojV4C/plELwMddALOFeYQzTif6sMRPf+3DSj8frbInjChC3yOLy0
6br92KFom17EIj2CAcoeq7UPhi2oouYBwPxh5ytdehJkoo+sN7RIWua6P2WSmon5
U888cSylXC0+ADFdgLX9K2zrDVYUG1vo8CX0vzxFBaHwN6Px26fhIT1/hYUHQR1z
VfNDcyQmXqkOnZvvoMfz/Q0s9BhFJ/zU6AgQbIZE/hm1spsfgvtsD1frZfygXJ9f
irP+MSAI80xHSf91qSRZOj4Pl3ZJNbq4yYxv0b1pkMqeGdjdCYhLU+LZ4wbQmpCk
SVe2prlLureigXtmZfkqevRz7FrIZiu9ky8wnCAPwC7/zmS18rgP/17bOtL4/iIz
QhxAAoAMWVrGyJivSkjhSGx1uCojsWfsTAm11P7jsruIL61ZzMUVE2aM3Pmj5G+W
9AcZ58Em+1WsVnAXdUR//bMmhyr8wL/G1YO1V3JEJTRdxsSxdYa4deGBBY/Adpsw
24jxhOJR+lsJpqIUeb999+R8euDhRHG9eFO7DRu6weatUJ6suupoDTRWtr/4yGqe
dKxV3qQhNLSnaAzqW/1nA3iUB4k7kCaKZxhdhDbClf9P37qaRW467BLCVO/coL3y
Vm50dwdrNtKpMBh3ZpbB1uJvgi9mXtyBOMJ3v8RZeDzFiG8HdCtg9RvIt/AIFoHR
H3S+U79NT6i0KPzLImDfs8T7RlpyuMc4Ufs8ggyg9v3Ae6cN3eQyxcK3w0cbBwsh
/nQNfsA6uu+9H7NhbehBMhYnpNZyrHzCmzyXkauwRAqoCbGCNykTRwsur9gS41TQ
M8ssD1jFheOJf3hODnkKU+HKjvMROl1DK7zdmLdNzA1cvtZH/nCC9KPj1z8QC47S
xx+dTZSx4ONAhwbS/LN3PoKtn8LPjY9NP9uDWI+TWYquS2U+KHDrBDlsgozDbs/O
jCxcpDzNmXpWQHEtHU7649OXHP7UeNST1mCUCH5qdank0V1iejF6/CfTFU4MfcrG
YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
=0YYh
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -1,41 +1,41 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=J9CI
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
=lSMJ
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

View file

@ -1,53 +0,0 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${server_name};
ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
root /opt/freescout/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-handler;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include params/fastcgi;
}
# Uncomment this location if you want to improve attachments downloading speed.
# Also make sure to set APP_DOWNLOAD_ATTACHMENTS_VIA=nginx in the .env file.
#location ^~ /storage/app/attachment/ {
# internal;
# alias /var/www/html/storage/app/attachment/;
#}
location ~* ^/storage/attachment/ {
expires 1M;
access_log off;
try_files $uri $uri/ /index.php?$query_string;
}
location ~* ^/(?:css|js)/.*\.(?:css|js)$ {
expires 2d;
access_log off;
add_header Cache-Control "public, must-revalidate";
}
# The list should be in sync with /storage/app/public/uploads/.htaccess and /config/app.php
location ~* ^/storage/.*\.((?!(jpg|jpeg|jfif|pjpeg|pjp|apng|bmp|gif|ico|cur|png|tif|tiff|webp|pdf|txt|diff|patch|json|mp3|wav|ogg|wma)).)*$ {
add_header Content-disposition "attachment; filename=$2";
default_type application/octet-stream;
}
location ~* ^/(?:css|fonts|img|installer|js|modules|[^\\\]+\..*)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~ /\. {
deny all;
}
}

View file

@ -1,22 +0,0 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${server_name};
ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_read_timeout 3600;
proxy_pass http://127.0.0.1:8123;
}
}

View file

@ -1,43 +0,0 @@
# Upstream to abstract backend connection(s) for php
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${server_name};
root ${root};
index index.php;
ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location / {
# This is cool because no php is touched for static content.
# include the "?$args" part so non-default permalinks doesn't break when using query string
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include params/fastcgi;
fastcgi_intercept_errors on;
fastcgi_pass php-handler;
# The following parameter can be also included in fastcgi_params file
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}

View file

@ -1,10 +0,0 @@
{
'supergroups': [
'webserver',
],
'bundles': [
'freescout',
'php',
'postgresql',
],
}

View file

@ -1,8 +0,0 @@
{
'bundles': [
'letsencrypt',
'mariadb',
'nginx',
'wordpress',
],
}

Some files were not shown because too many files have changed in this diff Show more