Tuesday, November 18, 2025

View docker container IP

  •  ดูทั้งหมด

$ docker ps -q | xargs docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

  • ดู container เดียว

$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container_name>

Monday, October 27, 2025

ว่าด้วยเรื่อง Docker service ใน CentOS 7

  • เคยติดตั้งแต่และใช้งานแล้ว
  • แต่พอปิดการใช้งาน และจะเปิดใหม่ขึ้น  
  • $ sudo systemctl start docker
  • $ journalctl -xe

failed to start daemon: Error initializing network controller: Error creating default "bridge" network: Failed to program NAT chain: ZONE_CONFLICT

Solved

$ sudo systemctl stop firewalld

$ sudo systemctl start docker

$ sudo systemclt start firewalld

  • สรุป stop firewalld ซะก่อน แล้ว start docker service อีกครั้ง จากนั้น ก็ค่อย start firewalld กลับคืนมาประมาณนี้
  • ถ้ายังไม่ได้ก็ลบ docker0 interface ใน cent7ออกก่อน พอเรา start docker มันะจสร้างขึ้นมาใหม่เอง
  • ตัวอย่างการลบและการเพิ่ม network ไว้ใช้งานของ docker

sudo ip link delete docker0

sudo ip link delete br-xxxxx

sudo docker network create \

  --driver=bridge \

  --subnet=172.16.0.0/24 \

  --ip-range=172.16.0.0/24 \

  --gateway=172.16.0.1 \

  hello-custom-net

Ref

  • https://chatgpt.com/s/t_68ff6bdcdb488191aeb0fa83a7577138

Sunday, October 26, 2025

ติดตั้ง Nginx + PHP-FPM ใน Debian 12 in WSL

Ref
https://share.google/aimode/jYqPzJuf6u3AMYLBp
  • อัพเดทและอัพเกรด

sudo apt update && sudo apt upgrade -y

  • ติดตั้ง cer repo

sudo apt install software-properties-common ca-certificates lsb-release apt-transport-https -y

  • เพิ่ม php repo

sudo add-apt-repository ppa:ondrej/php

  • อัพเดท repo

sudo apt update

  •   ติดตั้งสิ่งที่ต้องมี

sudo apt install nginx php8.3-fpm php8.3 php8.3-curl php8.3-xml php8.3-ziz php8.3-mbstring php8.3-mysql php8.3-gd -y

sudo apt install php8.2-sqlite3 php8.2-pdo-sqlite php8.2-pgsql

sudo apt install composer 

sudo nano /etc/nginx/sites-available/default

  • แก้ไขคอนฟิกเกี่ยวกับ nginx+php ประมาณนี้

server {

    listen 80;

    server_name your_domain_or_ip; # Replace with your domain or IP address

    root /var/www/html; # Or your web root directory


    index index.php index.html index.htm;


    location / {

        try_files $uri $uri/ =404;

    }


    location ~ \.php$ {

        include snippets/fastcgi-php.conf;

        fastcgi_pass unix:/run/php/php8.3-fpm.sock;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        include fastcgi_params;

    }

}

  • ตรวจสอบคอนฟิก และ รีสตาร์ท

sudo nginx -t

sudo systemctl restart nginx

sudo systemctl restart php8.3-fpm

เพิ่มเติม

  • สำหรับ Laravel 12.* แนะนำลง php extension เหล่านี้ให้เรียบร้อย phpX.X-curl, phpX.X-xml, phpX.X-zip สำหรับใช้  composer

Saturday, October 25, 2025

เริ่มต้นเรียนรู้ Laravel 12.x

  • มีโปรเจที่เขียนด้วย Laravel 12.x ที่ localhost ที่ push ขึ้น github.com อยากนำขึ้น production โดย ใช้ container
  • โดย download clone file.zip ลงมา นำไปวางไว้ linux server ที่มี docker service
  • สร้าง Dockerfile และ docker-compose.yml (โดยใช้  จาก Project อื่นๆ ที่ทำไว้สำหรับ Codeignitor)
  • ทำการ build image และสร้าง container แล้วเปิด browser รัน url ตามที่ map port
  • http://ip:port มันได้ 403 Forbidden ซะงั้น

