My HAProxy configuration

    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # See:
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

    log global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

    # Newly added timeouts
    timeout http-request 10s
    timeout http-keep-alive 2s
    timeout queue 5s
    timeout tunnel 2m
    timeout client-fin 1s
    timeout server-fin 1s

# Caching
cache hosting
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

cache general
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

# HAProxy Stats
listen  stats
        bind *:1936
        log global

        maxconn 10

        stats enable
        stats show-node

        http-request use-service prometheus-exporter if { path /metrics }
        stats uri  /stats

userlist basic_auth_logins
        user <your_username_here> insecure-password <your_password_here>

# Frontend HTTP
frontend http
    bind :80
    mode http
    compression algo gzip

    acl acl_sentry hdr(host) -i
    acl acl_grafana hdr(host) -i
    use_backend be_sentry if acl_sentry
    use_backend be_grafana if acl_grafana
    #default_backend be_http

backend be_sentry
        mode http
        balance roundrobin
        server gitlab check

backend be_grafana
        mode http
        balance roundrobin
        server gitlab check

## Frontend SSL
frontend ssl
        bind :443
        mode tcp
        option tcplog

        # Wait for a client hello for at most 5 seconds
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }

        use_backend be_ssl_cnmatrix if { req_ssl_sni -i }

        # use_backend be_ssl_unifi if { req_ssl_sni -i }

        use_backend be_ssl_nas if { req_ssl_sni -i }

        use_backend be_ssl_esxi if { req_ssl_sni -i }

        use_backend be_ssl_gitlab if { req_ssl_sni -i }
        ## Virtualmin / Webmin
        use_backend be_ssl_hosting_virtualmin if { req_ssl_sni -i }
        use_backend be_ssl_gatekeeper_webmin if { req_ssl_sni -i }
        use_backend be_ssl_smb_webmin if { req_ssl_sni -i }
        ## Hosting
        use_backend be_ssl_hosting if { req_ssl_sni -i } 
        use_backend be_ssl_hosting if { req_ssl_sni -m end }
        #use_backend be_ssl_develop if { req_ssl_sni -m end }

        ## XCrawler
        use_backend be_ssl_xcrawler if { req_ssl_sni -i }
        use_backend be_ssl_xcrawler if { req_ssl_sni -m end }

        default_backend be_ssl_hosting

### CnMatrix
backend be_ssl_cnmatrix
        mode tcp
        balance roundrobin
        server cnmatrix check

### Unifi
#backend be_ssl_unifi
#        mode tcp
#        balance roundrobin
#        server gatekeeper check

# BEGIN Monitor
# END Monitor

backend be_ssl_nas
        mode tcp
        balance roundrobin
        server smb check

        #### Gatekeeper
        backend be_ssl_gatekeeper_webmin
                mode tcp
                balance roundrobin
                server gatekeeper check

        #### ESXi
        backend be_ssl_esxi
                mode tcp
                balance roundrobin
                server esxi check

        #### BEGIN Hosting
        backend be_ssl_hosting_virtualmin
                mode tcp
                balance roundrobin
                server hosting check

        backend be_ssl_hosting
                mode tcp
                balance roundrobin
                server hosting check

        #backend be_ssl_develop
        #        mode tcp
        #        balance roundrobin
        #        server develop check

        backend be_ssl_smb_webmin
                mode tcp
                balance roundrobin
                server smb check

        backend be_ssl_gitlab
                mode tcp
                balance roundrobin
                server hosting check
# END Hosting

# BEGIN XCrawler
backend be_ssl_xcrawler
        mode tcp
        balance roundrobin
        server xcrawler check
# END XCrawler

Bash script setup basically VM

No password required with sudo


Extend LVM

sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv

Setup timezone

sudo timedatectl set-timezone Asia/Ho_Chi_Minh
sudo timedatectl set-ntp on


sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli docker-buildx-plugin docker-compose-plugin
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

Setup PHP


echo 'Install requirements'

sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update && sudo apt upgrade -y

phpExtensions=('dev' 'cli' 'mbstring' 'curl' 'intl' 'mbstring' 'xml' 'xmlrpc' 'xsl' 'yaml' 'zip' 'imagick' 'gd' 'opcache' 'memcache' 'memcached' 'mysql' 'sqlite3' 'ldap' 'bcmath' 'fpm')
phpPecls=('mongodb' 'redis' 'pcov' 'apcu')

