Dawn of the YoLD: Webstack

Die Einrichtung meines Webstacks unter Ubuntu ist ein gelöstes Problem: Die Inhalte (/var/www/) und Konfigurationsdateien (/etc/uwsgi/apps-enabled bzw. /etc/nginx) können unverändert vom lokalen Webserver übernommen werden, wobei das Verzeichnis /var/www dem Benutzer www-data zu eigen sein sollte (mit Ausnahme des DB-Dumps /var/www/djangoproject3/dbdump/site.sql). Der Symlink zur nginx-Standardkonfiguration (/etc/nginx/sites-enabled/default) muss entfernt und die Servernamen in /etc/nginx/sites-enabled/* müssen angepasst werden. Schließlich müssen dieselben Servernamen in /etc/hosts eingetragen und die Dienste nginx, PostgreSQL und uwsgi neu gestartet werden (service restart nginx|postgresql|uwsgi). Wegen der Einrichtung eines zusätzlichen synchronisationsbedürftigen Webservers muss das Synchronisationsskript flexibilisiert werden:

#!/usr/local/bin/python3 import os import operator import subprocess import argparse import paramiko local_dir = '/home/snafu/djangosite/dbdump/' remote_dir = '/var/www/djangosite/dbdump/' db = 'djangosite' dbuser = 'snafu' extension = '.sql' dumpfile = local_dir + db + extension targetfile = remote_dir + db + extension class ServerProfile: def __init__(self, server_name, actions): self.name = server_name self.actions = actions self.actions.sort() configparser = paramiko.SSHConfig() configparser.parse(open('/home/snafu/.ssh/config')) self.ssh_config = configparser.lookup(self.name) self.ssh_key = paramiko.ECDSAKey.from_private_key(open(self.ssh_config['identityfile'][0])) def print_status(self, return_code): if return_code == 0: print('done.') else: print('failed!') def dump_db(self): print('Dumping local database...') with open(dumpfile, 'w') as writefile: completed_process = subprocess.run(['pg_dump', '-E', 'UTF8', '-c', db], stdout=writefile) self.print_status(completed_process.returncode) def transfer_db(self): print(f'Sending database dump to {self.name} ...') transport = paramiko.Transport((self.ssh_config['hostname'],int(self.ssh_config['port']))) transport.connect(username=self.ssh_config['user'], pkey=self.ssh_key) sftp = paramiko.SFTPClient.from_transport(transport) try: sftp.put(dumpfile,targetfile) self.print_status(0) except: self.print_status(1) if sftp: sftp.close() if transport: transport.close() def update_db(self): print(f'Updating remote database on {self.name} ...') client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(self.ssh_config['hostname'], username=self.ssh_config['user'], port=self.ssh_config['port'], key_filename=self.ssh_config['identityfile'][0]) stdin, stdout, stderr = client.exec_command(f'psql -U {dbuser} {db} < {targetfile}') return_code = stdout.channel.recv_exit_status() self.print_status(return_code) client.close() def work(self): dispatcher = { 'd' : self.dump_db, 't' : self.transfer_db, 'u' : self.update_db } if self.actions: for action in self.actions: dispatcher[action]() else: print(f'Nothing to do for {self.name}.') def main(): p = argparse.ArgumentParser(description='Synchronize website database') p.add_argument('server', type=str, choices=['firstserver', 'secondserver'], help='the target server') p.add_argument('-d', '--dump', dest='actions', action='append_const', const='d') p.add_argument('-t', '--transfer', dest='actions', action='append_const', const='t') p.add_argument('-u', '--update', dest='actions', action='append_const', const='u') arguments = p.parse_args() server = ServerProfile(arguments.server, arguments.actions) server.work() if __name__=='__main__': main()

Das synchronisierende Nutzerkonto benötigt offensichtlich Schreibrechte auf den Pfad targetfile, aber die Überarbeitung nützt trotzdem wenig, wenn man vergisst, die PostgreSQL-Authentifizierung in /etc/postgresql/14/main/pg_hba.conf für lokale Nutzerinnen von peer auf scram-sha-256 umzustellen:

2022-10-08 18:05:49.435 CEST [16140] snafu@djangosite DETAIL: Connection matched pg_hba.conf line 95: "local all all peer" 325 2022-10-08 18:14:46.258 CEST [16579] snafu@djangosite LOG: provided user name (snafu) and authenticated user name (jan) do not match 326 2022-10-08 18:14:46.258 CEST [16579] snafu@djangosite FATAL: Peer authentication failed for user "snafu"

Jenseits des Webstacks ist für authentication unter Ubuntu ein Seepferdchen zuständig.