diff --git a/ssl-update.py b/ssl-update.py index facb7ae..1809098 100755 --- a/ssl-update.py +++ b/ssl-update.py @@ -40,8 +40,8 @@ restart_delay = { } pfx_key_path = { - 'plex': '/data/plex/certs/certificate.pfx', - 'jellyfin': '/data/jellyfin/ssl/jellyfin.pfx', + 'plex': pathlib.Path('/data/plex/certs/certificate.pfx'), + 'jellyfin': pathlib.Path('/data/jellyfin/ssl/jellyfin.pfx'), } # Cert owning user if different than the name of the service @@ -163,7 +163,7 @@ def pfx_gen(service): except KeyError: sys.exit(f'{service} has no defined private key path.') - cmd = ['/usr/bin/openssl', 'pkcs12', '-export', '-out', pkp, + cmd = ['/usr/bin/openssl', 'pkcs12', '-export', '-out', str(pkp), '-inkey', f'/etc/letsencrypt/live/{service}.{domain}/privkey.pem', '-in', f'/etc/letsencrypt/live/{service}.{domain}/cert.pem', '-certfile', f'/etc/letsencrypt/live/{service}.{domain}/chain.pem'] @@ -234,15 +234,24 @@ def run_cert_bot(fqdn, service, challenge_path, decrypt_pp): log.info(f'certbot cmd: "{" ".join(cmd)}"') cb = pexpect.spawnu(' '.join(cmd)) cb.logfile = sys.stderr + do_update = True + matches = [ + 'Create a file containing just this data:\r\n\r\n([^\r]+)\r', + ('You have an existing certificate that has exactly the ' + "same domains or certificate name you requested and isn't " + 'close to expiry'), + '(U)pdate key type/(K)eep existing key type:', + 'no action taken', + pexpect.TIMEOUT, + pexpect.EOF] while True: - res = cb.expect( - ['Create a file containing just this data:\r\n\r\n([^\r]+)\r', - ('You have an existing certificate that has exactly the ' - "same domains or certificate name you requested and isn't " - 'close to expiry'),'(U)pdate key type/(K)eep existing key type:', - pexpect.TIMEOUT, pexpect.EOF], timeout=20) - if res > 2: + res = cb.expect(matches, timeout=20) + print(f'\nresult: {matches[res]}, {res}') + if res > 3: sys.exit('Timed out') + if res == 3: + do_update = False + break if res == 2: cb.sendline('U') continue @@ -251,74 +260,76 @@ def run_cert_bot(fqdn, service, challenge_path, decrypt_pp): res = cb.expect_exact(['cancel):', pexpect.TIMEOUT, pexpect.EOF]) if res > 0: sys.exit('Timed out in setup with existing cert') - cb.sendline('2') - res = cb.expect( - ['Create a file containing just this data:\r\n\r\n([^\r]+)\r', - pexpect.TIMEOUT, pexpect.EOF], timeout=20) - if res > 1: - sys.exit('Timed out') + cb.sendline('1') + continue + # res = cb.expect( + # ['Create a file containing just this data:\r\n\r\n([^\r]+)\r', + # pexpect.TIMEOUT, pexpect.EOF], timeout=20) + # if res > 1: + # sys.exit('Timed out') if res == 0: break - data = cb.match.group(1) - log.info(f'secret data: {data}') - log.info('the data string and location for the shared secret are known') - long_match = ('And make it available on your web server at this URL:' - '\r\n\r\nhttp://%s/.well-known/acme-challenge/([^\r]+)\r') - res = cb.expect([long_match % (fqdn,), pexpect.TIMEOUT, pexpect.EOF]) - if res > 0: - sys.exit('Timed out') - filename = cb.match.group(1) - log.info(f'filename of secret: {filename}') - res = cb.expect(['Press Enter to Continue', pexpect.EOF], timeout=0) + if do_update: + data = cb.match.group(1) + log.info(f'secret data: {data}') + log.info('the data string and location for the shared secret are known') + long_match = ('And make it available on your web server at this URL:' + '\r\n\r\nhttp://%s/.well-known/acme-challenge/([^\r]+)\r') + res = cb.expect([long_match % (fqdn,), pexpect.TIMEOUT, pexpect.EOF]) + if res > 0: + sys.exit('Timed out') + filename = cb.match.group(1) + log.info(f'filename of secret: {filename}') + res = cb.expect(['Press Enter to Continue', pexpect.EOF], timeout=0) - data_file = challenge_path / pathlib.Path(filename) - try: - with open(data_file, 'w') as f: - f.write(data) - except: - sys.exit(f'Failed to write {data_file}') - log.info('created secret file with secret data') - data_file.chmod(0o644) - log.info('and chmodded') + data_file = challenge_path / pathlib.Path(filename) + try: + with open(data_file, 'w') as f: + f.write(data) + except: + sys.exit(f'Failed to write {data_file}') + log.info('created secret file with secret data') + data_file.chmod(0o644) + log.info('and chmodded') - symlink_name = pathlib.Path(f'{service}-le') - log.info(f'nginx symlink: {symlink_name}') - nx_conf = pathlib.Path('/etc/nginx') - avail_path = nx_conf / pathlib.Path('sites-available') - enabled_path = nx_conf / pathlib.Path('sites-enabled') + symlink_name = pathlib.Path(f'{service}-le') + log.info(f'nginx symlink: {symlink_name}') + nx_conf = pathlib.Path('/etc/nginx') + avail_path = nx_conf / pathlib.Path('sites-available') + enabled_path = nx_conf / pathlib.Path('sites-enabled') - service_available_file = avail_path / symlink_name - log.info(f'nginx service avail symlink: {service_available_file}') - service_enabled_symlink = enabled_path / symlink_name - log.info(f'nginx service enabled symlink: {service_enabled_symlink}') - if not service_enabled_symlink.is_symlink(): - service_enabled_symlink.symlink_to(service_available_file) - log.info('created symlink to enable service') + service_available_file = avail_path / symlink_name + log.info(f'nginx service avail symlink: {service_available_file}') + service_enabled_symlink = enabled_path / symlink_name + log.info(f'nginx service enabled symlink: {service_enabled_symlink}') + if not service_enabled_symlink.is_symlink(): + service_enabled_symlink.symlink_to(service_available_file) + log.info('created symlink to enable service') - log.info(f'open port 80 to {service}') - firewall_mod('HTTP_UP', service, decrypt_pp) - restart('nginx') + log.info(f'open port 80 to {service}') + firewall_mod('HTTP_UP', service, decrypt_pp) + restart('nginx') - cb.sendline() - log.info(f'sent to certbot to continue process') - res = cb.expect([pexpect.EOF]) - log.info(f'cerbot completed. final output: {cb.before}') + cb.sendline() + log.info(f'sent to certbot to continue process') + res = cb.expect([pexpect.EOF]) + log.info(f'cerbot completed. final output: {cb.before}') - output_text = str(cb.before) - if 'failed' in output_text: - sys.exit('Something went wrong') + output_text = str(cb.before) + if 'failed' in output_text: + sys.exit('Something went wrong') - log.info(f'close port 80 to {service}') - firewall_mod('HTTP_DOWN', service, decrypt_pp) + log.info(f'close port 80 to {service}') + firewall_mod('HTTP_DOWN', service, decrypt_pp) - service_enabled_symlink.unlink() - if service_enabled_symlink.is_symlink(): - sys.exit(f'Could not unlink {service_enabled_symlink}') - log.info('created symlink to enable service') - log.info('removed symlink in nginx to disable HTTP') + service_enabled_symlink.unlink() + if service_enabled_symlink.is_symlink(): + sys.exit(f'Could not unlink {service_enabled_symlink}') + log.info('created symlink to enable service') + log.info('removed symlink in nginx to disable HTTP') - restart('nginx') + restart('nginx') key_path = pathlib.Path('/etc/letsencrypt') live = key_path / pathlib.Path(f'live/{service}.{domain}') @@ -372,9 +383,6 @@ def main(args): fqdn = f'{service}.{domain}' log.info(f'fqdn: {fqdn}') - # Dry run: - # cmd = ['/usr/bin/certbot', '--dry-run', 'certonly', '--manual', '-d', fqdn] - # Real run: run_cert_bot(fqdn, service, challenge_path, decrypt_pp) restart(service) diff --git a/update_all b/update_all index 96df15e..51bb7d7 100755 --- a/update_all +++ b/update_all @@ -3,9 +3,9 @@ declare -a services services+=('git') services+=('plex') -# services+=('jellyfin') +services+=('jellyfin') services+=('photoprism') -services+=('nextcloud') +# services+=('nextcloud') services+=('read') services+=('www') services+=('chat')