diff --git a/README.md b/README.md index 6e64422..b7528e5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,155 @@ Wenn über http geklont wird muss lokal der [git-credential-oauth](https://githu ## Konfiguration -TODO +Erfolgt über zwei yaml files. Zu konfigurieren ist die Verbindung zur Datenbank und die Konfiguration der einzelnen Hotels. In zukunft kommt vermutlich auch noch die Push URL hinzu. + +```yaml +database: + url: "sqlite+aiosqlite:///alpinebits.db" # For local dev, use SQLite. For prod, override with PostgreSQL URL. + # url: "postgresql://user:password@host:port/dbname" # Example for Postgres + +alpine_bits_auth: + - hotel_id: "123" + hotel_name: "Frangart Inn" + username: "alice" + password: !secret ALICE_PASSWORD + - hotel_id: "456" + hotel_name: "Bemelmans" + username: "bob" + password: !secret BOB_PASSWORD +``` + +!secret verweist auf einen Eintrag in secrets.yaml. Diese Datei wird aus Sicherheitsgründen nicht auf die Repository hochgeladen. In secrets.yaml können passwörter folgendermaßen angegeben werden + +```yaml +ALICE_PASSWORD: "supersecretpassword123" +``` + +## Deployment + +Die Applikation wird in einem Dockercontainer deployed. Um das Container Image zu erstellen ist folgender Befehl notwendig + +```bash +uv sync +docker build . -t gitea.linter-home.com/jonas/asa_api:master +``` +Dieser Befehl muss im Wurzelverzeichnis der Repository ausgeführt werden. `pwd` sollte irgendwas/alpinebits_python ergeben. Der Punkt hinter dem docker build befehl verweißt nämlich auf das lokale Dockerfile. "-t" steht für tag. In diesem Beispiel wird das Image mit dem Tag `gitea.linter-home.com/jonas/asa_api:master` versehen. + +Ideal wäre eine Build Pipeline in Gitea selbst aber dies aufzusetzen ist etwas schwierig und es ist gut möglich das die Hetzner VM das nicht herhat. Lokal bei mir zuhause ist dies aufgesetzt. War alles andere als leicht. + +Am besten einfach direkt auf dem Zielsystem den Container bauen und im Docker Compose File dann auf dieses Image referenzieren. + + +### Docker Compose Beispiel mit Traefik Reverse Proxy + +```yaml +services: + asa_connector: + image: gitea.linter-home.com/jonas/asa_api:master + container_name: asa_connector + restart: unless-stopped + + # Environment variables via .env file + env_file: + - asa_connector.env + + networks: + - external + + # Only expose internally - Traefik will handle external access + expose: + - "8000" + + user: "1000:1000" # Run as user with UID 1000 and GID 1000 + + environment: + - ALPINEBITS_CONFIG_DIR=/config + + volumes: + - /home/jonas/asa_connector_logs:/app/src/logs + - /home/jonas/alpinebits_config:/config + + + + # Traefik labels for automatic service discovery + labels: + - "traefik.enable=true" + # API router - handles /api/* paths on 99tales.net + - "traefik.http.routers.asa_connector.rule=Host(`99tales.net`) && PathPrefix(`/api`)" + - "traefik.http.routers.asa_connector.entrypoints=https" + - "traefik.http.routers.asa_connector.tls.certresolver=letsencrypt" + - "traefik.http.services.asa_connector.loadbalancer.server.port=8000" + - "traefik.http.routers.asa_connector.priority=100" + + # Redirect middleware for non-API paths + - "traefik.http.middlewares.redirect-to-99tales-it.redirectregex.regex=^https://99tales\\.net/(.*)$$" + - "traefik.http.middlewares.redirect-to-99tales-it.redirectregex.replacement=https://99tales.it/$${1}" + - "traefik.http.middlewares.redirect-to-99tales-it.redirectregex.permanent=true" + + # Catch-all router for non-API paths on 99tales.net (lower priority) + - "traefik.http.routers.redirect-router.rule=Host(`99tales.net`)" + - "traefik.http.routers.redirect-router.entrypoints=https" + - "traefik.http.routers.redirect-router.tls.certresolver=letsencrypt" + - "traefik.http.routers.redirect-router.middlewares=redirect-to-99tales-it" + - "traefik.http.routers.redirect-router.service=noop@internal" + - "traefik.http.routers.redirect-router.priority=1" + + dockerproxy: + image: ghcr.io/tecnativa/docker-socket-proxy:latest + container_name: dockerproxy + restart: unless-stopped + environment: + CONTAINERS: 1 # read only + POST: 0 + + networks: + - external + + volumes: + - /var/run/docker.sock:/var/run/docker.sock + + + traefik: + image: traefik:latest + container_name: traefik + restart: unless-stopped + + + environment: + - DOCKER_HOST=dockerproxy + - HOSTINGER_API_TOKEN=kR7WKEBwV5w0JtyIazXcR0u2G8ufkgFn5IREL2AP855ee4a0 + + networks: + - external + + ports: + - "80:80" # HTTP + - "443:443" # HTTPS + - "22:22" # SSH for Gitea + + volumes: + - /home/jonas/traefik:/etc/traefik # Traefik configuration files + + + + # Health check + healthcheck: + test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:8000/health', timeout=5)"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + +networks: # custom bridge network named 'external' + external: + name: external + driver: bridge +``` + +Damit das ganze auch funktioniert müssen dns Einträge auf die Virtuelle Machine zeigen in der das ganze läuft. Wurde bei Hostinger für 99tales.net eingerichtet. + + + +