HAProxy server

Ở bài trước mình đã có 1 con server selfhosted dành cho web server. Tuy nhiên homelab này mình sẽ có nhiều server do đó sẽ cần 1 em đóng vai trò gateway ( cũng như monitoring )

  • i5-8700
  • 32GB RAM – 2666Mhz
  • SSD NVme Gen3 x4 : 256GB
  • HDD Sata : 1TB

Sau khi setup xong Ubuntu server như ở bài trước ( không cần Virtualmin ) thì ở server này sẽ cần HAProxy

HAProxy is a free, very fast and reliable reverse-proxy offering high availabilityload balancing, and proxying for TCP and HTTP-based applications.

Mục đích sử dụng HAProxy để forward request về các servers / services cần thiết. Ví dụ

  • https://selfhosted.jooservices.com/ sẽ được forward về Virtualmin ( port 10000 ) ở server selfhosted ta vừa installed trước.
  • https://jooservices.com sẽ forward về port 443 ( SSL ) của Virtualmin và load website

Cấu hình HAProxy

# 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

Bật HAProxy stats để quản lý

Tạm gác qua Sentry & Grafana ta sẽ nói sau. Thì ta có FE SSL cho các services

  • cnmatrix.jooservices.com : Trỏ về Core switch port 443
  • gatekeeper.jooservices.com : Trỏ về con server này với Webmin ( không phải Virtualmin ) trên port 10000
  • jooservices.com && xcrawler.net cùng nằm trên selfhosted server với port 443

Và sau đó là config BE để forward về server / port tương tứng với từng FE

global
	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
	daemon

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

	# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        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

defaults
	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 <username> insecure-password <password>


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

    acl acl_grafana hdr(host) -i grafana.jooservices.com
    acl acl_sentry hdr(host) -i sentry.jooservices.com

    use_backend be_grafana if acl_grafana
    #default_backend be_http

backend be_grafana
        mode http
        balance roundrobin
        server gatekeeper 192.168.1.5:3000 check

backend be_sentry
        mode http
        balance roundrobin
        server gitlab 192.168.1.5:9000 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 }

        ## 192.168.1.2
        use_backend be_ssl_cnmatrix if { req_ssl_sni -i cnmatrix.jooservices.com }

        ## 192.168.1.3
        # use_backend be_ssl_unifi if { req_ssl_sni -i unifi.jooservices.com }

	## 192.168.1.5
	use_backend be_ssl_webmin_gatekeeper if { req_ssl_sni -m end gatekeeper.jooservices.com }

        ## 192.168.1.6
        use_backend be_ssl_selfhosted if { req_ssl_sni -i jooservices.com }
	use_backend be_ssl_virtualmin_selfhosted if { req_ssl_sni -m end selfhosted.jooservices.com }
	#### XCrawler
        use_backend be_ssl_selfhosted if { req_ssl_sni -i xcrawler.net }
        use_backend be_ssl_selfhosted if { req_ssl_sni -m end .xcrawler.net }

        ## 192.168.1.8
        use_backend be_ssl_nas if { req_ssl_sni -i nas.jooservices.com }

        ## 192.168.1.10
        #use_backend be_ssl_esxi if { req_ssl_sni -i esxi.jooservices.com }

        ## 192.168.1.24
        #use_backend be_ssl_gitlab if { req_ssl_sni -i gitlab.jooservices.com }

        ## Virtualmin / Webmin
        #use_backend be_ssl_hosting_virtualmin if { req_ssl_sni -i virtualmin.jooservices.com }
        #use_backend be_ssl_gatekeeper_webmin if { req_ssl_sni -i gatekeeper.jooservices.com }
        #use_backend be_ssl_smb_webmin if { req_ssl_sni -i smb.jooservices.com }

        ## Hosting
        ## 192.168.1.20
        #use_backend be_ssl_hosting if { req_ssl_sni -i jooservices.com }       

        ## XCrawler
        ## 192.168.1.30
        #use_backend be_ssl_xcrawler if { req_ssl_sni -i xcrawler.net }
        #use_backend be_ssl_xcrawler if { req_ssl_sni -m end .xcrawler.net }

        #default_backend be_ssl_hosting

## Backend SSL
### CnMatrix
backend be_ssl_cnmatrix
        mode tcp
        balance roundrobin
        server cnmatrix 192.168.1.2:443 check

### Gatekeeper
backend be_ssl_webmin_gatekeeper
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.5:10000 check

### NAS
backend be_ssl_nas
        mode tcp
        balance roundrobin
        server nas 192.168.1.8:443 check

## Selfhosted
backend be_ssl_selfhosted
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.6:443 check
backend be_ssl_virtualmin_selfhosted
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.6:10000 check

My HAProxy configuration

global
    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
    daemon

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

    # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        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

defaults
    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 sentry.jooservices.com
    acl acl_grafana hdr(host) -i grafana.jooservices.com
    
    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 192.168.1.12:9000 check

