10/23/2025

Config squid 5.7

 

Config squid 5.7
คำอธิบาย Authorization ประกอบด้วย 3 ส่วน ใช้ วรรคในการแบ่ง
เช่น
acl web_bypass dstdomain "/etc/squid/web_bypass.txt"

ประกอบด้วย
acl เริ่มต้นด้วยคำสั่ง
web_bypass ตัวแปรที่จะนำไปใช้ในการ allow หรือ denied
"/etc/squid/web_bypass.txt" ค่าที่ต้องการ allow หรือ denied เก็บเป็นไฟล์ หรือใช้ค่า เลยก็ได้
ใช้ค่าเลยเช่น
acl sci_servers dstdomain .sci.com .scivalve.com .alfresco.com


คำสั่ง allow หรือ denied ประกอบด้วย 3 ส่วน ใช้วรรคเป็นตัวแบ่ง เช่น
http_access allow sci_macs

จะขึ้นต้นด้วย http_access เริ่มต้นคำสั่ง
allow จะ allow หรือ denied
sci_macs ตัวแปรที่เก็บค่าไว้ หรือ Fix ค่าไปเลยก็ได้

dstdomain คือ domain ต้องตรงกันกับค่าที่ต้องการ allow หรือ denied
url_regex -i คือ มีคำหรือข้อความนั้นใน ค่าที่ต้องการ allow หรือ denied
rep_mime_type -i mime-type คือชนิดที่ต้องการ เช่น application/x-bittorrent

ส่วนที่ 1 Authorization
  1. forwarded_for on
  2. request_header_access Allow allow all
  3. request_header_access Authorization allow all
  4. request_header_access WWW-Authenticate allow all
  5. request_header_access Proxy-Authorization allow all
  6. request_header_access Proxy-Authenticate allow all
  7. request_header_access Cache-Control allow all
  8. request_header_access Content-Encoding allow all
  9. request_header_access Content-Length allow all
  10. request_header_access Content-Type allow all
  11. request_header_access Date allow all
  12. request_header_access Expires allow all
  13. request_header_access Host allow all
  14. request_header_access If-Modified-Since allow all
  15. request_header_access Last-Modified allow all
  16. request_header_access Location allow all
  17. request_header_access Pragma allow all
  18. request_header_access Accept allow all
  19. request_header_access Accept-Charset allow all
  20. request_header_access Accept-Encoding allow all
  21. request_header_access Accept-Language allow all
  22. request_header_access Content-Language allow all
  23. request_header_access Mime-Version allow all
  24. request_header_access Retry-After allow all
  25. request_header_access Title allow all
  26. request_header_access Connection allow all
  27. request_header_access Proxy-Connection allow all
  28. request_header_access User-Agent allow all
  29. request_header_access Cookie allow all
  30. request_header_access All deny all
  31.  
  32. ################## Start SCI ################################
  33. #acl sci-mac arp 90:21:55:02:6c:e2
  34. acl sci_macs arp "/etc/squid/MAC.lst"
  35. http_access allow sci_macs
  36.  
  37. acl sci_servers dstdomain .sci.com .scivalve.com .alfresco.com
  38. always_direct allow sci_servers
  39. http_access allow sci_servers
  40.  
  41. #Google
  42. acl googles dstdomain .google.com
  43. #always_direct allow googles
  44. http_access allow googles
  45.  
  46. #hotmail
  47. acl HM_SERVER dstdomain .msn.com .hotmail.com .passport.com .live.com .outlook.live.com .outlook.office.net .scivalve.com
  48. http_access allow HM_SERVER
  49.  
  50. acl web_bypass dstdomain "/etc/squid/web_bypass.txt"
  51. http_access allow web_bypass
  52.  
  53. acl GoodSites dstdomain "/etc/squid/goodsites.txt"
  54. #acl GoodSites url_regex -i "/etc/squid/goodsites.txt"
  55. http_access allow GoodSites
  56.  
  57. acl webblocked url_regex -i '/etc/squid/webblocked.txt'
  58. #acl webblocked dstdomain '/etc/squid/webblocked.txt'
  59. http_access deny webblocked
  60. #deny_info denied.html webblocked
  61.  
  62. acl TorrentFiles rep_mime_type -i mime-type application/x-bittorrent
  63. http_reply_access deny TorrentFiles
  64. deny_info TCP_RESET TorrentFiles
  65.  
  66. auth_param basic program /usr/lib/squid/basic_ldap_auth -v 3 -b "cn=Users,dc=sci,dc=com" -D CN=ldap-user,CN=Users,DC=SCI,DC=COM -w PASSWORD -f "(&(sAMAccountName=%s)(objectClass=person)(memberof=CN=InetAllow,OU=SCI,DC=SCI,DC=COM))" -h dc04.sci.com
  67. acl ldap-auth proxy_auth REQUIRED
  68.  
  69. #external_acl_type InetGroup %LOGIN /usr/lib/squid3/ext_wbinfo_group_acl
  70.  
  71. #acl InetAccessFree external InetGroup FreeNet
  72. #http_access allow InetAccessFree
  73.  
  74. acl webblocked_tmp dstdomain '/etc/squid/webblocked_tmp.txt'
  75. acl day_am time 08:00-11:59
  76. acl day_pm time 13:00-17:39
  77. acl day_ot time 18:00-20:59
  78. acl day_after time 21:00-23:59
  79. acl day_before time 00:00-05:59
  80. http_access deny webblocked_tmp day_am
  81. http_access deny webblocked_tmp day_pm
  82. http_access deny webblocked_tmp day_ot
  83. http_access deny webblocked_tmp day_after
  84. http_access deny webblocked_tmp day_before
  85.  
  86. acl domain_blocked dstdomain '/etc/squid/webblocked_https.txt'
  87. http_reply_access deny domain_blocked day_am
  88. http_reply_access deny domain_blocked day_pm
  89. http_reply_access deny domain_blocked day_ot
  90. http_reply_access deny domain_blocked day_after
  91. http_reply_access deny domain_blocked day_before
  92. http_access deny CONNECT domain_blocked day_am
  93. http_access deny CONNECT domain_blocked day_pm
  94. http_access deny CONNECT domain_blocked day_ot
  95. http_access deny CONNECT domain_blocked day_after
  96. http_access deny CONNECT domain_blocked day_before
  97.  
  98. http_access allow ldap-auth
  99. #SCI End 
  100.  

ส่วนที่ 2 localnet และ ports
  1. #Start SCI
  2. acl localnet src 192.168.0.0/24 192.168.100.0/24 192.168.2.0/24
  3. acl SSL_ports port 995          #mail.scivalve.com new
  4. acl SSL_ports port 8443         #scivalve.com new
  5. acl SSL_ports port 443
  6. acl SSL_ports port 993
  7. acl SSL_ports port 2222         # SCI: for hosting
  8. acl SSL_ports port 6301         # gpsiam
  9.  
  10. acl Safe_ports port 80          # http
  11. acl Safe_ports port 110         # SCI: POP3
  12. acl Safe_ports port 587         # SCI: smtp
  13. acl Safe_ports port 25          # SCI: smtp
  14. #End SCI


ส่วนที่ 3 Log Server
  1. #SCI Start Sent Log Squid To Log Server
  2. #Sent To access.log file.
  3. access_log /var/log/squid/access.log squid
  4.  
  5. #Sent To Log Server.
  6. logformat squid %tl %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt
  7. access_log tcp:192.168.2.108:514 squid
  8. #SCI End

9/25/2025

Proxmox : upgrade PVE version from 8 to 9

 1.ตรวจสอบว่ามีปัญหาในการ upgrade หรือไม่ แล้วแก้ไขรายการที่ fail ให้ผ่านก่อน
