# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: HAProxy
spec:
    description: The Reliable, High Performance TCP/HTTP Load Balancer
    coverImage: https://cdn.zeabur.com/templates/cover-image/haproxy.png
    icon: https://cdn.zeabur.com/templates/icon/haproxy.svg
    tags:
        - proxy
        - load-balancer
    readme: "HAProxy is a free, open source high availability solution, providing load balancing and proxying for TCP and HTTP-based applications by spreading requests across multiple servers. It is written in C and has a reputation for being fast and efficient (in terms of processor and memory usage).\n\nLearn more about HAProxy on [the official website](https://www.haproxy.org/).\n\n## Usage\n\nIf the configuration is not working, HAProxy will crashed. Therefore, you should configure the HAProxy in the [Config Editor](https://zeabur.com/docs/data-management/config-edit), and restart the service to apply the changes.\n\nPlease refer to the configuration guide in [the HAProxy configuration tutorials document](https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/configuration-basics/overview/).\n\nExamples:\n\n### Load Balancing to Multiple Zeabur Services\n\n```plain\nglobal\n    log stdout format raw local0\n    maxconn 16384\n\ndefaults\n    log     global\n    mode    http\n    option  httplog\n    option  dontlognull\n    timeout connect 5000ms\n    timeout client  50000ms\n    timeout server  50000ms\n    retries 3\n\nfrontend http_front\n    bind *:8080\n    option forwardfor\n    default_backend service_backend\n\nbackend service_backend\n    balance roundrobin\n    option httpchk GET /health\n    http-check expect status 200\n    \n    server replica1 service-1-replica-1.zeabur.internal:80 check\n    server replica2 service-1-replica-2.zeabur.internal:80 check\n    server replica3 service-1-replica-3.zeabur.internal:80 check\n\n```\n\nThis example:\n\n* Binds to port `8080`.\n* Trust proxy's `X-Forwarded-For` header by using the `forwardfor` option. It is required since Zeabur services are behind a proxy.\n* Redirects all requests to the `service_backend` service group, which is a group of servers that are running the same service.\n* Utilizes the `roundrobin` algorithm to balance the requests.\n* Checks the health of the servers by sending a GET request to the `/health` endpoint.\n* If the server is not healthy, it will be removed from the pool.\n* If the server is healthy, it will be added to the pool.\n\nYou should expose the port `8080` to the public in the Networking tab.\n\n### HTTP Basic Auth\n\n```plain\nglobal\n    log stdout format raw local0\n    maxconn 16834\n\ndefaults\n    log     global\n    mode    http\n    option  httplog\n    option  dontlognull\n    timeout connect 5000ms\n    timeout client  50000ms\n    timeout server  50000ms\n    retries 3\n\n# Defining user list and password\nuserlist basic_auth_users\n    # Format: user <username> password <password>\n    user admin password $6$rounds=100000$saltvalue$hashedpassword\n    # Or using plain text password (not recommended for production environment)\n    user developer insecure-password mypassword123\n    user viewer insecure-password viewonly\n\nfrontend http_front\n    bind *:8080\n    option forwardfor\n    \n    # Require HTTP Basic Authentication\n    acl auth_ok http_auth(basic_auth_users)\n    http-request auth realm \"Protected Area\" unless auth_ok\n    \n    default_backend service_backend\n\nbackend service_backend\n    server service1 service-1.zeabur.internal:80\n\n```\n\nGenerate the password hash using the following command:\n\n```plain\nmkpasswd -m sha-512 mypassword\n```\n\nThen, replace the `$6$rounds=100000$saltvalue$hashedpassword` with the generated hash.\n\nIf you want to exclude certain paths from HTTP Basic Auth protection, you can add the `acl` rule to the `frontend` section. For example:\n\n```plain\nfrontend http_front\n    bind *:8080\n    \n    # Define paths that do not require authentication\n    acl public_path path_beg /health /public\n    acl auth_ok http_auth(basic_auth_users)\n    \n    # Only require authentication for non-public paths\n    http-request auth realm \"Protected Area\" unless public_path or auth_ok\n    \n    default_backend service_backend\n\n```\n\n### TCP Proxying (e.g., PostgreSQL HA)\n\n```plain\nglobal\n    log stdout format raw local0\n    maxconn 4096\n\ndefaults\n    log     global\n    mode    tcp\n    option  tcplog\n    option  dontlognull\n    timeout connect 10s\n    timeout client  1h\n    timeout server  1h\n    retries 3\n\n# PostgreSQL primary (write operations)\nfrontend postgres_write\n    bind *:5432\n    default_backend postgres_primary\n\n# PostgreSQL replicas (read operations)\nfrontend postgres_read\n    bind *:5433\n    default_backend postgres_replicas\n\n# Primary backend\nbackend postgres_primary\n    mode tcp\n    option tcp-check\n    \n    # PostgreSQL health check\n    tcp-check connect\n    tcp-check send-binary 00000008 # Length\n    tcp-check send-binary 04d2162f # SSL request\n    \n    server primary postgres-primary.zeabur.internal:5432 check\n\n# Replicas backend (load balancing)\nbackend postgres_replicas\n    mode tcp\n    balance leastconn\n    option tcp-check\n    \n    # PostgreSQL health check\n    tcp-check connect\n    tcp-check send-binary 00000008\n    tcp-check send-binary 04d2162f\n    \n    server replica1 postgres-replica-1.zeabur.internal:5432 check\n    server replica2 postgres-replica-2.zeabur.internal:5432 check\n    server replica3 postgres-replica-3.zeabur.internal:5432 check\n\n```\n\nMake sure to expose ports `5432` and `5433` in the Networking tab.\n\n### Web UI\n\nAdd this frontend section to your configuration file:\n\n```plain\nfrontend stats\n    bind *:8404\n    mode http\n    stats enable\n    stats uri /stats\n    stats refresh 10s\n    stats realm HAProxy\\ Statistics\n    stats auth admin:admin123\n    stats admin if TRUE\n    stats show-legends\n    stats show-node\n\n```\n\nRemember to expose port `8404` to the public in the Networking tab, and you can access the stats page at `http://your-domain:8404/stats`, with the username `admin` and password `admin123`.\n"
    services:
        - name: haproxy
          icon: https://cdn.zeabur.com/templates/icon/haproxy.svg
          template: PREBUILT
          spec:
            source:
                image: haproxy:3.3
                runAsUserID: 99
            ports:
                - id: web
                  port: 8080
                  type: HTTP
                - id: stats
                  port: 8404
                  type: HTTP
            configs:
                - path: /usr/local/etc/haproxy/haproxy.cfg
                  template: "global\n    log stdout format raw local0\n    maxconn 16384\n\ndefaults\n    log     global\n    mode    http\n    option  httplog\n    option  dontlognull\n    timeout connect 5000ms\n    timeout client  50000ms\n    timeout server  50000ms\n    retries 3\n\nfrontend http_front\n    bind *:8080\n    default_backend service_backend\n\nbackend service_backend\n    balance roundrobin\n    option httpchk GET /health\n    http-check expect status 200\n    \n    server replica1 service-1-replica-1.zeabur.internal:80 check\n    server replica2 service-1-replica-2.zeabur.internal:80 check\n    server replica3 service-1-replica-3.zeabur.internal:80 check\n\nfrontend stats\n    bind *:8404\n    mode http\n    stats enable\n    stats uri /stats\n    stats refresh 10s\n    stats realm HAProxy\\ Statistics\n    stats auth admin:admin123\n    stats admin if TRUE\n    stats show-legends\n    stats show-node\n"
                  permission: null
                  envsubst: null