backend be_grafana
        mode http
        balance roundrobin
        server gitlab 192.168.1.12:3000 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 }

        ## 192.168.1.2
        use_backend be_ssl_cnmatrix if { req_ssl_sni -i cnmatrix.jooservices.com }

        ## 192.168.1.3
        # use_backend be_ssl_unifi if { req_ssl_sni -i unifi.jooservices.com }

        ## 192.168.1.8
        use_backend be_ssl_nas if { req_ssl_sni -i nas.jooservices.com }

        ## 192.168.1.10
        use_backend be_ssl_esxi if { req_ssl_sni -i esxi.jooservices.com }

        ## 192.168.1.24
        use_backend be_ssl_gitlab if { req_ssl_sni -i gitlab.jooservices.com }
        
        ## Virtualmin / Webmin
        use_backend be_ssl_hosting_virtualmin if { req_ssl_sni -i virtualmin.jooservices.com }
        use_backend be_ssl_gatekeeper_webmin if { req_ssl_sni -i gatekeeper.jooservices.com }
        use_backend be_ssl_smb_webmin if { req_ssl_sni -i smb.jooservices.com }
        
        ## Hosting
        ## 192.168.1.20
        use_backend be_ssl_hosting if { req_ssl_sni -i jooservices.com } 
        use_backend be_ssl_hosting if { req_ssl_sni -m end tpbeauty.art baristaschool.vn .baristaschool.vn phongcachxanh.vn }
        #use_backend be_ssl_develop if { req_ssl_sni -m end coffeeschool.vn .coffeeschool.vn }

        ## XCrawler
        ## 192.168.1.30
        use_backend be_ssl_xcrawler if { req_ssl_sni -i xcrawler.net }
        use_backend be_ssl_xcrawler if { req_ssl_sni -m end .xcrawler.net }

        default_backend be_ssl_hosting


### CnMatrix
backend be_ssl_cnmatrix
        mode tcp
        balance roundrobin
        server cnmatrix 192.168.1.2:443 check

### Unifi
#backend be_ssl_unifi
#        mode tcp
#        balance roundrobin
#        server gatekeeper 192.168.1.3:443 check

# BEGIN Monitor
# END Monitor

# NAS
backend be_ssl_nas
        mode tcp
        balance roundrobin
        server smb 192.168.1.8:443 check

### BEGIN ESXi
        #### Gatekeeper
        backend be_ssl_gatekeeper_webmin
                mode tcp
                balance roundrobin
                server gatekeeper 192.168.1.9:10000 check

        #### ESXi
        backend be_ssl_esxi
                mode tcp
                balance roundrobin
                server esxi 192.168.1.10:443 check

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

        backend be_ssl_hosting
                mode tcp
                balance roundrobin
                server hosting 192.168.1.20:443 check

        #backend be_ssl_develop
        #        mode tcp
        #        balance roundrobin
        #        server develop 192.168.1.12:443 check

        backend be_ssl_smb_webmin
                mode tcp
                balance roundrobin
                server smb 192.168.1.14:10000 check

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


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

HAProxy Health check fails

backend be_staging
        option httpchk

        server staging 192.168.1.60:80 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ó

192.168.1.4 - - [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 192.168.1.60:80 check

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

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 127.0.0.1:7860, 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 0.0.0.0:7860. 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à 127.0.0.1

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 127.0.0.1:7860

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 127.0.0.1 đượ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.

HAProxy SSL Passthrough

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_hosting if { req_ssl_sni -i jooservices.com }

        default_backend be_ssl
backend be_ssl_hosting
        mode tcp
        balance roundrobin
        server aaa_ssl_server 192.168.1.39:443 check

My infrastructure network

Về cơ bản infrastructure network này mình build chưa được hoàn thiện, nhưng cũng thấy tương đối happy về nó. 1 chút chia sẽ.

Router 3910

  • Mình có tổng cộng 4 WANs. Tuy nhiên thực tế chỉ có 1 WAN chính với IP tĩnh

Core Switch – CnMatrix 2028-P

  • Thật ra em này có 1 điểm dở là không có port 2.5Gbe nên vướng 1 con Asus AX86U đành phải xài tạm port 1Gbe
  • 1 port SFP+ đến “Workstation”
  • 1 port 1Gbe đến X300
  • 1 port 1Gbe đến ProDesk
  • 1 port 1Gbe đến Asus AX86U

ProDesk

  • Em nó tuy nhỏ bé nhưng lại gần như là mấu chốt chính của toàn bộ Network. Gọi em nó là gatekeeper
  • HAProxy
    • Tiếp nhận 100% mọi requests và sau đó forwarding đến các server phía sau
    • Cũng là em SSH Jumper luôn
    • Tuy nhiên 1 số bất cập mình chưa làm được
      • Forward RDP
      • Passthrough SSL ( cái này đúng ra đã từng làm được mà giờ lại bị stucked )
  • Grafana
  • Loki
  • Syslog
  • Pihole

Asrock X300

  • Bản chất em này … ăn điện ít mà specs cũng kha khá ( 5700G / 64GB RAM & 2 TB SSD ) nên “hiểu” em nó như 1 thiết bị thứ sẽ online gần như 24/7. Do đó các “services” hosting trên đây là các services cần online liên tục
  • 1 con Virtualmin để hosting … chính các web này và n web khác
  • và 1 vài VM khác

Workstation

  • Em nó chính thức đã được triển khai với ESXi 7
  • 1 em VM “SMB” được attach với các HDDs. Em này bản thân cũng khá nhỏ, chủ yếu để phục vụ SMB / Plex & Torrent thôi
  • Em Workstation ngốn điện cao nên lý thuyết cũng khó online 24/7 mà sẽ có lúc down. Tuy nhiên specs em nó mạnh. Nên các service cần resource cao sẽ nằm trên đây.