for phpVersion in "${phpVersions[@]}"
  echo "Install PHP ${phpVersion} extensions"
  extensions=$(printf "php${phpVersion}-%s " "${phpExtensions[@]}")
  sudo apt install -y $extensions

  echo "Install PHP ${phpVersion} pecl extensions"
  for phpPecl in "${phpPecls[@]}"
    sudo pecl -d php_suffix="${phpVersion}" install "${phpPecl}"
    sudo pecl uninstall -r "${phpPecl}"    
    sudo bash -c 'echo "extension='${phpPecl}'.so" >> /etc/php/'${phpVersion}'/cli/php.ini'
    sudo bash -c 'echo "extension='${phpPecl}'.so" >> /etc/php/'${phpVersion}'/fpm/php.ini'

Github action – Reusable

name: XCrawler - Build & Tests

    branches: [ develop ]
    types: [ opened, synchronize ]


    name: SonarCloud
    uses: ./.github/workflows/sonar_cloud.yml
    secrets: inherit

    name: Security check
    uses: ./.github/workflows/security_check.yml
    secrets: inherit

    name: Code standards check
    needs: [ sonar_cloud, security_check ]
        lint: [ phpstan, phpmd, phpcs ]
    uses: ./.github/workflows/code_standards.yml
      lint: ${{ matrix.lint }}
    secrets: inherit

    name: Execute UnitTest
    needs: [ code_standards ]
        test: [ Client, JAV, Flickr, Core ]
    uses: ./.github/workflows/unittest.yml
      test: ${{ matrix.test }}
    secrets: inherit

    name: "All Parallel Tests passed"
    needs: [ tests ]
    uses: ./.github/workflows/codecov.yml
    secrets: inherit
Continue reading Github action – Reusable

HAProxy Health check fails

backend be_staging
        option httpchk

        server staging check

Web server sử dụng Nginx

Đối với config trên thì HAProxy báo be_staging not available dù rằng mọi access đều working fine. !

Check Nginx log ta có - - [27/Aug/2023:21:36:00 +0700] "OPTIONS / HTTP/1.0" 405 166 "-" "-"

Vậy là do Nginx nó trả về 405 cho OPTIONS requests.

Update HAProxy

backend be_staging
        option httpchk GET /
        http-check expect status 200

        server staging check

Và mọi thứ trở về lại bình thường !

Laravel – Stable Diffusion

Sau một thời gian nghịch Stable Diffusion thì giờ cũng chút hứng thú với … code Laravel cho em nó.

Về cơ bản

  • Tạo ra queues để liên tục generate images
  • Tạo ra các “base prompt” để có thể tái` sử dụng ( ví dụ có thể tạo ``$prompt->portraits('Irene Aronson') thì sẽ tự add prompt là portraits của nghệ sĩ Irene Aronson

Alrite. Tuy nhiên trước đó thì cần chuẩn bị 1 số thứ

  • Stable Diffusion ( webUI ) chạy service
Description=systemd service start stable-diffusion

ExecStart=/bin/bash /home/joos/stable-diffusion-webui/

  • 1 em cron để chạy schedule:run của Laravel

Xong ! Giờ thì ta có 2 cách

  • Generate ra “queues” qua command
php artisan stable-diffusion:generate --prompt="a beautiful girl at 20 years old. she has colorful hair"

Command này sẽ sinh ra 1.001 queues ứng với prompt trên và … toàn bộ models mình đang có.

  • Code thêm theo ý
        $response = $service

Stable Diffusion – Public port

Bài viết này mình không tập trung vào Stable Diffusion mà là cách xử lý bài toán public port khi bản thân nó chỉ bind cho localhost.

By default Stable Diffusion chỉ listening trên, nghĩa là bạn không thể public ra ngoài Internet hoặc access từ các máy khác trong LAN.

Tất nhiên ta vẫn có thể sử dụng paramter –listen để listening trên Tuy nhiên cái giá phải trả là sẽ bị hạn chế nhiều thứ ( góc nhìn của developer AUTOMATIC1111 có lẽ là hạn chế bị change settings, cài extensions ngoài ý muốn khi public ).

Nhưng nếu bạn vẫn muốn làm điều này thì sao ? Giải quyết bài toán này khá đơn giản với HAProxy

  • HAProxy có thể dùng Frontend để listening 1 port nhất định sau đó forwarding về 1 IP khác. Trong trường hợp này là

Vậy trên chính cái máy bạn install Stable Diffusion WebUI, ta setup thêm HAProxy và cấu hình

frontend http
        bind :8080
        mode http

        default_backend be_develop

backend be_develop
    # default backend
        #option httpchk

        server hosting

Nghĩa là ta listening port 8080 từ ngoài vào ( tất nhiên router đã NAT 8080 về IP máy rồi ).

Sau đó do HAProxy nằm trên chính máy Stable Diffusion nên hiển nhiên access được. Vậy ta cứ forward về đó thôi.

Xong 😀

Tất nhiên lúc này ta có thể secure thêm 1 chút bằng basic authenticate.