ปัญหาคือ

  • เราไม่เข้าใจวิธีการ run project ของเค้าหว่า
  • มันต้องไปรัน http://host-ip/public แบบนี้ทั้ง Codeignitor, และ Laravel
  • เมื่อรัน http://host:port/public ได้ ERROR 500 ซะงั้น
  • ตรวจสอบโดยดู LOG ของ container

$ docker logs my-docker-name

  • เห็นปัญหาคือ  ใน /public/index.php มันจะเรียก vender/autoload.php ประมาณนี้
  • ซึ่ง vender folder ที่ clone ระบบมาไม่มีซะงั้น ต้องติดตั้งตาม composer.json (เข้าไปใน project folder ที่จะมีไฟล์ composer.json อยู่ ก่อนรันคำสั่ง)

$ compose install

  • รันไม่ได้ซะงั้น ยังไม่ติดตั้ง  ก็ติดตั้งสิคับ (recommended)

$ curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

  • หรือ

   $ curl -sS https://getcomposer.org/installer | php

   $ sudo mv composer.phar /usr/local/bin/composer 

  • รันคำสั่งติดตั้ง  dependency อีกรอบ

$ compose install

  • จากนั้นรัน host อีกรอบ http://host:port/public
  • ได้ storage error ซะงั้น (folder นี้คล้ายกับ writeable ของ codeignitor ต้องเปิดสิทธิ์ให้เขียนได้)

$ chmod -R 707 storage

  • สุดท้ายแก้ไข path url ใน .env ให้ถูกต้องตามที่ใช้งาน

เพิ่มเติม

  • ในกรณีที่เราไม่อยากรันแบบ http://host/public อยากรันแค่ http://host เท่านี้แหละ

วิธีแรก

$ docker exec -it my-docker-name bash

# apt install nano

# nano /etc/apache2/sites-available/000-default.conf

  • แก้ไข DocumentRoot /var/www/html เป็น DocumentRoot /var/www/html/public

# /etc/init.d/apache2 reload

วิธีที่ 2

  • คัดลอง index.php และ .htaccess ใน public folder ออกมาที่ root project แล้วแก้ไข พาธใน index.php จาก .. แก้เป็น / เฉย เช่น

$app = require_once __DIR__.'/../bootstrap/app.php';

  • ก็แก้ไขเป็น

$app = require_once __DIR__.'/bootstrap/app.php';


Saturday, October 18, 2025

ปัญหาเรื่อง bug เมื่อวาง node project หลัง WAF Cloudflare

  •  คือเราเขียน CRUD และ upload file ด้วย Node+Express nodejs 22.18 ที่ local
  •  ทำงานได้ทุกฟังก์ชั่น ทดสอบผ่าน insert , update, delete รวมทั้ง upload file ได้ทุกไฟล์
  • แต่พอ ย้ายขึ้น product ทำแบบ รัน container docker และ ใช้ nginx reverse proxy เข้าไป ตั้งพาธให้เรียบร้อย
  • ปัญหาคือ อัพโหลดไฟล์ .webp บางไฟล์ไม่ได้ซะงั้น ได้ reponse status 403 forbidden error
  • ทำให้ ajax รับ response ไม่สามารถ decode json ได้เพราะ response เป็น html error 403
  • ทำให้ catch เมื่อเรียก .fetch().catch() 

Code ที่มีปัญหากับไฟล์ภาพบางไฟล์ เมื่อวางหลัง  WAF Cloudflare

