Hướng dẫn cài đặt và cấu hình Squid Proxy Server trên CentOS Stream 9: Kiểm soát truy cập Internet cho mạng nội bộ doanh nghiệp với SELinux và firewalld

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Bối cảnh: Khi nào doanh nghiệp cần Squid Proxy?

Mình bắt đầu tiếp xúc với Squid từ hồi còn làm sysadmin cho một công ty logistics. Lúc đó, bộ phận IT nhận khiếu nại từ HR rằng nhân viên đang xem YouTube trong giờ làm, bandwidth bị ngốn hết khiến các cuộc họp video call liên tục bị lag. Giải pháp lúc đó là dựng Squid Proxy — và nó xử lý xong trong vòng một buổi sáng.

Squid Proxy Server giúp bạn làm được những việc mà router thông thường không có:

  • Kiểm soát truy cập theo domain: Chặn YouTube, Facebook, TikTok theo danh sách, hoặc chỉ cho phép whitelist các site cần thiết
  • Kiểm soát theo giờ: Cho phép mạng xã hội trong giờ nghỉ trưa, chặn ngoài giờ đó
  • Cache nội dung: Nhiều máy tải cùng file — chỉ ra Internet một lần, tiết kiệm đáng kể băng thông
  • Audit log đầy đủ: Biết chính xác máy nào, IP nào đã vào website gì, lúc mấy giờ
  • Ẩn IP nội bộ: Client ra Internet qua IP proxy, không lộ topology mạng nội bộ

Công ty mình vẫn còn vài con server chạy CentOS 7, và việc migrate sang AlmaLinux là bài toán mình đã xử lý. Nhưng với các server proxy ít tải, team vẫn chọn CentOS Stream 9 vì chu kỳ hỗ trợ rõ ràng và tương thích tốt với RHEL ecosystem. Bài này mình sẽ hướng dẫn dựng Squid từ đầu, bao gồm cả xử lý SELinux và firewalld — hai thứ hay làm junior developer đau đầu nhất khi mới tiếp cận RHEL/CentOS.

Cài đặt Squid trên CentOS Stream 9

Bước 1: Cập nhật hệ thống và cài đặt Squid

Bắt đầu bằng việc cập nhật hệ thống, sau đó cài Squid từ repo mặc định của CentOS Stream 9:

sudo dnf update -y
sudo dnf install squid -y

Kiểm tra version vừa cài:

squid -v

Kết quả trả về thông tin build, trong đó có dòng Squid Cache: Version 5.x.

Bước 2: Khởi động và enable service

sudo systemctl enable squid --now
sudo systemctl status squid

Nếu thấy Active: active (running) là ổn. Squid mặc định lắng nghe trên port 3128.

Cấu hình chi tiết Squid

Tạo file cấu hình gọn

File mặc định /etc/squid/squid.conf có đến ~7000 dòng comment. Mình thường backup rồi viết lại file cấu hình gọn hơn cho dễ quản lý:

sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.backup
sudo nano /etc/squid/squid.conf

Dán nội dung cấu hình chuẩn cho môi trường doanh nghiệp:

# ============================================================
# Squid Proxy - Enterprise Config
# CentOS Stream 9
# ============================================================

# Port lắng nghe
http_port 3128

# === ACL: Định nghĩa mạng nội bộ ===
acl localnet src 192.168.0.0/16
acl localnet src 10.0.0.0/8
acl localnet src 172.16.0.0/12

# ACL chuẩn
acl SSL_ports port 443
acl Safe_ports port 80 443 8080 8443 21 70 210 280 488 591 777
acl CONNECT method CONNECT

# === ACL: Danh sách domain bị chặn ===
acl blocked_sites dstdomain "/etc/squid/blocked_sites.txt"

# === Rules ===
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny blocked_sites
http_access allow localnet
http_access allow localhost
http_access deny all

# === Cache ===
cache_dir ufs /var/spool/squid 1024 16 256
maximum_object_size 50 MB
cache_mem 256 MB

# === Log ===
access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log

# Ẩn thông tin server
via off
forwarded_for off
httpd_suppress_version_string on

Tạo danh sách website bị chặn

sudo nano /etc/squid/blocked_sites.txt

Nội dung ví dụ:

.youtube.com
.facebook.com
.tiktok.com
.netflix.com
.instagram.com

Lưu ý: Dấu chấm . trước domain sẽ chặn cả subdomain — ví dụ .youtube.com chặn luôn www.youtube.com, m.youtube.com, music.youtube.com.

Cấu hình ACL theo giờ làm việc

Tình huống thực tế: cho phép mạng xã hội trong giờ nghỉ trưa (12h–13h), chặn ngoài khung giờ đó:

# Thêm vào squid.conf (trước phần Rules)

# Giờ làm việc: Thứ 2-6, 8h-12h và 13h-18h
acl working_hours time MTWHF 08:00-12:00
acl working_hours time MTWHF 13:00-18:00

# Giờ nghỉ trưa
acl lunch_break time MTWHF 12:00-13:00

# Domain mạng xã hội
acl social_media dstdomain .facebook.com .youtube.com .tiktok.com

# Rules áp dụng:
http_access deny social_media working_hours
http_access allow social_media lunch_break localnet

Cấu hình SELinux cho Squid

