> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open-politics.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation & Architecture

> Self-hosting guide and platform architecture

## How to set up your HQ

<Tabs>
  <Tab title="Hosted">
    The simplest way to use Open Politics is through our hosted platform:

    1. Register at [open-politics.org](https://open-politics.org/accounts/register)
    2. Log in at [open-politics.org/](https://open-politics.org/accounts/login)
    3. Begin using the platform with pre-loaded data and continue to:

    <Card icon="cog" href="/pages/app/app-setup" title="App Setup">
      Configure your API keys and providers
    </Card>
  </Tab>

  <Tab title="Self-hosted">
    Our preferred way to self-host on a single machine or develop with is Docker Compose. For Multi-machine setups, we recommend Kubernetes.

    But in both the cases you can choose to outsource services to managed providers for a more lightweight (but less private) setup.

    | Service          | Purpose         | Example Provider |                                   |
    | ---------------- | --------------- | ---------------- | --------------------------------- |
    | Postgres         | Main database   | Hetzner          |                                   |
    | Redis            | Cache and queue | Upstash          |                                   |
    | MinIO / S3       | Object storage  | Hetzner          |                                   |
    | Nominatim        | Geocoding       | Nominatim        | - uses lot of disk space (170gb+) |
    | LLM API          | Language model  | OpenAI           | - high gpu and/or cpu usage       |
    | Tavily / SerpAPI | Web search      | Tavily           |                                   |

    <Tabs>
      <Tab title="Docker Compose">
        Run the complete platform locally:

        <Steps>
          <Step title="Prerequisites">
            * Docker and Docker Compose
            * 32GB RAM recommended
            * 20GB free disk space
            * Git
          </Step>

          <Step title="Clone repository">
            ```bash theme={null}
            git clone https://github.com/open-politics/open-politics-hq.git
            cd open-politics-hq
            ```
          </Step>

          <Step title="Configure environment">
            ```bash theme={null}
            cp .env.example .env
            # Edit .env with your configuration
            # All values with changeThis need to be changed before the app will start.
            # for example with 'openssl rand -base64 14' in your terminal.
            ```
          </Step>

          <Step title="Start services">
            ```bash theme={null}
            docker compose up
            ```
          </Step>

          <Step title="Access the platform">
            Open your browser and navigate to:

            ```
            http://localhost:3000
            ```
          </Step>
        </Steps>

        <Note>
          Initial setup may take time depending on your system configuration.
        </Note>
      </Tab>

      <Tab title="Kubernetes">
        <Note>If you are here, we assume you know what you are doing.</Note>

        ## Base Helm Chart

        We have a base helm chart available [here](https://github.com/open-politics/open-politics-hq/tree/main/.deployments)

        ```bash theme={null}
        git clone https://github.com/open-politics/open-politics-hq
        cd .deployments/end-to-end-hetzner-k3s-terraform-helm/open-politics-hq-deployment/hq-cluster-chart
        cp values.example.yaml values.yaml
        # Edit values.yaml with your configuration
        ```

        ## Hetzner Kubernetes Stack

        Our easiest way to deploy HQ via Kubernetes is to use Hetzner. We provide an end-to-end script that provisions a master and worker nodes via Terraform and installs K3s. We suggest using K9s alongside our scripts to manage and scale the cluster.

        <Accordion title="Hetzner Kubernetes Stack">
          # HQ on Hetzner (K3s) — End-to-End Deployment Guide

          This repository delivers a batteries-included, reproducible way to provision a Hetzner K3s cluster and deploy your application stack with one command.

          ## What This Gives You

          * **3 Hetzner Cloud servers by default**: 1 control plane, 2 workers (configurable)
          * **K3s** with sensible flags for Hetzner CCM integration
          * **Traefik** Ingress with automatic TLS via Let's Encrypt (ACME)
          * **Persistent storage** using Hetzner CSI
          * **Application stack via Helm**: frontend, backend API, Celery workers, Redis, optional Postgres/MinIO templates

          ***

          ## Quick Start

          <Steps>
            <Step title="Configure Hetzner token">
              ```bash theme={null}
              cd .deployments/end-to-end-hetzner-k3s-terraform-helm/open-politics-hq-deployment/
              cp .tfvars.example .tfvars
              cp hq-cluster-chart/values.example.yaml hq-cluster-chart/values.yaml
              # Edit .tfvars and values.yaml with your configuration (see below)
              ```
            </Step>

            <Step title="Deploy">
              ```bash theme={null}
              ./deploy.sh
              ```

              The script is idempotent. Re-running applies updates safely. Typical first deploy time: \~10–15 minutes.
            </Step>
          </Steps>

          ## Configuration Checklist

          Before running `./deploy.sh`, ensure you've completed:

          * [ ] **Hetzner API Token**: Set `hcloud_token` in `.tfvars`
          * [ ] **Domain**: Set `domain` in `.tfvars` (must match `env.config.DOMAIN` in `values.yaml`)
          * [ ] **Application Values**: Copy and customize `hq-cluster-chart/values.yaml`
          * [ ] **Secrets**: Replace all `xxx` placeholders with real values
          * [ ] **SSH Keys**: Run `./scripts/manage-ssh-keys.sh generate`
          * [ ] **DNS Ready**: Have your domain ready for A record creation

          ***

          ## Prerequisites

          * Hetzner Cloud account and API token (Read/Write)
          * Local tools: `terraform`, `kubectl`, `helm`, `jq`
          * An SSH key uploaded to Hetzner; the scripts can rotate/manage keys automatically

          ***

          ## Initial Configuration

          <Steps>
            <Step title="Infrastructure Configuration (.tfvars)">
              ```bash theme={null}
              cp .tfvars.example .tfvars
              ```

              **Required:**

              * `hcloud_token`: Hetzner API token ([get from console](https://console.hetzner.com/projects))
              * `domain`: your public domain for TLS/ingress

              **Optional (with defaults):**

              * `worker_count`: number of workers (default: 2)
              * `master_server_type` / `worker_server_type`: server types (default: `cx22`)
              * `location`: Hetzner location (default: `fsn1`)
              * `cluster_slug`: resource naming prefix (default: `hq`)
            </Step>

            <Step title="Application Configuration (values.yaml)">
              ```bash theme={null}
              cp hq-cluster-chart/values.example.yaml hq-cluster-chart/values.yaml
              ```

              **Required customizations:**

              * `email`: admin email for Let's Encrypt
              * `env.config.DOMAIN`: your domain (must match `.tfvars`)
              * `env.config.BACKEND_CORS_ORIGINS`: update with your domain
              * Docker image repositories for backend, frontend, and celery-worker

              **Secrets (replace all `xxx` placeholders):**

              * `SECRET_KEY`, `FIRST_SUPERUSER_PASSWORD`, `POSTGRES_PASSWORD`
              * `MINIO_ROOT_PASSWORD`, `MINIO_SECRET_KEY`
              * `SMTP_USER`, `SMTP_PASSWORD`, `EMAILS_FROM_EMAIL`
              * API keys: `OPENAI_API_KEY`, `TAVILY_API_KEY`, `GOOGLE_API_KEY`, `MAPBOX_ACCESS_TOKEN`
            </Step>

            <Step title="SSH Key Management">
              ```bash theme={null}
              ./scripts/manage-ssh-keys.sh generate
              ```

              This generates key pairs, uploads to Hetzner, and updates cloud-init templates.

              **Manual alternative:** Upload your SSH key to Hetzner Console and set `ssh_key_name` in `.tfvars`.
            </Step>

            <Step title="DNS Preparation">
              Have your domain ready. After deployment, create A records pointing to the Load Balancer IP for both `your-domain.com` and `www.your-domain.com`.
            </Step>
          </Steps>

          ***

          ## How It Works

          The `./deploy.sh` orchestrator performs two phases:

          1. **Provision infrastructure**: Terraform creates network, firewall, servers; cloud-init installs K3s
          2. **Deploy stack**: Configures Traefik, installs Hetzner CCM/CSI, deploys the Helm chart

          **Core commands:**

          | Command                | Description                              |
          | ---------------------- | ---------------------------------------- |
          | `./deploy.sh`          | Full deploy (infra → app)                |
          | `./scripts/connect.sh` | Fetch kubeconfig and set kubectl context |
          | `./scripts/status.sh`  | Summary of nodes, services, ingress, PVs |
          | `./scripts/logs.sh`    | Tail app logs                            |
          | `./scripts/monitor.sh` | Open k9s                                 |
          | `./scripts/destroy.sh` | Tear everything down                     |

          ***

          ## DNS and TLS

          <Steps>
            <Step title="Get Load Balancer IP">
              ```bash theme={null}
              kubectl get svc traefik -n kube-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
              ```
            </Step>

            <Step title="Create DNS A records">
              Point your domain (and `www`) to the Load Balancer IP. Traefik will obtain Let's Encrypt certificates automatically (typically 2-5 minutes after DNS propagation).
            </Step>

            <Step title="Verify deployment">
              ```bash theme={null}
              ./scripts/test-deployment.sh  # Test DNS, HTTP/HTTPS, and TLS
              ./scripts/status.sh           # View pods, services, ingress
              ./scripts/check-ssl.sh        # Check ACME progress
              ```
            </Step>
          </Steps>

          ***

          ## Troubleshooting

          | Issue                       | Solution                                                          |
          | --------------------------- | ----------------------------------------------------------------- |
          | Workers don't schedule pods | CCM removes taints automatically; wait or remove manually         |
          | No Load Balancer IP         | Confirm Traefik is `LoadBalancer` and CCM is Ready                |
          | Domain mismatch             | Ensure `.tfvars` domain matches `values.yaml`                     |
          | CORS errors                 | Verify `BACKEND_CORS_ORIGINS` includes your domain                |
          | ACME stuck                  | Verify DNS A records point to LB IP; run `./scripts/check-ssl.sh` |
          | SSH failures                | Run `./scripts/manage-ssh-keys.sh generate`                       |

          ## Cost

          Default: 3× `cx22` + 1 Load Balancer ≈ €40–45/month. Reduce costs by lowering `worker_count` or using smaller server types.
        </Accordion>
      </Tab>
    </Tabs>
  </Tab>
</Tabs>