function sendDataAjax() {
    // Prepare FormData
    const form = document.getElementById('insertForm');
    const formData = new FormData(form);

    fetch('<%=baseUrl%>/insertslide', {
        method: 'POST',
        body: formData
    })
    .then(async response => {
        const result = await response.json();
        if (result.success) {
            Swal.fire({
                icon: 'success',
                title: 'เพิ่มข้อมูลสำเร็จ'
            }).then(() => {
                window.location.reload();
            });
        } else {
            Swal.fire({
                icon: 'error',
                title: 'เกิดข้อผิดพลาด1',
                text: result.error || 'ไม่สามารถเพิ่มข้อมูลได้'
            });
        }
    })
    .catch((error) => {

        console.error("Fetch Error:", error); // พิมพ์ข้อผิดพลาดใน console เพื่อดีบั๊ก
   
        // แสดงข้อผิดพลาดที่เกิดขึ้นจริง
        let errorMessage = 'ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้';
       
        // พยายามดึงข้อความจาก Error Object ถ้ามี
        if (error && error.message) {
            errorMessage = `การเชื่อมต่อล้มเหลว: ${error.message}`;
        } else if (error) {
            errorMessage = String(error); // แปลง error object เป็น string
        }

        Swal.fire({
            icon: 'error',
            title: 'เกิดข้อผิดพลาด2',
            text: `ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้ ${error.message}`
        });
    });
}

Problem

  • มันเข้า  .catch error.message ที่ครั้งที่  แนบไฟล์นี้ไปด้วย

SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

Solved

  • capture ภาพนั้นวางบน paint แล้ว save มันอันใหม่ แล้วอัพโหลดก็ใช้ได้ซะงั้น
เพิ่มเติม
  • รู้สึกปัญหาประมาณนี้ เจอบ่อยๆ อยู่ระหว่าง process อื่นๆ ที่วางหลัง WAF cloudflare เค้าปลอดภัยจริงๆ
  • ทดสอบสมมุติฐาน คือ ย้ายโปรเจคไปอีก domain ที่ไม่ได้อยู่หลัง WAF Cloudflare ผลคือ ใ่ช้งานได้ปกติตามคาด
  • อีกเรื่องคือ plugin บางตัวใน CMS ยอดนิยม หน้าจัดการนะ แก้ไข post ให้แสดงจำนวนมาขึ้นและ มีการเรียงใหม่ DESC, ASC ประมาณนี้ ทั้งที่ทำผ่านหน้า GUI plugin นะ   ตอนกด save มันโดน cloudflare  block ซะงั้น วิธีแก้ต้องใช้วิชา network นิดหน่อย

Kill process linux

Ref

https://stackoverflow.com/questions/11583562/how-to-kill-a-process-running-on-particular-port-in-linux

$ sudo fuser -k 8000/tcp

การใช้งา pm2 จัดการ node project เบื้องต้น

https://gemini.google.com/share/e70b6bf55e75

PM2 เป็นตัวจัดการโพรเซส (Process Manager) สำหรับ Node.js ที่มีประสิทธิภาพและนิยมใช้ในการนำแอปพลิเคชัน Node.js ไปใช้งานจริง (Production) บนเซิร์ฟเวอร์ มันช่วยให้แอปพลิเคชันของคุณทำงานได้อย่างต่อเนื่องตลอดเวลา (always-on), จัดการการโหลดบาลานซ์ (Load Balancing), และดูแลการรีสตาร์ทอัตโนมัติเมื่อเกิดข้อผิดพลาด

นี่คือวิธีการใช้งาน PM2 ตั้งแต่การติดตั้งไปจนถึงการใช้งานเบื้องต้น:

1. การติดตั้ง PM2

ติดตั้ง PM2 แบบ Global บนเซิร์ฟเวอร์ของคุณ เพื่อให้สามารถเรียกใช้คำสั่งได้จากทุกที่:

Bash
npm install -g pm2

2. การเริ่มโปรเจกต์ (Start Your Project)

มีหลายวิธีในการเริ่มต้นโปรเจกต์ด้วย PM2:

A. เริ่มต้นง่าย ๆ (Simple Start)

รันไฟล์หลักของแอปพลิเคชันของคุณ (สมมติว่าเป็น index.js หรือ app.js):

Bash
pm2 start index.js

B. ตั้งชื่อและเพิ่มพารามิเตอร์