Đây là phần nhiều người bỏ qua và sau đó thắc mắc tại sao Squid không chạy được dù config đúng. SELinux trên CentOS Stream 9 mặc định ở chế độ Enforcing.

Kiểm tra trạng thái:

getenforce
# Kết quả: Enforcing

Squid cần một số quyền SELinux đặc biệt. Port 3128 đã được SELinux cho phép mặc định, nhưng nếu bạn muốn đổi sang port khác (ví dụ 8080):

# Thêm port 8080 vào policy squid_port_t
sudo semanage port -a -t squid_port_t -p tcp 8080

# Kiểm tra lại
sudo semanage port -l | grep squid

Nếu Squid cần kết nối đến các port không chuẩn (ví dụ upstream proxy), bật boolean này:

sudo setsebool -P squid_connect_any 1

Khi gặp lỗi permission denied và không rõ SELinux đang chặn gì, đây là cách debug nhanh:

# Xem audit log các denial gần nhất
sudo ausearch -c 'squid' --raw | audit2allow -M my-squid

# Apply policy vừa tạo
sudo semodule -i my-squid.pp

Cấu hình firewalld

Mở port 3128 để client trong mạng nội bộ kết nối được đến proxy:

# Dùng service squid có sẵn trong firewalld (tiện hơn)
sudo firewall-cmd --zone=internal --add-service=squid --permanent

# Hoặc mở port trực tiếp nếu thích
sudo firewall-cmd --zone=internal --add-port=3128/tcp --permanent

# Apply
sudo firewall-cmd --reload

# Kiểm tra zone internal
sudo firewall-cmd --zone=internal --list-all

Kiểm tra interface mạng nội bộ thuộc zone nào, và chuyển nó sang zone internal nếu cần:

# Xem interface nào đang ở zone nào
sudo firewall-cmd --get-active-zones

# Ví dụ eth1 là interface nội bộ
sudo firewall-cmd --zone=internal --add-interface=eth1 --permanent
sudo firewall-cmd --reload

Validate config và restart Squid

Luôn kiểm tra syntax trước khi restart — tránh trường hợp config sai làm service không khởi động được:

# Parse và kiểm tra config
sudo squid -k parse

# Không có lỗi → restart
sudo systemctl restart squid

Kiểm tra và Monitoring

Test proxy từ client

Từ máy client trong mạng nội bộ, dùng curl để test qua proxy (thay 192.168.1.100 bằng IP thực của máy chạy Squid):

# Test truy cập bình thường
curl -x http://192.168.1.100:3128 http://example.com -I
# Mong đợi: HTTP/1.1 200 OK

# Test chặn domain
curl -x http://192.168.1.100:3128 http://www.youtube.com -I
# Mong đợi: HTTP/1.1 403 Forbidden

Xem log real-time

Access log Squid ghi lại toàn bộ hoạt động — đây là nguồn thông tin chính để audit:

sudo tail -f /var/log/squid/access.log

Mỗi dòng log có dạng:

1720123456.789  1234 192.168.1.50 TCP_MISS/200 5432 GET http://example.com/ - DIRECT/93.184.216.34 text/html
  • 1720123456.789: Unix timestamp
  • 1234: Thời gian xử lý (milliseconds)
  • 192.168.1.50: IP client
  • TCP_MISS/200: Cache miss, server trả HTTP 200
  • GET http://example.com/: Phương thức và URL đầy đủ

Xem thống kê Squid

# Thống kê tổng quan
sudo squidclient -h localhost mgr:info

# Cache hit rate
sudo squidclient -h localhost mgr:counters | grep -i hit

Script tìm top domain truy cập nhiều nhất

Hữu ích khi cần báo cáo hàng tuần cho quản lý:

#!/bin/bash
# Top 10 domain truy cập nhiều nhất trong log hiện tại
cat /var/log/squid/access.log | \
  awk '{print $7}' | \
  sed 's|http[s]*://||' | \
  cut -d'/' -f1 | \
  sort | uniq -c | \
  sort -rn | \
  head -10

Cấu hình log rotation

Môi trường nhiều user, log Squid có thể phình lên vài GB sau vài ngày. Cấu hình logrotate để tự dọn:

sudo nano /etc/logrotate.d/squid
/var/log/squid/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        /usr/sbin/squid -k rotate
    endscript
}

Xử lý lỗi thường gặp

Squid không start — lỗi permission:

# Kiểm tra SELinux có đang chặn không
sudo ausearch -m avc -ts recent | grep squid

# Debug nhanh: tạm set permissive (CHỈ để test, không dùng production)
sudo setenforce 0
sudo systemctl restart squid
# Nếu chạy được → vấn đề là SELinux → dùng audit2allow để fix đúng cách
sudo setenforce 1

Client không kết nối được qua proxy:

# Squid đang listen port nào?
sudo ss -tlnp | grep squid

# Firewall có đang block không?
sudo firewall-cmd --list-all --zone=internal

# Thử telnet từ client đến proxy
telnet 192.168.1.100 3128

Sau khi dựng Squid xong và hệ thống chạy ổn định, bước tiếp theo mình thường làm là chuyển sang transparent proxy — client không cần cấu hình proxy thủ công, mọi traffic HTTP tự động đi qua Squid nhờ iptables redirect. Nhưng đó là câu chuyện phức tạp hơn, cần kết hợp thêm SSL bump để inspect HTTPS traffic — để dành cho bài khác.

Share: