#!/usr/bin/env python3 import sys, os, shutil, platform, subprocess, re, argparse # only support linux / Debian, Ubuntu / nginx, apache2 platform_system_support = ['Linux'] platform_version_support = ['DEBIAN', 'UBUNTU'] server_support = ['NGINX', "APACHE2"] html_dir_path = "" logs_dir_path = "" re_domain = r'^(?=.{1,253}$)(?!.*\.\..*)(?!\..*)([a-zA-Z0-9-]{,63}\.){,127}[a-zA-Z0-9-]{1,63}$' def y_n_question(question_str: str) -> bool: yes = {'yes','y', 'ye', ''} no = {'no','n'} while True: sys.stdout.write(question_str + " [Y/n]: ") choice = input().lower() if choice in yes: return True elif choice in no: return False else: sys.stdout.write("\nPlease respond with 'yes' or 'no'\n") continue def check_server_version() -> str: a = subprocess.call("sudo apache2 -v", shell=True) if not a: return "APACHE2" n = subprocess.call("sudo nginx -v", shell=True) if not n: return "NGINX" return None def check_distribution_version() -> str: dist = platform.version().lower() if 'debian' in dist: return "DEBIAN" if 'ubuntu' in dist: return "UBUNTU" return None def sanity_check_system(): # check platform if platform.system() not in platform_system_support: sys.exit(f"Platform {platform.system()} not supported. Aborting...") dist = check_distribution_version() if not dist: sys.exit("OS distribution not supported. Aborting...") sv = check_server_version() if not sv: sys.exit("Server distribution not supported. Aborting...") if dist in platform_version_support and sv == "APACHE2": # check apache2 (ubuntu or debian) u = os.path.exists('/etc/apache2/sites-available/') if not u: sys.exit(f"Apache2 ({dist}) not installed on your system. Aborting...") if dist in platform_version_support and sv in server_support: # check apache2 (ubuntu or debian) u = os.path.exists(f'/etc/{sv.lower()}/sites-available/') if not u: sys.exit(f"{sv} ({dist}) not installed on your system. Aborting...") return sv, dist def sanity_check_platform(): global html_dir_path, logs_dir_path usr = os.getlogin() html_dir_path = os.path.join('/home', usr, 'html') logs_dir_path = os.path.join('/home', usr, 'logs') if not os.path.exists(html_dir_path): if y_n_question("Path - " + html_dir_path + ' - does not exists. Create it?'): os.makedirs(html_dir_path) else: sys.exit("Can not configure platform. Aborting...") if not os.path.exists(logs_dir_path): if y_n_question("Path - " + logs_dir_path + ' - does not exists. Create it?'): os.makedirs(logs_dir_path) else: sys.exit("Can not configure platform. Aborting...") def vhost_add(domain: str, sv: str, dist: str): global html_dir_path, logs_dir_path, re_domain print(" adding vhost domain - " + domain) if re.match(re_domain, domain) is None: print("Invalid domain name: " + domain + " -> pass") www = os.path.join(html_dir_path, domain) os.makedirs(www, exist_ok=True) logs = os.path.join(logs_dir_path, domain) os.makedirs(logs, exist_ok=True) # debug: this file might not be here........... if sv == "APACHE2": with open('vhost_tmpl_apache2') as vhost_tmpl_fp: vhost_tmpl = vhost_tmpl_fp.read() elif sv == "NGINX": with open('vhost_tmpl_nginx') as vhost_tmpl_fp: vhost_tmpl = vhost_tmpl_fp.read() else: sys.exit(f"{sv} not recognised. Aborting...") usr = os.getlogin() vhost = vhost_tmpl.replace("%domain?", domain).replace("%user?", usr) # debug: write file directly to '/etc/apache2/sites-available/' ? vhost_file = os.path.join(www, domain + '.conf') with open(vhost_file, 'w+') as vhost_file_fp: vhost_file_fp.write(vhost) # debug: this file might not be here........... if y_n_question("Create index.html placeholder?") shutil.copyfile('c.txt', os.path.join(www, 'index.html')) # check is ssl cert exists cert = os.path.join('/etc/letsencrypt/live', domain) if not os.path.exists(cert): print(" warning: SSL certificates do not exist for domain - " + domain + " - this will problaly cause errors...") print(" warning: Please make sure to place them in " + cert + " to allow secure https connection to your site.") # mv conf file to apache? if dist in platform_version_support: if y_n_question(f"Move {vhost_file} to /etc/{sv.lower()}/sites-available/ ?"): vhost_conf_file = os.path.join(f'/etc/{sv.lower()}/sites-available/', f'{domain}.conf') subprocess.call(['sudo', 'mv', vhost_file, vhost_conf_file]) # enable site? if y_n_question(f"Enable {domain}?"): if sv == "APACHE2": subprocess.call(['sudo', 'a2ensite', f'{domain}.conf']) if sv == "NGINX": vhost_conf_file_enabled = os.path.join(f'/etc/nginx/sites-enabled/', f'{domain}.conf') subprocess.call(['sudo', 'ln', '-s', vhost_conf_file, vhost_conf_file_enabled]) def vhost_remove(domain: str, sv: str, dist: str): print(" removing domain — " + domain) vhost_conf_file = os.path.join(f'/etc/{sv.lower()}/sites-available/{domain}.conf') if os.path.exists(vhost_conf_file): if y_n_question("Delete " + vhost_conf_file + " ?"): subprocess.call(['sudo', 'rm', vhost_conf_file]) if sv == "APACHE2": subprocess.call(['sudo', 'a2dissite', vhost_conf_file]) if sv == "NGINX": vhost_conf_file_enabled = os.path.join(f'/etc/nginx/sites-enabled/', f'{domain}.conf') subprocess.call(['sudo', 'rm', vhost_conf_file_enabled]) www = os.path.join(html_dir_path, domain) if os.path.exists(www): if y_n_question("Delete " + www + " ?"): subprocess.call(['sudo', 'rm', '-r', www]) logs = os.path.join(logs_dir_path, domain) if os.path.exists(logs): if y_n_question("Delete " + logs + " ?"): subprocess.call(['sudo', 'rm', '-r', logs]) if __name__ == "__main__": p = argparse.ArgumentParser(description='vhost helper') p.add_argument('domain', metavar="domain", help="vhost domain(s)", nargs="+") g = p.add_mutually_exclusive_group() g.add_argument('-a', '--add', action='store_true', help="adds vhost for given domain(s)") g.add_argument('-r', '--remove', action='store_true', help="removes vhost for given domain(s)") args = p.parse_args() print('1. sanity checks') sv, dist = sanity_check_system() sanity_check_platform() print('2. vhosting') for d in args.domain: if args.add: vhost_add(d, sv, dist) elif args.remove: vhost_remove(d, sv, dist) if y_n_question(f"Reload {sv}?"): subprocess.call(['sudo', 'service', sv.lower(), 'reload']) print('done.')