คุณสามารถตั้งชื่อโพรเซสเพื่อระบุได้ง่ายขึ้น และตั้งค่าให้รีสตาร์ทอัตโนมัติเมื่อไฟล์มีการเปลี่ยนแปลง (สำหรับ Development/Testing):

Bash
pm2 start app.js --name "my-web-app" --watch
  • --name: ตั้งชื่อโพรเซส

  • --watch: โพรเซสจะรีสตาร์ทอัตโนมัติเมื่อโค้ดมีการเปลี่ยนแปลง (ควรปิดใน Production)

C. โหมด Cluster (Load Balancing)

PM2 สามารถสร้างโพรเซสย่อย (Worker Processes) หลายตัวเพื่อใช้ประโยชน์จาก CPU หลายคอร์บนเซิร์ฟเวอร์ของคุณ ซึ่งช่วยเพิ่มประสิทธิภาพและรองรับการโหลดบาลานซ์:

Bash
# โดยที่ N คือจำนวน CPU Cores ที่คุณต้องการใช้ หรือใช้ 'max' เพื่อใช้ทุก Core
pm2 start app.js -i N
# หรือใช้ 'max' เพื่อใช้ทุก Core ที่มี
pm2 start app.js -i max

PM2 จะดูแลการกระจายคำขอ (Load Balancing) ไปยังโพรเซสย่อยทั้งหมดให้คุณโดยอัตโนมัติ


3. การจัดการสถานะ (Process Management)

นี่คือคำสั่งพื้นฐานในการควบคุมโพรเซสที่คุณรันอยู่:

คำสั่ง (Command)คำอธิบาย (Description)
pm2 status หรือ pm2 lsแสดงรายการโพรเซสทั้งหมดที่รันอยู่พร้อมสถานะ
`pm2 stop <nameid>`
`pm2 restart <nameid>`
`pm2 delete <nameid>`
pm2 stop allหยุดโพรเซสทั้งหมด
pm2 killฆ่าโพรเซส Demon (โพรเซสหลักของ PM2)

4. การจัดการ Log และ Monitoring

A. ดู Log แบบ Real-time

ใช้คำสั่งนี้เพื่อดู Log ทั้งหมดจากโพรเซสของคุณในหน้าจอเดียว:

Bash
pm2 logs
# หรือดู Log ของโพรเซสที่ระบุเท่านั้น
pm2 logs <name|id>

B. ดูสถานะทรัพยากร (Monitoring)

PM2 มีแดชบอร์ดใน Terminal ที่ช่วยให้คุณติดตามสถานะ CPU, Memory, และ Request Per Minute ได้แบบเรียลไทม์:

Bash
pm2 monit

5. การตั้งค่าให้รันอัตโนมัติเมื่อรีบูต (Startup/Daemon)

สิ่งสำคัญใน Production คือการทำให้ PM2 และแอปพลิเคชันของคุณกลับมาทำงานได้ทันทีหลังจากที่เซิร์ฟเวอร์รีบูต:

  1. สร้าง Startup Script:

    Bash
    pm2 startup
    

    คำสั่งนี้จะสร้าง Service สำหรับระบบปฏิบัติการของคุณ (เช่น systemd บน Ubuntu) และแสดงคำสั่งที่คุณต้องรันต่อไป (ซึ่งมักจะต้องใช้ sudo)

  2. บันทึกรายการโพรเซสปัจจุบัน:

    หลังจากที่คุณเริ่มแอปพลิเคชันทั้งหมดที่คุณต้องการแล้ว ให้บันทึกรายการโพรเซสปัจจุบัน:

    Bash
    pm2 save
    

    เมื่อเซิร์ฟเวอร์รีบูต PM2 จะโหลดโพรเซสทั้งหมดที่คุณบันทึกไว้กลับมาโดยอัตโนมัติ

💡 สรุปขั้นตอน Production ที่สำคัญ:

  1. pm2 install -g pm2

  2. pm2 start app.js -i max --name "production-app" (เริ่มด้วยโหมด Cluster)

  3. pm2 startup (ตั้งค่าให้รันเมื่อบูต)

  4. pm2 save (บันทึกรายการโพรเซส)

Popular Posts