diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/scripts/setup_wordpress.py b/scripts/setup_wordpress.py new file mode 100644 index 0000000..699f6df --- /dev/null +++ b/scripts/setup_wordpress.py @@ -0,0 +1,27 @@ +import argparse + +from wordperchta.alpine_system import AlpineSystem +from wordperchta.domain import Domain + + +def main(): + parser = argparse.ArgumentParser(description="Setup WordPress with Nginx") + parser.add_argument("domain", help="Primary domain name") + parser.add_argument( + "--vanity", nargs="*", default=[], help="Additional vanity hosts" + ) + args = parser.parse_args() + + alpine_system = AlpineSystem() + alpine_system.setup_system() + + domain = Domain(args.domain, args.vanity) + domain.setup(alpine_system) + + print( + "Setup complete. Complete WordPress installation on the web." + ) + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..a40494c --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup, find_packages + +setup( + name="wordperchta", + version="0.0", + packages=find_packages(where="src"), + package_dir={"": "src"}, + install_requires=[ + # List your dependencies here + ], + scripts=["scripts/setup_wordpress.py"], +) diff --git a/src/wordperchta/__init__.py b/src/wordperchta/__init__.py new file mode 100644 index 0000000..e106af3 --- /dev/null +++ b/src/wordperchta/__init__.py @@ -0,0 +1,2 @@ +from .alpine_system import AlpineSystem +from .domain import Domain diff --git a/src/wordperchta/alpine_system.py b/src/wordperchta/alpine_system.py new file mode 100644 index 0000000..9cabb44 --- /dev/null +++ b/src/wordperchta/alpine_system.py @@ -0,0 +1,52 @@ +import subprocess +import sys +import os + +class AlpineSystem: + def __init__(self): + self.required_packages = ['nginx', 'php-fpm', 'mariadb', 'certbot', 'certbot-nginx'] + self.services = ['nginx', 'mariadb', 'php-fpm7'] + + def run_command(self, command): + try: + subprocess.run(command, check=True, shell=True) + except subprocess.CalledProcessError as e: + print(f"Error running command: {command}") + print(f"Error details: {e}") + sys.exit(1) + + def is_installed(self, package): + return subprocess.run(['which', package], stdout=subprocess.DEVNULL).returncode == 0 + + def install_package(self, package): + print(f"Installing {package}...") + self.run_command(f"apk add {package}") + + def secure_mariadb(self): + print("Securing MariaDB...") + self.run_command("mysql_secure_installation") + + def secure_nginx(self): + print("Securing Nginx...") + nginx_conf = "/etc/nginx/nginx.conf" + with open(nginx_conf, 'a') as f: + f.write("\nserver_tokens off;\n") + self.run_command("nginx -t && rc-service nginx reload") + + def setup_system(self): + for package in self.required_packages: + if not self.is_installed(package): + self.install_package(package) + + for service in self.services: + self.run_command(f"rc-service {service} start") + self.run_command(f"rc-update add {service}") + + if not os.path.exists("/root/.my.cnf"): + self.secure_mariadb() + self.secure_nginx() + + self.setup_ssl_renewal() + + def setup_ssl_renewal(self): + self.run_command("(crontab -l 2>/dev/null; echo \"0 12 * * * /usr/bin/certbot renew --quiet\") | crontab -") \ No newline at end of file diff --git a/src/wordperchta/domain.py b/src/wordperchta/domain.py new file mode 100644 index 0000000..ede98d9 --- /dev/null +++ b/src/wordperchta/domain.py @@ -0,0 +1,68 @@ +import os +import random +import string + +class Domain: + def __init__(self, name, vanity_hosts=None): + self.name = name + self.vanity_hosts = vanity_hosts or [] + self.db_name = f"wp_{name.replace('.', '_')}" + self.db_user = f"wpuser_{name.replace('.', '_')}" + self.db_pass = self.generate_password() + self.wp_dir = f"/var/www/wordpress_{name}" + + @staticmethod + def generate_password(length=16): + return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length)) + + def setup_database(self, system): + system.run_command(f"mysql -e \"CREATE DATABASE {self.db_name}; \ + CREATE USER '{self.db_user}'@'localhost' IDENTIFIED BY '{self.db_pass}'; \ + GRANT ALL PRIVILEGES ON {self.db_name}.* TO '{self.db_user}'@'localhost'; \ + FLUSH PRIVILEGES;\"") + + def setup_wordpress(self, system): + if not os.path.exists(self.wp_dir): + system.run_command(f"wget -q -O /tmp/wordpress.tar.gz https://wordpress.org/latest.tar.gz") + system.run_command(f"tar -xzf /tmp/wordpress.tar.gz -C /tmp") + system.run_command(f"mv /tmp/wordpress {self.wp_dir}") + system.run_command(f"chown -R nginx:nginx {self.wp_dir}") + + def configure_nginx(self, system): + server_names = f"{self.name} www.{self.name} " + " ".join(f"{host}.{self.name}" for host in self.vanity_hosts) + nginx_conf = f"/etc/nginx/conf.d/{self.name}.conf" + with open(nginx_conf, 'w') as f: + f.write(f""" +server {{ + listen 80; + server_name {server_names}; + root {self.wp_dir}; + index index.php; + + location / {{ + try_files $uri $uri/ /index.php?$args; + }} + + location ~ \\.php$ {{ + fastcgi_pass unix:/var/run/php-fpm7.sock; + fastcgi_index index.php; + include fastcgi.conf; + }} +}} +""") + + def setup_ssl(self, system): + ssl_domains = f"-d {self.name} -d www.{self.name} " + " ".join(f"-d {host}.{self.name}" for host in self.vanity_hosts) + system.run_command(f"certbot --nginx {ssl_domains}") + + def add_vanity_host(self, host): + if host not in self.vanity_hosts: + self.vanity_hosts.append(host) + print(f"Added vanity host: {host}.{self.name}") + + def setup(self, system): + self.setup_database(system) + self.setup_wordpress(system) + self.configure_nginx(system) + self.setup_ssl(system) + print(f"WordPress setup completed for {self.name}") \ No newline at end of file