มีสีเหลืองได้ แต่ถ้าสีแดงต้องแก้ก่อน

  1. pve8to9

2.Shutdown VM และ CT ทั้งหมด
3.ตรวจสอบสถานะปัจจุบัน
  1. apt update
  2. apt dist-upgrade
  3. pveversion


4.แก้ไข Repositories ให้เป็นตัวใหม่ ต้องแก้ตัวนี้ให้เป็นตัวใหม่ก่อน เพราะตอน update ยังใช้ sources นี้อยู่
  1. sed -i 's/bookworm/trixie/g' /etc/apt/sources.list


5. สร้างไฟล์ Repositories ที่ต้องใช้สำหรับ Version ใหม่
  1. cat > /etc/apt/sources.list.d/pve-enterprise.sources << EOF
  2. Types: deb deb-src
  3. URIs: http://mirror.kku.ac.th/debian/
  4. Suites: trixie
  5. Components: main non-free-firmware
  6. Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
  7.  
  8. Types: deb deb-src
  9. URIs: http://security.debian.org/debian-security/
  10. Suites: trixie-security
  11. Components: main non-free-firmware
  12. Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
  13.  
  14. Types: deb deb-src
  15. URIs: http://mirror.kku.ac.th/debian/
  16. Suites: trixie-updates
  17. Components: main non-free-firmware
  18. Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
  19. EOF

6.update+upgrade
apt update
apt dist-upgrade
จะมีข้อความให้ตอบ
ตอบ q enter
ตอบ Yes เฉพาะ /etc/lvm/lvm.conf
นอกนั้น No ทั้งหมด

7. ปิด sources.list เดิมไม่ได้ใช้ ใส่ # ไว้
  1. nano /etc/apt/sources.list


หรือปิดผ่านหน้า GUI ใน Nodes --> pve --> Repositories

ที่มา : https://pve.proxmox.com/wiki/Upgrade_from_8_to_9

 

หากมีปัญหาหรือ Error ให้กลับไปใช้ Kernel เดิม แล้วทำการ แก้ไขเริ่มต้น upgrade ใหม่
1. ดูว่าใช้ kernel ไหนอยู่

  1. uname -a

Linux pve44 6.8.12-15-pve #1 SMP PREEMPT_DYNAMIC PMX 6.8.12-15 (2025-09-12T11:02Z) x86_64 GNU/Linux

2. list ดู kernel
  1. proxmox-boot-tool kernel list

แล้วย้อนกลับไปที่ kernel เก่า
  1. proxmox-boot-tool kernel pin 6.8.12-15-pve --next-boot

3. reboot
แล้วแก้ไขทำการเริ่ม upgrade ใหม่

เมื่อ upgrade ได้แล้ว ต้อง unpin kernel เพื่อให้ใช้ kernel ล่าสุด
  1. proxmox-boot-tool kernel unpin 
  1. proxmox-boot-tool kernel list
  1. uname -a

 

9/23/2025

Ubuntu 18.04 Samba share เข้า terminal ภาษาไทยไม่แสดง

 Ubuntu 18.04 Samba share เข้า terminal ภาษาไทยไม่แสดง

ตั้งตั้งค่า locales
1. คำสั่ง

  1. dpkg-reconfigure locales

2. เลือก
th_TH.UTF-8 UTF-8

 


 

Home Assistant with Docker กล้อง ONVIF แจ้งเตือนเข้า Rocketchat

 *** หาต้องการให้แสดงรูป ต้องใช้ url
https://rocket.scivalve.com
- หากใช้ IP จะเห็น รูปได้เครื่องอยู่ในวง network เดียวกัน
- ใช้ chat.scivalve.com ใน app จะไม่เห็น เพราะ app ชี้ url ไปที่ rocket.scivalve.com
ให้ใช้ rocket.scivalve.com จะเห็นทั้งในหมด
ขึ้นตอน
1. Add integration ONVIF ถ้ากล้องอยู่วงเดียวกันกับ HA จะเจอเลย ถ้าไม่เจอ Add Manual Port 10080
2. Add กล้องสำหรับ view เข้า Dashboard ไว้ดู By entity แล้วเลือก Profile กล้องที่ต้องการ
*** หาวิธีส่งรูปตรง ๆ จาก HA แล้วไม่ได้ ติดปัญหา กล้องไม่มี function ที่ snap เป็น jpg จึงทำไม่ได้ ****
แก้ปัญหาโดย เขียน code python save ลง docker แล้วให้ HA เรียกใช้ python ส่งแจ้งเตือนเข้า Rocketchat
3. สร้างไฟล์ python ที่ Home Assistant
ไว้ที่ /HA/snapshot.py
Code

  1. #!/usr/bin/env python3
  2. import requests
  3.  
  4. url = "http://xxx.xx.xx.xx:8080/snapshot.cgi?user=xxx&pwd=xxx"
  5. res = requests.get(url, stream=True)
  6.  
  7. if res.status_code == 200:
  8.     #with open("/HA/www/snapshot.jpg", "wb") as f:
  9.     with open("/config/www/snapshot.jpg", "wb") as f:
  10.        for chunk in res.iter_content(1024):
  11.             f.write(chunk)
  12.  
  13.     url = "http://xxx.xx.xx.xx:3000/api/v1/rooms.upload/RoomId"
  14.     #url = "https://chat.scivalve.com/api/v1/rooms.upload/RoomId"
  15.     headers = {
  16.         "X-Auth-Token": "xxx",
  17.         "X-User-Id": "xxx"
  18.     }
  19.    
  20.     files = {
  21.         #"file": ("snapshot.jpg", open("/HA/www/snapshot.jpg", "rb"), "image/jpeg")
  22.         "file": ("snapshot.jpg", open("/config/www/snapshot.jpg", "rb"), "image/jpeg")
  23.     }
  24.  
  25.     data = {
  26.         "msg": "พบการเคลื่อนไหวจากกล้อง SERVER A"
  27.     }
  28.  
  29.     response = requests.post(url, headers=headers, files=files, data=data)
  30.     #print(response.text)
  31.     #print("Snapshot saved")
  32. else:
  33.     print("Error:", res.status_code)


***สำคัญไฟล์ ที่ save และส่ง ต้องใช้ใน /config/ เพื่อให้รูปได้จริง หากไว้ใน /HA/ จะ run คำสั่ง python ตรง ๆ ได้ แต่เมื่อ Home Assistant เรียกใช้จะส่งรูปไม่ได้ ***
RoomId หาได้จาก คำสั่ง
  1. curl -H "X-Auth-Token: xxx" \
  2.      -H "X-User-Id: xxx" \
  3.      http://xxx.xxx.xx.xx:3000/api/v1/rooms.info?roomName=ชื่อห้อง

เช่น
  1. curl -H "X-Auth-Token: xxx" \
  2.      -H "X-User-Id: xxx" \
  3.      http://xxx.xxx.xx.xx:3000/api/v1/rooms.info?roomName=Test

