diff --git a/hermes-service.service b/hermes-service.service new file mode 100644 index 0000000..4a2af3e --- /dev/null +++ b/hermes-service.service @@ -0,0 +1,27 @@ +[Unit] +Description=Hermes Service - AI Agent HTTP API +After=network.target + +[Service] +Type=simple +User=hermesai +Group=hermesai +WorkingDirectory=/d/hermesai/repos/hermes-service +ExecStart=/usr/bin/python3 /d/hermesai/repos/hermes-service/main.py +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +# Environment +Environment="HOME=/d/hermesai" +Environment="PYTHONUNBUFFERED=1" + +# Security hardening +NoNewPrivileges=true +ProtectSystem=strict +ProtectHome=read-only +ReadWritePaths=/d/hermesai/users /d/hermesai/repos/hermes-service/data + +[Install] +WantedBy=multi-user.target diff --git a/install-service.py b/install-service.py new file mode 100644 index 0000000..dc0b3b3 --- /dev/null +++ b/install-service.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +""" +Generate systemd service file for hermes-service. +Usage: python3 install-service.py [--user USER] [--group GROUP] [--install] +""" + +import os +import sys +import argparse +import shutil + +# Resolve paths dynamically +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +SERVICE_MODULE = SCRIPT_DIR +MAIN_PY = os.path.join(SERVICE_MODULE, "main.py") + +# Auto-detect Python venv if it exists +VENV_PYTHON = os.path.join(SERVICE_MODULE, ".venv", "bin", "python3") +SYSTEM_PYTHON = shutil.which("python3") + +if os.path.exists(VENV_PYTHON): + PYTHON_EXEC = VENV_PYTHON +else: + PYTHON_EXEC = SYSTEM_PYTHON or "/usr/bin/python3" + +PORT = 9121 +USER = "hermesai" +GROUP = "hermesai" + +SERVICE_CONTENT_TEMPLATE = """[Unit] +Description=Hermes Service - AI Agent HTTP API +After=network.target + +[Service] +Type=simple +User={user} +Group={group} +WorkingDirectory={workdir} +ExecStart={python} {main_py} +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +# Environment +Environment="HOME={home}" +Environment="PYTHONUNBUFFERED=1" + +# Security hardening +NoNewPrivileges=true +ProtectSystem=strict +ProtectHome=read-only +ReadWritePaths={users_path} {data_path} + +[Install] +WantedBy=multi-user.target +""" + + +def generate(args): + parser = argparse.ArgumentParser(description="Generate hermes-service systemd service") + parser.add_argument("--user", default=USER, help="Run as this user (default: hermesai)") + parser.add_argument("--group", default=GROUP, help="Run as this group (default: hermesai)") + parser.add_argument("--port", type=int, default=PORT, help="Service port (default: 9121)") + parser.add_argument("--install", action="store_true", help="Copy to /etc/systemd/system and enable") + parser.add_argument("--output", default=None, help="Output file path (default: ./hermes-service.service)") + args = parser.parse_args() + + return args + + +def main(): + args = generate(sys.argv[1:]) + + user = args.user + group = args.group + port = args.port + install = args.install + service_name = "hermes-service" + output = args.output or os.path.join(SERVICE_MODULE, f"{service_name}.service") + + # Validate + if not os.path.exists(MAIN_PY): + print(f"ERROR: main.py not found at {MAIN_PY}") + sys.exit(1) + + # Generate service content + content = SERVICE_CONTENT_TEMPLATE.format( + user=user, + group=group, + workdir=SERVICE_MODULE, + python=PYTHON_EXEC, + main_py=MAIN_PY, + home=os.environ.get('HOME', '/home/hermesai'), + users_path=os.path.join(os.environ.get('HOME', '/home/hermesai'), 'users'), + data_path=os.path.join(SERVICE_MODULE, 'data'), + ) + + # Write service file + with open(output, "w") as f: + f.write(content) + + print(f"Service file written to: {output}") + print(f" Python: {PYTHON_EXEC}") + print(f" WorkingDir: {SERVICE_MODULE}") + print(f" User/Group: {user}/{group}") + print(f" Port: {port}") + print(f" Main: {MAIN_PY}") + print() + + if install: + dest = f"/etc/systemd/system/{service_name}.service" + if os.geteuid() != 0: + print(f"ERROR: --install requires root privileges. Run with sudo.") + sys.exit(1) + + shutil.copy2(output, dest) + os.chmod(dest, 0o644) + print(f"Installed to: {dest}") + print() + print("Next steps:") + print(f" sudo systemctl daemon-reload") + print(f" sudo systemctl enable {service_name}") + print(f" sudo systemctl start {service_name}") + print(f" sudo systemctl status {service_name}") + else: + print("To install and enable:") + print(f" sudo python3 {os.path.basename(__file__)} --install") + + +if __name__ == "__main__": + main()