--- # Performance West — SHKeeper role # Installs k3s (lightweight Kubernetes), Helm, and deploys SHKeeper # via the official Helm chart for crypto payment processing. # # SHKeeper supports: BTC, ETH, USDC/USDT (ERC-20), Polygon, Tron, BNB, LTC, DOGE, XMR, SOL, AVAX, XRP # All free, open-source, non-custodial. # # Architecture: # k3s manages SHKeeper pods (crypto daemons + Flask API + MariaDB) # nginx on the host proxies pay.performancewest.net → k3s NodePort/LoadBalancer # ERPNext frappe_crypto app calls SHKeeper REST API to create invoices # SHKeeper webhooks POST back to ERPNext on payment confirmation # ── k3s installation ────────────────────────────────────────────────────────── - name: Check if k3s is already installed ansible.builtin.stat: path: /usr/local/bin/k3s register: k3s_binary - name: Install k3s with Docker runtime ansible.builtin.shell: | curl -sfL {{ k3s_install_url }} | INSTALL_K3S_EXEC="{{ k3s_exec_args }}" sh - args: creates: /usr/local/bin/k3s when: not k3s_binary.stat.exists - name: Wait for k3s to be ready ansible.builtin.command: k3s kubectl get nodes register: k3s_nodes retries: 12 delay: 5 until: "'Ready' in k3s_nodes.stdout" changed_when: false - name: Ensure deploy user has kubectl access block: - name: Create .kube directory for deploy user ansible.builtin.file: path: "/home/{{ deploy_user }}/.kube" state: directory owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: "0700" - name: Copy k3s kubeconfig for deploy user ansible.builtin.copy: src: /etc/rancher/k3s/k3s.yaml dest: "/home/{{ deploy_user }}/.kube/config" remote_src: true owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: "0600" # ── Helm installation ───────────────────────────────────────────────────────── - name: Check if helm is already installed ansible.builtin.stat: path: /usr/local/bin/helm register: helm_binary - name: Install Helm 3 ansible.builtin.shell: | curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash args: creates: /usr/local/bin/helm when: not helm_binary.stat.exists # ── Helm repos ──────────────────────────────────────────────────────────────── - name: Add SHKeeper Helm repo kubernetes.core.helm_repository: name: vsys-host repo_url: "{{ shkeeper_helm_repo }}" become: true become_user: "{{ deploy_user }}" environment: KUBECONFIG: "/home/{{ deploy_user }}/.kube/config" - name: Add mittwald Helm repo (kubernetes-secret-generator) kubernetes.core.helm_repository: name: mittwald repo_url: "{{ shkeeper_secret_gen_repo }}" become: true become_user: "{{ deploy_user }}" environment: KUBECONFIG: "/home/{{ deploy_user }}/.kube/config" # ── Deploy kubernetes-secret-generator (required by SHKeeper) ───────────────── - name: Install kubernetes-secret-generator kubernetes.core.helm: name: kubernetes-secret-generator chart_ref: mittwald/kubernetes-secret-generator release_namespace: default state: present update_repo_cache: true become: true become_user: "{{ deploy_user }}" environment: KUBECONFIG: "/home/{{ deploy_user }}/.kube/config" # ── Deploy SHKeeper values.yaml ────────────────────────────────────────────── - name: Deploy SHKeeper Helm values.yaml ansible.builtin.template: src: shkeeper-values.yaml.j2 dest: "{{ project_dir }}/shkeeper-values.yaml" owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: "0644" # ── Deploy SHKeeper ────────────────────────────────────────────────────────── - name: Install/upgrade SHKeeper via Helm kubernetes.core.helm: name: "{{ shkeeper_helm_release }}" chart_ref: vsys-host/shkeeper release_namespace: "{{ shkeeper_helm_namespace }}" state: present values_files: - "{{ project_dir }}/shkeeper-values.yaml" update_repo_cache: true become: true become_user: "{{ deploy_user }}" environment: KUBECONFIG: "/home/{{ deploy_user }}/.kube/config" - name: Wait for SHKeeper pod to be ready ansible.builtin.command: > k3s kubectl -n shkeeper wait --for=condition=ready pod -l app=shkeeper --timeout=300s register: shkeeper_ready retries: 3 delay: 10 until: shkeeper_ready.rc == 0 changed_when: false ignore_errors: true # ── UFW: allow k3s NodePort range ──────────────────────────────────────────── - name: Allow SHKeeper NodePort access from localhost only community.general.ufw: rule: allow port: "{{ shkeeper_port }}" proto: tcp from_ip: 127.0.0.1 comment: "SHKeeper web UI (k3s NodePort, localhost only)" # ── Remove stale Bitcart Docker containers if present ──────────────────────── - name: Stop and remove Bitcart Docker containers (replaced by SHKeeper) community.docker.docker_container: name: "{{ item }}" state: absent loop: - performancewest-bitcart-1 - performancewest-bitcart-worker-1 - performancewest-bitcart-admin-1 - performancewest-bitcart-postgres-1 - performancewest-bitcart-redis-1 ignore_errors: true