จะได้ _id คือ room id
{"room":{"_id":"xxx","fname":"Test"
{"room":{"_id":"xxx","fname":"IT_Notification",

4. configuration.yaml สำหรับเรียกใช้ python เพิ่ม
  1. shell_command:
  2.    send_snapshot: "python3 /config/snapshot.py"
  3.  


5. automation.yaml เพิ่ม
  1. - id: motion_alert_server_a
  2.   alias: "แจ้งเตือน SERVER A พร้อมส่งรูป"
  3.   trigger:
  4.     - platform: state
  5.       entity_id: binary_sensor.ip_camera_cell_motion_detection
  6.       to: "on"
  7.   action:
  8.     - service: shell_command.send_snapshot

9/18/2025

ส่งค่าอุณหภูมิจาก Pi ไป Home Assistant แบบ Docker

 ส่งค่าอุณหภูมิจาก Pi ไป Home Assistant แบบ Docker

ต่อจาก
https://intranet.scivalve.com/blog.php?u=281&b=2051

1. ตัว HA ลงแบบ Docker ก็ต้อง Mosquitto ด้วย Docker container
1.1. สร้างโฟลเดอร์เก็บ config/data/log ของ Mosquitto:

  1. mkdir -p /HA/mosquitto/config /HA/mosquitto/data /HA/mosquitto/log

1.2. สร้างไฟล์ config
  1. nano /HA/mosquitto/config/mosquitto.conf

1.3. ใส่ค่า
แบบใช้ได้หมด ไม่ต้องใส่ use password ไม่ปลอดภัย
  1. persistence true
  2. persistence_location /mosquitto/data/
  3. log_dest file /mosquitto/log/mosquitto.log
  4.  
  5. allow_anonymous true
  6. listener 1883

แบบตั้ง user password
  1. persistence true
  2. persistence_location /mosquitto/data/
  3. log_dest file /mosquitto/log/mosquitto.log
  4.  
  5. allow_anonymous false
  6. password_file /mosquitto/config/password.txt
  7. listener 1883


1.4. สร้าง user ด้วยคำสั่ง
docker run --rm -it \
  1.  -v /HA/mosquitto/config:/mosquitto/config \
  2.   eclipse-mosquitto mosquitto_passwd -c /mosquitto/config/password.txt hauserXXXXX

มันจะถาม password ให้คุณใส่ → เก็บไว้ใน /HA/mosquitto/config/password.txt

1.5. รัน container Mosquitto:
  1. docker run -d \
  2.   --name mosquitto \
  3.   -p 1883:1883 \
  4.   -p 9001:9001 \
  5.   -v /HA/mosquitto/config:/mosquitto/config \
  6.   -v /HA/mosquitto/data:/mosquitto/data \
  7.   -v /HA/mosquitto/log:/mosquitto/log \
  8.   eclipse-mosquitto


1.6. Restart Mosquitto
  1. docker restart mosquitto


1.7. ทดสอบ ที่เครื่อง HA Run
  1. mosquitto_sub -h localhost -p 1883 -u "hauser" -P "รหัสผ่าน" -t "#"


1.8. ที่เครื่องเรา ติดตั้ง
  1. apt install mosquitto-clients -y

แล้วลองส่งค่าไป
  1. mosquitto_pub -h 192.168.2.5 -p 1883 -u "xxx" -P "xxxx" -t "test/topic" -m "Hello MQTT"
  1. mosquitto_pub -h 192.168.2.5 -p 1883 -u "xxx" -P "xxxx" -t "hass/sensor/temperature" -m "27"

ที่ Terminal ของ HA จะต้องเห็นข้อความ Hello MQTT

1.9. ที่ เครื่อง HA เพิ่ม ที่ไฟล์ configuration.yaml เป็น Sensor และรอรับค่า MQTT
  1. mqtt:
  2.   sensor:
  3.     - name: "Server Temp."
  4.       state_topic: "hass/sensor/temperature"
  5.       value_template: "{{ value_json.temperature }}"
  6.       unit_of_measurement: "°C"
  7.  
  8.     - name: "Server Hum."
  9.       state_topic: "hass/sensor/temperature"
  10.       value_template: "{{ value_json.humidity }}"
  11.       unit_of_measurement: "%"


1.10. เข้า Setting --> Devices & Services Add integration MQTT เข้าไปด้วย
ใส่ IP User Password

1.11. ที่เครื่อง pi ทดลอง run python Code temp2mqtt.2.5.py
  1. #!/usr/bin/python3
  2. import sys
  3. import Adafruit_DHT
  4.  
  5. import time, json
  6. import RPi.GPIO as GPIO
  7. import paho.mqtt.client as mqtt
  8.  
  9. import requests
  10.  
  11. # Config
  12. MQTT_BROKER = "192.168.2.5"   # IP ของ Home Assistant
  13. MQTT_PORT = 1883
  14. MQTT_USER = "xx"
  15. MQTT_PASSWORD = "xx"
  16. MQTT_TOPIC = "hass/sensor/temperature"
  17.  
  18. SENSOR = Adafruit_DHT.AM2302  # หรือ DHT11 แล้วแต่ที่ใช้
  19. PIN = 4  # GPIO ที่ต่อ sensor
  20.  
  21. # Connect MQTT
  22. client = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2)
  23. client.username_pw_set(MQTT_USER, MQTT_PASSWORD)
  24. client.connect(MQTT_BROKER, MQTT_PORT, 60)
  25.  
  26. # Try to grab a sensor reading.  Use the read_retry method which will retry up
  27. # to 15 times to get a sensor reading (waiting 2 seconds between each retry).
  28. humidity, temperature = Adafruit_DHT.read_retry(SENSOR, PIN)
  29.  
  30. # Un-comment the line below to convert the temperature to Fahrenheit.
  31. # temperature = temperature * 9/5.0 + 32
  32.  
  33. from datetime import datetime
  34. if humidity is not None and temperature is not None:
  35.    print('Temp={0:0.1f}*  Humidity={1:0.1f}%  Date={2}'.format(temperature, humidity, datetime.today().strftime('%Y-%m-%d %H:%M:%S')))
  36.    payload = {
  37.         "temperature": round(temperature, 2),
  38.         "humidity": round(humidity, 2)
  39.    }
  40.    #print('{0}'.format(json.dumps(payload)))
  41.    client.publish(MQTT_TOPIC, json.dumps(payload))
  42.  


แก้ Code ให้ส่ง MQTT ไป 2 เครื่อง
  1. #!/usr/bin/python3
  2. import Adafruit_DHT
  3. import time, json
  4. from datetime import datetime
  5. import paho.mqtt.client as mqtt
  6.  
  7. # Config broker 1
  8. MQTT_BROKER1   = "192.168.0.187"
  9. MQTT_PORT1     = 1883
  10. MQTT_USER1     = "xxx"
  11. MQTT_PASSWORD1 = "xxx"
  12. BROKER1_TOPIC  = "hass/sensor/temperature"
  13.  
  14. # Config broker 2
  15. MQTT_BROKER2   = "192.168.2.5"
  16. MQTT_PORT2     = 1883
  17. MQTT_USER2     = "xxx"
  18. MQTT_PASSWORD2 = "xxx"
  19. BROKER2_TOPIC  = "hass/sensor/temperature"
  20.  
  21. SENSOR = Adafruit_DHT.AM2302
  22. PIN = 4
  23.  
  24. # อ่านค่าจาก DHT
  25. humidity, temperature = Adafruit_DHT.read_retry(SENSOR, PIN)
  26.  
  27. if humidity is not None and temperature is not None:
  28.     payload = {
  29.         "temperature": round(temperature, 2),
  30.         "humidity": round(humidity, 2)
  31.     }
  32.  
  33.     print(f"Publish: {payload} at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  34.  
  35.     # ส่งไป broker 1
  36.     client1 = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2)
  37.     client1.username_pw_set(MQTT_USER1, MQTT_PASSWORD1)
  38.     client1.connect(MQTT_BROKER1, MQTT_PORT1, 60)
  39.     client1.publish(BROKER1_TOPIC, json.dumps(payload))
  40.     client1.disconnect()
  41.  
  42.     # ส่งไป broker 2
  43.     client2 = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2)
  44.     client2.username_pw_set(MQTT_USER2, MQTT_PASSWORD2)
  45.     client2.connect(MQTT_BROKER2, MQTT_PORT2, 60)
  46.     client2.publish(BROKER2_TOPIC, json.dumps(payload))
  47.     client2.disconnect()

 

HA + Pi สั่งปิดเปิด Air Auto แทนเครื่อง MN-SERVER

 HA + Pi สั่งปิดเปิด Air Auto แทนเครื่อง MN-SERVER

คำสั่ง Restart service HA docker

  1. docker restart Docker-ID

ตั้งค่า Timezone ให้ Debian เพื่อให้เวลาตรง
  1. timedatectl set-timezone Asia/Bangkok
  2. timedatectl
  3. date


1. ติดตั้ง Home Assistant with Docker
https://intranet.scivalve.com/blog.php?u=281

2. HA และ PI สร้าง Private Key เพื่อให้ HA สามารถ SSH เข้าเครื่อง PI โดยไม่ต้องใช้รหัส
จะทำให้ HA สามารถเรียกคำสั่งโปรแกรมที่เครื่อง PI ได้
2.1. ใช้ Terminal ล็อคอินเข้าไปที่ เครื่อง Server ที่รัน Docker และ Home Assistant ของคุณ
2.2. รันคำสั่งนี้เพื่อสร้าง Key คู่ใหม่:
  1. ssh-keygen -t rsa -b 4096

2.3. ระบบจะถามคำถาม 2-3 ข้อ ให้ กด Enter ผ่านไปทั้งหมด เพื่อยอมรับค่าเริ่มต้น และ ไม่ต้องใส่รหัสผ่าน (passphrase) นะครับ
2.4. คำสั่งนี้จะสร้างไฟล์ id_rsa (กุญแจลับ) และ id_rsa.pub (กุญแจสาธารณะ) ขึ้นมาในโฟลเดอร์ .ssh ของ user ที่คุณกำลังล็อคอินอยู่บน Server (เช่น /root/.ssh/ หากคุณล็อคอินเป็น root)

[บนเครื่อง HA Server] ขั้นตอนที่ 2: คัดลอกเนื้อหา Public Key

2.5. รันคำสั่งนี้เพื่อแสดงเนื้อหาของ Public Key:
  1. cat ~/.ssh/id_rsa.pub

2.6. คัดลอก (Copy) ข้อความทั้งหมด ที่แสดงขึ้นมา มันจะขึ้นต้นด้วย ssh-rsa และลงท้ายด้วยชื่อ user@hostname ของคุณ

[บนเครื่อง Raspberry Pi] ขั้นตอนที่ 3: ติดตั้ง Public Key

2.7. ตอนนี้ ให้ใช้ Terminal ล็อคอินเข้าไปที่ เครื่อง Raspberry Pi ของคุณ
2.8. รันคำสั่งนี้เพื่อสร้างโฟลเดอร์และไฟล์ที่จำเป็น (หากยังไม่มี) และตั้งค่า permission ให้ถูกต้อง:
  1. mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys

2.9. เปิดไฟล์ authorized_keys ด้วยโปรแกรม nano:
  1. nano ~/.ssh/authorized_keys

2.10. วาง (Paste) Public Key ที่คุณคัดลอกมาจากขั้นตอนที่ 2 ลงในไฟล์นี้ จากนั้นกด Ctrl+X > กด Y > กด Enter เพื่อบันทึกและออกจากโปรแกรม

[บนเครื่อง HA Server] ขั้นตอนที่ 4: คัดลอก Private Key ให้ Docker
2.11. กลับมาที่ Terminal ของ เครื่อง HA Server
2.12. ตอนนี้ให้ทำขั้นตอนที่เราคุยกันล่าสุด คือคัดลอก Private Key (id_rsa) ที่เพิ่งสร้างในขั้นตอนที่ 1 ไปยังโฟลเดอร์คอนฟิกของ HA ที่แชร์กับ Docker

# แก้ /root/.ssh/id_rsa หาก Key ของคุณอยู่ที่อื่น
# แก้ /path/to/your/ha/config/ ให้เป็น Path จริง
เครื่องจริงอยู่ที่ /config/id_rsa
  1. cp /root/.ssh/id_rsa /path/to/your/ha/config/

2.13. ตั้งค่า permission ให้ไฟล์ที่คัดลอกไป:
  1. chmod 600 /path/to/your/ha/config/id_rsa

2.14. ทดสอบ SSH จากเครื่อง HA ไปเครื่อง PI จะต้องไม่ขึ้นถามรหัส Login

3. แก้ไข ไฟล์ configuration.yaml เพื่อให้มี Switch ปิดเปิด Air manual เพิ่ม
  1. ### Air ####
  2. shell_command:
  3.   # !!! สำคัญ: แก้ไข <IP_ของ_RPi> และ path ไปยังไฟล์ .py ของคุณให้ถูกต้อง !!!
  4.   #### TEST #####
  5.   #air1_on:  "sshpass -p 'XXX' ssh pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  6.   #air1_off: "sshpass -p 'XXX' ssh pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  7.   #air1_on:  "ssh -i /HA/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  8.   #air1_off: "ssh -i /HA/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  9.   #air1_on:  "ssh pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  10.   #air1_off: "ssh pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  11.   ##### Test Rocketchat #######
  12.   #air1_on:  "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  13.   #air1_off: "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Test.py 2302 4'"
  14.  
  15.   air1_on:  "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/On_air1.py'"
  16.   air1_off: "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Off_air1.py'"
  17.  
  18.   air2_on:  "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/On_air2.py'"
  19.   air2_off: "ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' pi@192.168.0.3 'python3 /home/pi/Off_air2.py'"
  20.  
  21.   # --- DEBUG COMMANDS ---
  22.   #debug_find_path: "pwd > pwd.txt && ls -la >> pwd.txt"
  23.  
  24. # New sensor for human-readable status
  25. sensor:
  26.   - platform: template
  27.     sensors:
  28.       air_status:
  29.         friendly_name: "สถานะแอร์"
  30.         value_template: >-
  31.           {% set state = states('input_select.active_air') %}
  32.           {% if state == 'air1' %}
  33.             Air 1 กำลังทำงาน
  34.           {% elif state == 'air2' %}
  35.             Air 2 กำลังทำงาน
  36.           {% elif state == 'both' %}
  37.             Air 1 และ Air 2 กำลังทำงาน
  38.           {% else %}
  39.             แอร์ทุกเครื่องปิดอยู่
  40.           {% endif %}
  41.  
  42. switch:
  43.   - platform: template
  44.     switches:
  45.       air1_switch:
  46.         friendly_name: "Air 1"
  47.         value_template: "{{ states('input_select.active_air') in ['air1', 'both'] }}"
  48.         turn_on:
  49.           - service: shell_command.air1_on
  50.           - service: input_select.select_option
  51.             target:
  52.               entity_id: input_select.active_air
  53.             data:
  54.               option: >-
  55.                 {% if is_state('input_select.active_air', 'air2') %}
  56.                   both
  57.                 {% else %}
  58.                   air1
  59.                 {% endif %}
  60.         turn_off:
  61.           - service: shell_command.air1_off
  62.           - service: input_select.select_option
  63.             target:
  64.               entity_id: input_select.active_air
  65.             data:
  66.               option: >-
  67.                 {% if is_state('input_select.active_air', 'both') %}
  68.                   air2
  69.                 {% else %}
  70.                   none
  71.                 {% endif %}
  72.  
  73.       air2_switch:
  74.         friendly_name: "Air 2"
  75.         value_template: "{{ states('input_select.active_air') in ['air2', 'both'] }}"
  76.         turn_on:
  77.           - service: shell_command.air2_on
  78.           - service: input_select.select_option
  79.             target:
  80.               entity_id: input_select.active_air
  81.             data:
  82.               option: >-
  83.                 {% if is_state('input_select.active_air', 'air1') %}
  84.                   both
  85.                 {% else %}
  86.                   air2
  87.                 {% endif %}
  88.         turn_off:
  89.           - service: shell_command.air2_off
  90.           - service: input_select.select_option
  91.             target:
  92.               entity_id: input_select.active_air
  93.             data:
  94.               option: >-
  95.                 {% if is_state('input_select.active_air', 'both') %}
  96.                   air1
  97.                 {% else %}
  98.                   none
  99.                 {% endif %}
  100.  
  101.       # New switch for controlling both
  102.       all_air_switch:
  103.         friendly_name: "Air1+Air2"
  104.         value_template: "{{ is_state('input_select.active_air', 'both') }}"
  105.         turn_on:
  106.           - service: shell_command.air1_on
  107.           - service: shell_command.air2_on
  108.           - service: input_select.select_option
  109.             target:
  110.               entity_id: input_select.active_air
  111.             data:
  112.               option: 'both'
  113.         turn_off:
  114.           - service: shell_command.air1_off
  115.           - service: shell_command.air2_off
  116.           - service: input_select.select_option
  117.             target:
  118.               entity_id: input_select.active_air
  119.             data:
  120.               option: 'none'
  121.  
  122. input_select:
  123.   active_air:
  124.     name: Air ที่ทำงานอยู่
  125.     options:
  126.       - none
  127.       - air1
  128.       - air2
  129.       - both # Added 'both' state
  130.     initial: none


4. ไฟล์ automation.yaml เพื่อให้สลับ Air อัตโนมัติ เพิ่ม
  1. #### Off ก่อนแล้วค่อย ON เพื่อไม่ให้ Switch เปิดทั้ง 2
  2. #### delay 15 วิ รอให้ คำสั่งแรกทำงานเสร็จก่อน ถ้าทำต่อเลย คำสั่งแรกยังทำไม่เสร็จ Status จะไม่ถูก
  3. - id: air1_0000
  4.   alias: "Air1 00:00 - 02:59"
  5.   trigger:
  6.     - platform: time
  7.       at: "00:00:00"
  8.   action:
  9.     - service: switch.turn_off
  10.       target:
  11.         entity_id: switch.all_air_switch
  12.     - delay: "00:00:15"   # รอ 15 วินาที      
  13.     - service: switch.turn_on
  14.       target:
  15.         entity_id: switch.air1_switch
  16.  
  17. - id: air2_0300
  18.   alias: "Air2 03:00 - 05:59"
  19.   trigger:
  20.     - platform: time
  21.       at: "03:00:00"
  22.   action:
  23.     - service: switch.turn_off
  24.       target:
  25.         entity_id: switch.all_air_switch
  26.     - delay: "00:00:15"   # รอ 15 วินาที      
  27.     - service: switch.turn_on
  28.       target:
  29.         entity_id: switch.air2_switch
  30.  
  31. - id: air1_0600
  32.   alias: "Air1 06:00 - 08:59"
  33.   trigger:
  34.     - platform: time
  35.       at: "06:00:00"
  36.   action:
  37.     - service: switch.turn_off
  38.       target:
  39.         entity_id: switch.all_air_switch
  40.     - delay: "00:00:15"   # รอ 15 วินาที      
  41.     - service: switch.turn_on
  42.       target:
  43.         entity_id: switch.air1_switch
  44.  
  45. - id: air2_0900
  46.   alias: "Air2 09:00 - 11:59"
  47.   trigger:
  48.     - platform: time
  49.       at: "09:00:00"
  50.   action:
  51.     - service: switch.turn_off
  52.       target:
  53.         entity_id: switch.all_air_switch
  54.     - delay: "00:00:15"   # รอ 15 วินาที      
  55.     - service: switch.turn_on
  56.       target:
  57.         entity_id: switch.air2_switch
  58.  
  59. - id: air1_1200
  60.   alias: "Air1 12:00 - 14:59"
  61.   trigger:
  62.     - platform: time
  63.       at: "12:00:00"
  64.   action:
  65.     - service: switch.turn_off
  66.       target:
  67.         entity_id: switch.all_air_switch
  68.     - delay: "00:00:15"   # รอ 15 วินาที      
  69.     - service: switch.turn_on
  70.       target:
  71.         entity_id: switch.air1_switch
  72.  
  73. - id: air2_1500
  74.   alias: "Air2 15:00 - 17:59"
  75.   trigger:
  76.     - platform: time
  77.       at: "15:00:00"
  78.   action:
  79.     - service: switch.turn_off
  80.       target:
  81.         entity_id: switch.all_air_switch
  82.     - delay: "00:00:15"   # รอ 15 วินาที    
  83.     - service: switch.turn_on
  84.       target:
  85.         entity_id: switch.air2_switch
  86.  
  87. - id: air1_1800
  88.   alias: "Air1 18:00 - 20:59"
  89.   trigger:
  90.     - platform: time
  91.       at: "18:00:00"
  92.   action:
  93.     - service: switch.turn_off
  94.       target:
  95.         entity_id: switch.all_air_switch
  96.     - delay: "00:00:15"   # รอ 15 วินาที      
  97.     - service: switch.turn_on
  98.       target:
  99.         entity_id: switch.air1_switch
  100.  
  101. - id: air2_2100
  102.   alias: "Air2 21:00 - 23:59"
  103.   trigger:
  104.     - platform: time
  105.       at: "21:00:00"
  106.   action:
  107.     - service: switch.turn_off
  108.       target:
  109.         entity_id: switch.all_air_switch
  110.     - delay: "00:00:15"   # รอ 15 วินาที      
  111.     - service: switch.turn_on
  112.       target:
  113.         entity_id: switch.air2_switch

5. ที่เครื่อง PI เพิ่มไฟล์ 4 ไฟล์ สำหรับ HA เรียกใช้
On_air1.py, On_air2.py, Off_air1.py, Off_air2.py
Code
On_air1.py
  1. #!/usr/bin/python3
  2. import time
  3. import RPi.GPIO as GPIO
  4.  
  5. GPIO.setmode(GPIO.BCM)
  6.  
  7. GPIO.setwarnings(False)
  8. GPIO.setup(20, GPIO.OUT)
  9. GPIO.output(20, GPIO.LOW)
  10. #GPIO.setup(21, GPIO.OUT)
  11. #GPIO.output(21, GPIO.LOW)
  12.  
  13. ##### Rocketchat #####
  14. import requests
  15. from datetime import datetime
  16. def send_to_rocketchat(message):
  17.    url = "http://xx.xx.xx.xx:3000/api/v1/chat.postMessage"
  18.  
  19.    headers = {
  20.       "Content-type": "application/json",
  21.       "X-Auth-Token": "XXX",
  22.       "X-User-Id": "XXX"
  23.    }
  24.  
  25.    payload = {
  26.        "channel": "#Test", #IT_Notification
  27.        "text": message
  28.    }
  29.    response = requests.post(url, json=payload, headers=headers)
  30.  
  31. message = "แจ้งเตือน เปิด AIR1 ปิด AIR2 " + datetime.today().strftime('%Y-%m-%d %H:%M:%S')
  32.  
  33. send_to_rocketchat(message)
  34.  

On_air2.py
  1. #!/usr/bin/python3
  2. import time
  3. import RPi.GPIO as GPIO
  4.  
  5. GPIO.setmode(GPIO.BCM)
  6.  
  7. GPIO.setwarnings(False)
  8. #GPIO.setup(20, GPIO.OUT)
  9. #GPIO.output(20, GPIO.LOW)
  10. GPIO.setup(21, GPIO.OUT)
  11. GPIO.output(21, GPIO.LOW)
  12.  
  13.  
  14. ##### Rocketchat #####
  15. import requests
  16. from datetime import datetime
  17. def send_to_rocketchat(message):
  18.    url = "http://192.168.2.76:3000/api/v1/chat.postMessage"
  19.  
  20.    headers = {
  21.       "Content-type": "application/json",
  22.       "X-Auth-Token": "XXX",
  23.       "X-User-Id": "XXX"
  24.    }
  25.  
  26.    payload = {
  27.        "channel": "#Test", #IT_Notification
  28.        "text": message
  29.    }
  30.    response = requests.post(url, json=payload, headers=headers)
  31.  
  32. message = "แจ้งเตือน เปิด AIR2 ปิด AIR1 " + datetime.today().strftime('%Y-%m-%d %H:%M:%S')
  33.  
  34. send_to_rocketchat(message)
  35.  

Off_air1.py

  1. import time
  2. import RPi.GPIO as GPIO
  3.  
  4. GPIO.setmode(GPIO.BCM)
  5.  
  6. GPIO.setwarnings(False)
  7. GPIO.setup(20, GPIO.OUT)
  8. GPIO.output(20, GPIO.HIGH)
  9. #GPIO.setup(21, GPIO.OUT)
  10. #GPIO.output(21, GPIO.HIGH)
  11. GPIO.cleanup()
  12.  

Off_air2.py
  1. #!/usr/bin/python3
  2. import time
  3. import RPi.GPIO as GPIO
  4.  
  5. GPIO.setmode(GPIO.BCM)
  6.  
  7. GPIO.setwarnings(False)
  8. #GPIO.setup(20, GPIO.OUT)
  9. #GPIO.output(20, GPIO.HIGH)
  10. GPIO.setup(21, GPIO.OUT)
  11. GPIO.output(21, GPIO.HIGH)
  12. GPIO.cleanup()

 

Home Assistant with Docker HACS+Editor-card

 Home Assistant with Docker HACS+Editor-card

 

1. add lxc debian template
2. install sudo ติดตั้ง docker และ program ที่ต้องใช้
  1. for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt-get remove $pkg; done
  2. apt-get install ca-certificates curl
  3. install -m 0755 -d /etc/apt/keyrings
  4. curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
  5. echo   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  6. $(. /etc/os-release && echo "$VERSION_CODENAME") stable" |   tee /etc/apt/sources.list.d/docker.list > /dev/null
  7. apt-get update
  8. apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

3.ติดตั้ง Portainer : https://intranet.scivalve.com/blog.php?u=3&b=1961
  1. docker volume create portainer_data
  2. docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

4. สร้างที่เก็บ config
  1. mkdir /HA

5. ติดตั้ง docker แล้วตั้งค่า
  1. docker run -d \
  2.   --name homeassistant \
  3.   --privileged \
  4.   --restart=unless-stopped \
  5.   -e TZ=Asia/Bangkok \
  6.   -v /HA:/config \
  7.   -v /run/dbus:/run/dbus:ro \
  8.   --network=host \
  9.   ghcr.io/home-assistant/home-assistant:stable

6. ติดตั้ง HACS
  1. docker ps
  2. docker exec -it [CONTAINER_ID] bash -c "wget -O - https://get.hacs.xyz | bash -"

7. restart HA
  1. docker restart <container_name_or_id>

8. เข้า IP:8123 ตั้งค่า HA, Password และอื่น ๆ เพิ่ม integration ชื่อ HACS
เข้าไปที่ Settings --> Devices & Services กด Add integration ค้นหา HACS เพิ่มกด Link ไป github แล้วเอา เลยไปใส่ใน Account github
9. ติดตั้ง Config Editor เพื่อช่วยแก้ไฟล์ config ต่าง ๆ
- เข้าเมนู HACS
- ค้นหาคำว่า config editor
- Download addon ทั้ง 2 ตัว (Config Editor, Config Editor Card)
- เพิ่มข้อความในไฟล์ configuration.yaml
  1. config_editor:


- Restart HA + Reload browser
- เพิ่มเมนูใน Dashboard
- Setting --> Dashboards --> + Add dashboard
- ไปที่ Dashboards ที่เพิ่มมาใหม่ เปลี่ยน View configuration ที่ Add ขึ้นมาใหม่ให้เป็น Panel (single card) เพื่อจะได้เต็มจอ
- Add card ค้นหา Config Editor Card กด save
type text จะเป็น
  1. type: custom:config-editor-card

8/30/2025

Proxmox : Import .vmdk จาก VMware โดยการ ใช้ไฟล์ .vmdk ไม่ผ่าน Import ของ PVE

 Proxmox : Import .vmdk จาก VMware โดยการ ใช้ไฟล์ .vmdk ไม่ผ่าน Import ของ PVE


Download ไฟล์ vmdk จะได้ไฟล์ คู่กัน 2 อัน เช่น จากเครื่อง Axapta-DB-2014
1. scp ทั้ง 2 ไฟล์ ไป PVE
scp Axapta-DB-2014-flat.vmdk root@192.168.2.44:/tmp/
scp Axapta-DB-2014.vmdk root@192.168.2.44:/tmp/

2. ที่เครื่อง PVE
-rw-r--r-- 1 root root 10737418240 Aug 30 11:19 Axapta-DB-2014-flat.vmdk
-rw-r--r-- 1 root root 505 Aug 30 11:57 Axapta-DB-2014.vmdk

3. สร้าง VM ที่เครื่อง PVE เพื่อ importdisk เข้า ID VM แล้วใช้คำสั่ง
qm importdisk XXX /tmp/Axapta-DB-2014.vmdk LLL --format qcow2

XXX = ID ของ VM
LLL = Location ของ Disk ที่ต้องการใช้งาน
เช่น
qm importdisk 157 /tmp/Axapta-DB-2014.vmdk DATA1 --format qcow2

4. เข้าไป Add disk ที่ Import เข้ามา และ แก้ Boot

8/25/2025

วิธีแก้ปัญหา Windows 10/11 เข้า Samba Alias Name ไม่ได้ ขึ้นให้ใส่ User Password

 วิธีแก้ปัญหา Windows 10/11 เข้า Samba Alias Name ไม่ได้ ขึ้นให้ใส่ User Password แต่ไม่สามารถเข้าได้แต่ Windows7 เข้าได้ตามปกติ
1. ติดตั้ง SUPTOOLS.MSI
อยู่ในแผ่น Windows Server 2003 CD → โฟลเดอร์ SUPPORT\TOOLS

2. ใช้ CMD run ด้วยสิทธิ์ Admin เข้าไปที่ C:\Program Files\Support Tools\
"C:\Program Files\Support Tools\"

**** ที่เครื่อง DC03 มีปัญหาใช้คำสั่งแล้วไม่ได้ผลเหมือน DC04 *****

3. Run คำสั่ง
setspn -A HOST/datacenter3 department
setspn -A HOST/datacenter4 e-document


4. ตรวจสอบผลที่ได้
setspn -L department
setspn -L e-document


5. แก้ไฟล์ smb.conf แล้ว Restart smb, winbind
เพิ่ม
netbios aliases = cname

ให้ใช้ AD ทั้ง 2 เครื่อง เพิ่ม
password server = dc03.sci.com, dc04.sci.com
wins server = xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx

8/19/2025

ติดตั้ง Theme, Icon, เมาส์ Style สำหรับ Linux, Ubuntu, Debain

 

ติดตั้ง Theme, Icon, เมาส์ Style สำหรับ Linux, Ubuntu, Debain
1. ติดตั้ง Program
apt install nala

2. Theme ARC
nala install arc-theme

3. เมาส์ Style
nala install oxygencursors

4. Icon mint และอื่น ๆ
nala install mint-y-icons
nala install papirus-icon-theme

เข้าเครื่อง Container ผ่าน เครื่องหลัก PVE โดยใช้คำสั่ง

 เข้าเครื่อง Container ผ่าน เครื่องหลัก PVE โดยใช้คำสั่ง
XX = Id เครื่อง
XX = โปรแกรมที่ต้องการเรียกใช้งาน

pct exec XX -- XXX
เช่น
pct exec 134 -- bash

แต่ของ VM ไม่ได้ทำได้แค่ Run คำสั่งที่ต้องการและได้ผลลัพธ์เลยไม่ค้างหน้า Terminal

Upgrade Debian 12 To Debian 13

 Upgrade Debian 12 To Debian 13 

ทุกคำสั่งทำใน root
1. ปรับปรุงระบบ Debian 12 ให้สมบูรณ์

apt update
apt upgrade
apt full-upgrade

2. กำจัดแพ็กเกจที่ไม่จำเป็น
apt --purge autoremove
apt autoclean

3. ตรวจสอบว่าแพ็กเกจใดมาจากแหล่งภายนอก (เช่น Chrome, Docker)
sudo apt list '?narrow(?installed, ?not(?origin(Debian)))'


4. เปลี่ยน sources.list ไปใช้ "trixie" และ สำรองไฟล์ repo
mkdir ~/apt-backup
cp /etc/apt/sources.list ~/apt-backup/
cp -r /etc/apt/sources.list.d/ ~/apt-backup/

แก้ไข sources ให้เปลี่ยน bookworm → trixie
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list.d/*

ดูใน sources.list จะต้องมี
deb http://deb.debian.org/debian/ trixie main contrib non-free
deb http://security.debian.org/debian-security trixie-security main contrib non-free
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free

5. อัปเดตเป็น Trixie: ขั้นตอนแบบแบ่งเป็นสองส่วน
5.1. Minimal Upgrade ช่วยลดความเสี่ยงจากการติดตั้งแพ็กเกจใหม่ที่ไม่จำเป็นทันที
apt update
apt upgrade --without-new-pkgs
หรือ
5.2. Full Upgrade ยืนยัน (Yes) เมื่อมี prompt ให้รีสตาร์ท Service และเลือกเก็บคอนฟิกเดิมเมื่อถูกถาม
sudo apt full-upgrade --autoremove -y

6. Reboot เครื่อง
7. ตรวจสอบว่ามีการติดตั้ง linux-image-xxx-metapackage หรือไม่
dpkg -l 'linux-image*' | grep ^ii | grep -i meta

ถ้าไม่มี ให้ติดตั้ง linux-image-amd64
apt install linux-image-amd64

8. ทำความสะอาดหลังอัปเกรด
apt autoremove
apt autoclean

9. ตรวจสอบว่าอัปเกรดสำเร็จ
lsb_release -a
หรือ
cat /etc/debian_version


ควรเห็นว่าเป็น Debian 13 (Trixie) หรือดูในโปรแกรม System Info


 

5/19/2025

ติดตั้ง Proxmox Backup Client ใน server Ubuntu 18.04

Ubuntu 18.04

sudo add-apt-repository ppa:bkryza/onedata-1909-bionic
sudo apt update
sudo apt install -y libfuse3-3 qrencode
wget http://download.proxmox.com/debian/pbs/dists/buster/pbs-no-subscription/binary-amd64/proxmox-backup-client_1.1.14-1_amd64.deb
sudo dpkg -i proxmox-backup-client_1.1.14-1_amd64.deb

rsync ข้อมูลจากเครื่อง 1 ไปอีกเครื่อง 1 ใน Ubuntu

 ที่เครื่อง X1 ที่ต้องการเอาข้อมูล
1. แก้ไฟล์ sshd_config

  1. nano /etc/ssh/sshd_config

เพิ่ม
PermitRootLogin yes

และใส่ # ไม่ใช้งานหน้า
#PermitRootLogin prohibit-password
#StrictModes yes

restart service
systemctl restart sshd

ที่เครื่องใหม่ X2
2. ทดลอง ssh ด้วย user root ว่าเข้าไปที่ X1 ได้หรือไม่
3. คำสั่ง
ทดลอง
  1. rsync -aAXv -e "ssh -p 22" root@IP_X1:/DATA/e-document/#2025#/* /DATA/e-document/#2025#/

ถ้าจะทำจริง ๆ
  1. rsync -aAXv -e "ssh -p 22" root@IP_X1:/DATA/e-document/* /DATA/e-document/
ไม่ต้องใส่ --numeric-ids เพราะจะทำให้ group ได้ไม่ตรงกัน เนื่องจาก id ของเครื่องเก่าและใหม่ไม่ตรงกัน

ตรวจสอบสิทธิ์ ด้วย ls -la ว่า group และสิทธิ์ ถูกต้องหรือไม่
ls -la /DATA/e-document/#2025#/001-099/SO25-001/

symbolic-link Ubuntu

 ให้รูปจาก Datacenter ดึงมาแสดงใน Intranet โดยการสร้าง symbolic-link
ใช้คำสั่ง

  1. ln -s /DATA/Asset/ /var/www/

จะได้
  1. ls -la
  2. lrwxrwxrwx  1 root root   12 May 14 10:15 Asset -> /DATA/Asset/

คำอธิบาย
ln -s /ปลายทางของไฟล์ที่จะ link ไป/ /ที่อยู่ของ link/

5/15/2025

Proxmox VE old images container Download.

 Proxmox VE old images container Download.

http://download.proxmox.com/images/system/

ปิด auto add printer ใน network เข้า debian auto

 ปิด auto add printer ใน network เข้า debian auto
แนวทางแก้ไข: "ปิด auto-add แต่ยังให้ add เองได้"
คุณสามารถ เปิด cups-browsed แต่สั่งให้มันไม่ auto-add printer ได้ โดยแก้ไฟล์ cups-browsed.conf
1. แก้ไขไฟล์ตั้งค่า:

sudo nano /etc/cups/cups-browsed.conf

2. ค้นหาบรรทัดที่เกี่ยวกับ BrowseRemoteProtocols และ CreateIPPPrinterQueues
ตั้งค่าแบบนี้:
BrowseRemoteProtocols none
CreateIPPPrinterQueues No

ความหมาย:
BrowseRemoteProtocols none: ไม่ต้องค้นหาเครื่องพิมพ์จาก network
CreateIPPPrinterQueues No: ไม่ต้องสร้าง printer queue อัตโนมัติ

3. บันทึกไฟล์ แล้วรีสตาร์ท cups-browsed และ cups
sudo systemctl restart cups-browsed
sudo systemctl restart cups

4. แล้ว Add printer ที่ต้องการใช้งานเอง โดย
connect ผ่าน /run/cups/cups.sock ที่หน้าโปรแกรม Printer

Proxmox Virtual Environment(PVE) QEMU Guest Agent Install

 Proxmox Virtual Environment(PVE) QEMU Guest Agent Install

sudo apt install qemu-guest-agent
systemctl enable qemu-guest-agent
systemctl start qemu-guest-agent
systemctl status qemu-guest-agent


แล้วไปเปิด QEMU Guest Agent Enabled ใน Option ของ Host

Windows Server 2003 Active Directory (AD) ใช้กับ Ubuntu Join domain ได้สูงสุด

 Windows Server 2003 Active Directory (AD) ใช้กับ Ubuntu เพื่อ join domain ได้ จำกัดอยู่ที่บางเวอร์ชันของ Ubuntu เท่านั้น เนื่องจาก Windows Server 2003 ใช้ SMB1 และ LDAP แบบเก่า ซึ่งถูกเลิกสนับสนุนในเวอร์ชัน Ubuntu ที่ใหม่กว่าเพื่อความปลอดภัย
Ubuntu เวอร์ชันที่ยังสามารถ join domain กับ Windows Server 2003 ได้ (โดยทั่วไป):

- Ubuntu 12.04 LTS
- Ubuntu 14.04 LTS
- Ubuntu 16.04 LTS (อาจต้องปรับแต่งเพิ่มเติม)

Ubuntu 18.04 ขึ้นไป เริ่มมีปัญหาเข้ากันไม่ได้โดยตรงกับ Windows Server 2003 AD เพราะ:
Ubuntu ใช้ Samba 4 ที่ตั้งค่าเริ่มต้นปิด SMB1
LDAP/NTLMv1 ถูกปิด ระบบความปลอดภัยและการเข้ารหัสมีการปรับให้รัดกุมขึ้น

ถ้าต้องใช้ Ubuntu ที่ใหม่กว่า:
ยังสามารถ พยายาม join domain ได้โดยการบังคับให้เปิด SMB1 และ NTLMv1 เช่น:
ปรับ smb.conf ให้รองรับ SMB1 (client min protocol = NT1)
แก้ krb5.conf และ nsswitch.conf ให้รองรับ Kerberos แบบเก่า
แต่ ไม่แนะนำอย่างยิ่ง ใน production เนื่องจากความเสี่ยงด้านความปลอดภัย

สรุป:
Ubuntu ที่แนะนำสุดท้ายสำหรับใช้งานร่วมกับ Windows Server 2003 AD คือ Ubuntu 16.04 LTS
เวอร์ชันใหม่กว่านั้นอาจทำงานไม่ได้เลยหรือทำได้แต่ต้องปรับแต่งเสี่ยง

Hosting สำหรับตรวจสอบ Log mail ถูก Block

 1. สำหรับ ตรวจสอบว่า IP ไปหา Server อีกฝั่งได้หรือไม่ ลองจาก hosting และเครื่องเรา

ถ้าเครื่องเราได้ แต่ Hosting ไม่ได้แสดงว่าถูก Block
telnet outlook-com.olc.protection.outlook.com 25
telnet mx.viettelidc.com.vn 25
ถ้าไม่ผ่าน
Trying 103.1.208.206...
Connected to mx.viettelidc.com.vn.
Escape character is '^]'.
451 Listed by SBL, see https://check.spamhaus.org/sbl/query/SBL531607
ZConnection closed by foreign host.
ถ้าผ่าน
telnet mx.viettelidc.com.vn 25
Trying 103.1.208.228...
Connected to mx.viettelidc.com.vn.
Escape character is '^]'.
220 smtp-01.viettelidc.com.vn Ready to receive mail -=- ESMTP
Connection closed by foreign host.
2. ดู log grep หาเมล์ที่เกี่ยวข้อง เพื่อดูผลจากไฟล์ log
exigrep "@dhl.com" /var/log/exim/mainlog
exigrep "@tinhtue.vn" /var/log/exim/mainlog

3. ดูว่าคำสั่งที่ทำอะไรไป ผลลัพธ์ได้อะไร
exinext mail@xxx
exinext mail@xxx
error
Transport: mx1.dhl.iphmx.com [68.232.135.103/NULL] error 0: H=mx1.dhl.iphmx.com [68.232.135.103]: SMTP error from remote mail server after initial connection: 554-esa.dhl.iphmx.com\n554 Your access to this mail
หรือ
Transport: mx.viettelidc.com.vn [103.1.208.228/NULL] error 0: H=mx.viettelidc.com.vn [103.1.208.228]: SMTP error from remote mail server after initial connection: 451 Listed by SBL, see https://check.spamhaus.org

Telegram Bot + Code php อ่านค่า ESP8266 + Bot Command

 Telegram Bot + Code php อ่านค่า ESP8266 + Bot Command
สร้าง Bot
1. เข้า Telegram ค้นหา BotFather
2. กด /newbot
3. ตั้งชื่อ ใหม่มีคำว่า bot ต่อท้าย เช่น scivalve_bot
4. copy HTTP API token ไว้สำหรับใช้งาน
5. กด t.me/ชื่อ Bot เพื่อใช้งาน Bot
6. กด Start
7.เข้าดู Chat ID โดย เข้า XXXXX คือ Token ที่ได้จากข้อ 4.
https://api.telegram.org/botXXXXX/getUpdates
พิมพ์แชทกับ Bot แล้ว Reface หน้า Web link จะได้ Chat ID หรือ สร้าง Group เพิ่ม Bot เข้า แล้ว พิมพ์ ข้อความเพื่อดู Chat ID

1. Code Auto notify
Code file Extranet --> telegram_bot_auto.php
การใช้งาน Run หน้า php หรือตั้ง Crontab เพื่อเรียกใช้งานไฟล์ จะส่งเข้า Grop ไอซ์ที

2. Telegram Command
จะใช้ Command ได้ต้องเปิด Set Webhook ก่อน โดยเข้าไปที่
XXXXX คือ Token ที่ได้จากข้อ 4.
URL คือ Link ไฟล์ php ที่ต้องการเรียกใช้งาน และต้องเป็น HTTPS เช่น https://web/telegram_bot_command.php
เช่น
https://api.telegram.org/botXXXXX/setWe ... ommand.php
เรียกใช้คำสั่ง เพื่อดึงค่ามาแสดง
คำสั่งที่ใช้งานได้ /ฝุ่น หรือ /PM หรือ /PM2.5
Code file Extranet --> telegram_bot_auto.php


Arduino Code ส่งค่าจาก ESP8266 ไปใช้งานด้วย PHP

 Code สำเร็จ
- ต่อ Wifi
- Web Server
- อ่านค่า PM2.5 จาก Sensor PMS7003
PMS.h ก่อนจะใช้งานได้ต้องติดตั้ง PMS Library โดย เข้าไปที่
Sketch --> Include Library --> Manage Libraries --> ค้นหา PMS และติดตั้ง PMS Library

  1.  
  2. //############# Connect WIFI ####################//
  3. #include <ESP8266WiFi.h>
  4. #include <ESP8266WebServer.h>
  5.  
  6. const char* ssid     = "XXX";
  7. const char* password = "XXX";
  8.  
  9. //############# PMS ####################//
  10. #include "PMS.h"
  11. PMS pms(Serial);
  12. PMS::DATA data;
  13. String pm25Str = "-";
  14.  
  15. //############### Web Server ######################//
  16. ESP8266WebServer server(80);
  17.  
  18. void handleRoot() {
  19.   server.send(200, "text/plain", pm25Str);  // Send updated PM2.5 value
  20. }
  21.  
  22. void setup() {
  23.   Serial.begin(9600);
  24.  
  25.   // Connect to WiFi
  26.   WiFi.begin(ssid, password);
  27.   while (WiFi.status() != WL_CONNECTED) {
  28.     delay(1000);
  29.     Serial.println("Connecting...");
  30.   }
  31.   Serial.println("Connected!");
  32.  
  33.   // Start Web Server
  34.   server.on("/", handleRoot);
  35.   server.begin();
  36.   Serial.println("HTTP server started");  
  37. }
  38.  
  39. void loop() {
  40. /*
  41.   // Read data from PMS sensor
  42.   if (pms.read(data)) {
  43.     Serial.print("PM 1.0 (ug/m3): ");
  44.     Serial.println(data.PM_AE_UG_1_0);
  45.     Serial.print("PM 2.5 (ug/m3): ");
  46.     Serial.println(data.PM_AE_UG_2_5);
  47.     Serial.print("PM 10.0 (ug/m3): ");
  48.     Serial.println(data.PM_AE_UG_10_0);
  49.     Serial.println();
  50.  
  51.     pm25Str = String(data.PM_AE_UG_2_5);
  52.   }
  53. */
  54.   if (pms.read(data)) {
  55.     pm25Str = String(data.PM_AE_UG_2_5);
  56.     Serial.print("Updated PM2.5: ");
  57.     Serial.println(pm25Str);
  58.   }
  59.  
  60.   server.handleClient(); // Process web requests
  61.   //delay(1000);
  62. }