--- title: Linux 中階 tag: Linux 2026 --- 合作與邀約 naxchang@gmail.com # Linux 非本科系學程式找工作 <details> <summary>📁 學習總進度</summary> | 時間 | 主題 | 狀態 | |-----------------------|--------------------------|------------| | 2026/01/01 - 2026/03/06 | ⚡ Linux RHCSA入門到初階 | ⏳ 進行中 | | 2026/03/07 - 2026/04/26 | ⚡ Linux 網路管理 與 trouble shooting | ⏸️ 尚未開始 | | 2026/04/27 - 2026/06/22 | ⚡ Linux RHCSA進階 與 trouble shooting | ⏸️ 尚未開始 | **note:** `Linux從2025/06/22正式開始 預計會錄製到2026/06/21` </details> --- <details> <summary>📁 預計課表</summary> | 時間 | 主題 | 備註 | |------------|------------------------------------|--------------------| | 2月5日 | chown / chgrp 管理檔案與目錄擁有權限 | ✅ 已完成 | | 2月6日 | ACL Access Control List | ✅ 已完成 | | 2月7日 | 管理用戶 User & Groups | ✅ 已完成 | | 2月8日 | chage 檢查、passwd 修改與群組操作 | ✅ 已完成 | | 2月9日 | su / sudo 權限切換與管理 | ✅ 已完成 | | 2月10日 | 檔案封裝與壓縮快速入門 | ✅ 已完成 | | 2月11日 | dnf 套件使用 | ✅ 已完成| | 2月12日 | sed用法 | ✅ 已完成| | 2月14日 | systemd timedatectl review | ✅ 已完成| | 2月15日 | 排程工具 at cron | ✅ 已完成| | 2月16日 | ps jobs | ✅ 已完成| | 2月17日 | Linux 背景工作與優先級操作 | ✅ 已完成| | 2月18日 | 網路工具ping ss | ✅ 已完成| | 2月21日 | podman | ✅ 已完成| | 2月21日 | ssh免密碼連線 | ✅ 已完成| | 2月27日 | 使用 ip指令操作介面與地址 | ✅ 已完成 | | 3月1日(日) | namespace | ✅ 已完成 | | 3月2日(一) | nmcli | ✅ 已完成 | | 3月3日(二) | DNS | ✅ 已完成| | 3月4日(三) | iptables封鎖與開放連線操作 | ✅ 已完成| | 3月8日(日) | ip指令 | ✅ 已完成| | 3月9日(一) | netplan ip 設定 | ✅ 已完成| | 3月11日(三) | ip neighbor/ apr| ✅ 已完成| | 3月15日(五) | Bonding Active-Backup主備備援實作 | ✅ 已完成| </details> --- <details> <summary>📁 學習目錄</summary> - [指令補充](#第0-00天) - [RedHat系統dnf套件管理:安裝更新與安全維護](#第0-01天) - [Linux sed 文字處理:高效替換與刪除實務](#第0-02天) - [從零開始學 systemd:服務管理與時區設定](#第0-03天) - [Linux 檔案封裝與壓縮快速入門](#第0-0天) - [stdout與stderr導向文件](#第0-1天) - [vim文字編輯器](#第0-2天) - [Linux 從零開始指令實務速成|不廢話實戰](#第1天) - [Linux基礎指令加強](#第2-1天) - [Linux-grep正規表示式及使用者帳號管理](#第2-2天) - [文件與目錄權限介紹及umask設定](#第2-3天) - [管理用戶user and groups](#第2-4天) - [su 與 sudo 到底差在哪?Linux 使用者切換與權限提升](#第2-5天) - [Linux 排程任務管理:at、cron 與 systemd timer](#第1-9天) - [常用指令快速上手:shutdown、reboot、poweroff](#第2天) - [使用ip指令操作介面與地址](#第3天) - [Firewalld-基礎操作:查詢狀態與新增防火牆規則](#第4天) - [使用systemctl管理Linux服務](#第5天) - [managing jobs](#第6天) - [journalctl相關操作](#第7天) - [MariaDB安裝與連線](#第8天) - [MySQL 8.0 安裝(RHEL 8 / RPM)](#第9天) - [設定SSH金鑰免密登入伺服器主機](#第10天) - [LVM邏輯卷建立與容量擴展實作](#第11天) - [Nginx 反向代理進階 Upstream 群組管理與 SELinux 設定](#第12天) - [設定SELinux規則讓Apache可讀取/web目錄](#第13天) - [Managing Apache HTTP Services](#第14天) - [短名與預設 registry:Podman 自動拉取映像機制](#第14-1天) - [Podman-啟動、進入、暫時離開 (detach) 以及停止容器](#第15天) - [Podman-自建容器image上傳到 Docker Hub](#第16天) - [Ansible 的 Loop 與 Items](#第17天) - [使用 Ansible 變數建立使用者與系統資訊](#第18天) - [shell scripts](#第19天) - [從本地到容器:Flask 應用 Docker 化實戰](#第20天) - [Linux 排程實務:cron、at 與 systemd timer](#第21天) - [在Ubuntu容器中安裝 Python 並執行程式](#第22天) - [Linux 網路工具與 ping / ss 快速檢查連線](#第23天) - [從零建立Linux網路Namespace:veth虛擬連線讓兩個隔離空間互相ping通](#第24天) - [Linux 網管:使用 nmcli 建立永久連線並設定靜態 IP](#第25天) - [Linux 防火牆:iptables封鎖與開放連線操作](#第26天) - [ 3/8 網路管理](#第27天) - [Bonding Active-Backup主備備援實作](#第28天) </details> <a id="第0-00天"></a> # 指令補充 ```bash= sudo apt install open-vm-tools open-vm-tools-desktop ``` ```bash= ss -ntu Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process udp ESTAB 0 0 192.168.132.128%ens33:68 192.168.132.254:67 ``` <a id="第0-01天"></a> # RedHat系統dnf套件管理:安裝更新與安全維護 1️⃣ yum 與 dnf ```bash= which yum which dnf ls -l /bin/yum ls -l /bin/dnf yum --version dnf --version ``` 2️⃣ 查看套件來源 (Repository) ```bash= dnf repolist ``` 3️⃣ 查詢套件 ```bash= # 查單一套件 dnf list httpd dnf list git # 使用萬用字元 dnf list git* ``` 4️⃣ 安裝 / 移除套件 ```bash= 安裝 dnf install git dnf install -y git 移除 dnf remove git dnf remove -y git ``` 5️⃣ 套件操作紀錄 ```bash= dnf history dnf history undo 26 # 還原指定操作 ``` 6️⃣ 查看更新資訊 ```bash= dnf updateinfo ``` 7️⃣ 只看安全更新 ```bash= dnf updateinfo --security ``` 8️⃣ 查看 Important 等級安全更新 ```bash= dnf updateinfo info --sec-severity Important ``` 9️⃣ 依安全公告更新 ```bash= dnf update --advisory RLSA-2025:7569 # 注意,需要換成自己的編號 ``` 🔟 更新後再次確認 ```bash= dnf updateinfo --security ``` 1️⃣1️⃣ 檢查可更新套件 ```bash= dnf check-update ``` 1️⃣2️⃣ 全部更新 ```bash= sudo dnf update sudo dnf update -y ``` 1️⃣3️⃣ 只更新安全更新 ```bash= sudo dnf update --security ``` <a id="第0-02天"></a> # Linux sed 文字處理:高效替換與刪除實務 - 原始內容: ```bash= John Anderson Michael Brown David Johnson Robert Taylor Daniel Martinez Chris Wilson Chris Wilson James Thompson Kevin Moore Brian Jackson Anthony White ``` ## sed練習 ```bash= 1. 基本替換 # 替換文字 sed 's/舊字串/新字串/g' sed_name # g = 全部替換 sed -i 's/舊字串/新字串/g' sed_name # -i = 直接改檔案 2. 查看檔案 cat sed_name # 直接看檔案 cat -n sed_name # 顯示行號 3. 替換範例 cp sed_name sed_name.bak # 備份檔案 sed 's/Chris/Colin/g' sed_name # 螢幕上看結果 sed -i 's/Chris/Colin/g' sed_name # 直接改檔 sed -i 's/Colin//g' sed_name # 刪掉字串 4. 刪除整行 sed '/Wilson/d' sed_name # 刪掉含 Wilson 的行(不改檔) sed -i '/Wilson/d' sed_name # 直接改檔 5. 刪除空白行 sed '/^$/d' sed_name # 刪掉空白行(不改檔) sed -i '/^$/d' sed_name # 直接改檔 6. 刪除特定行 sed '1d' sed_name # 刪掉第一行 sed '1,2d' sed_name # 刪掉前兩行 7. Tab 與空白替換 # Tab → 空白 sed 's/\t/ /g' sed_name sed -i 's/ / /g' sed_name # 直接改檔(鍵盤 Tab) # 空白 → Tab sed 's/ / /g' sed_name # 先看效果 sed -i 's/ / /g' sed_name # 直接改檔 8. 查看指定行 sed -n '16,20p' sed_name # 只看第 16~20 行 sed '16,20d' sed_name # 刪掉第 16~20 行,其他行照常顯示 9. 單行替換 # 只改第 4 行的第一個 Brown sed '4s/Brown/Jason/' sed_name sed -i '4s/Brown/Jason/' sed_name # 除了第 4 行,其他行都改第一個 Brown sed '4!s/Brown/Jason/' sed_name sed -i '4!s/Brown/Jason/' sed_name ``` - 製作結果: ![image](https://hackmd.io/_uploads/rkEPdc2P-g.png) <a id="第0-03天"></a> # 從零開始學 systemd:服務管理與時區設定 1️⃣ 確認 systemd 與 PID 1 ```bash= ls -l /sbin/init pstree -p | less ``` 2️⃣ 查看登入 session ```bash= loginctl list-sessions ``` 3️⃣ 列出所有運作中的 unit ```bash= systemctl list-units ``` 4️⃣ 查看特定 unit 狀態 ```bash= systemctl status sshd.service systemctl status chronyd.service ``` 5️⃣ 啟動 / 停止服務 ```bash= # 停止 systemctl stop chronyd.service # 啟動 systemctl start chronyd.service ``` 6️⃣ 重新啟動服務 ```bash= systemctl restart chronyd.service ``` 7️⃣ 設定開機自動啟動 / 停用 ```bash= # 停用開機自動啟動 systemctl disable chronyd # 啟用並立即啟動 systemctl enable --now chronyd ``` 8️⃣ 查看系統時間 ```bash= date timedatectl ``` 9️⃣ 查詢可用時區 ```bash= timedatectl list-timezones ``` 🔟 設定時區 ```bash= # 設定為多倫多時間 timedatectl set-timezone America/Toronto # 切換回台北時間 timedatectl set-timezone Asia/Taipei ``` - 製作結果: ![image](https://hackmd.io/_uploads/rkfK0yRvbg.png) <a id="第0-0天"></a> # Linux 檔案封裝與壓縮快速入門 | 指令 / 工具 | 功能 | 語法範例 | 說明 | | ----------- | ------------ | --------------------------------- | ----------------------------- | | tar | 打包多個檔案或目錄 | tar -cf file.tar file1 file2 | -c 建立封裝檔,-f 指定檔名 | | tar -t | 查看打包檔案內容 | tar -tf file.tar | -t 列出封裝檔內容(table of contents) | | tar -x | 解壓縮檔案 | tar -xf file.tar | -x 解壓縮(extract) | | tar + gzip | 打包並壓縮成 gzip | tar -czf file.tar.gz file1 file2 | -z 表示使用 gzip | | tar + bzip2 | 打包並壓縮成 bzip2 | tar -cjf file.tar.bz2 file1 file2 | -j 表示使用 bzip2 | | gzip | 壓縮單一檔案 | gzip file.txt | 生成 .gz | | gunzip | 解壓縮 gzip | gunzip file.txt.gz | 將 .gz 還原為原始檔案 | | bzip2 | 壓縮單一檔案 | bzip2 file.txt | 生成 .bz2 | | bunzip2 | 解壓縮 bzip2 | bunzip2 file.txt.bz2 | 將 .bz2 還原為原始檔案 | ```bash= 1. tar 基本概念 -c 建立封裝檔 -t 查看封裝檔內容 (table of contents) -x 解開封裝檔 (extract) -f 指定檔名 2. 查看磁碟使用量 du -h /etc # human readable, 列出每個子目錄 du -sh /etc # summary, 只看總大小 3. 建立 tar 封裝 mkdir tmp; cd tmp tar -cf etc.tar /etc ls -lh etc.tar # 打包前 32MB, 打包後約 30MB 4. 查看 tar 內容與解壓 tar -tf etc.tar # 列出封裝內容 tar -xf etc.tar # 解壓 ls -l etc # 確認還原 5. gzip / gunzip 壓縮單檔案 gzip etc.tar # 壓縮成 etc.tar.gz ls -lh gunzip etc.tar.gz # 解壓回 etc.tar 6. bzip2 / bunzip2 bzip2 etc.tar # 壓縮成 etc.tar.bz2 ls -lh # 大小比 gzip 小 bunzip2 etc.tar.bz2 # 解壓回 etc.tar 7. 壓縮速度比較 time gzip etc.tar # 幾乎瞬間完成 time bzip2 etc.tar # 比 gzip 慢, 但壓縮比更高 8. tar + gzip 一次打包壓縮 tar -czf etc.tar.gz etc # -z 表示 gzip ls -lh # 查看檔案大小 tar -xzf etc.tar.gz # 解壓 rm -rf etc.tar.gz # 清理 9. tar + bzip2 一次打包壓縮 tar -cjf etc.tar.bz2 etc # -j 表示 bzip2 ls -lh # 查看檔案大小 tar -xjf etc.tar.bz2 # 解壓 rm -rf etc.tar.bz2 # 清理 10. tar + gzip/bzip2 顯示過程 tar -czvf etc.tar.gz etc # 打包時列出每個檔案 tar -xzvf etc.tar.gz # 解壓時列出每個檔案 ``` <a id="第0-1天"></a> # stdout與stderr導向文件 ```bash= # 1. 創建空文件 touch test.txt file test.txt # 顯示 empty # 2. 寫入內容(覆蓋) echo 0129 > test.txt cat test.txt # 查看內容 # 3. 寫入新內容(覆蓋原本) echo hello > test.txt cat test.txt # 4. 追加內容 echo hello >> test.txt echo hello >> test.txt cat test.txt # 內容會累加 # 5. 輸出重導向範例 cat /etc/hosts > test.txt cat test.txt # 6. 標準錯誤不會被 > 導入 ls -l /etc/host > error.txt cat error.txt # 空檔 # 7. 標準輸出與標準錯誤示範 ls -l /etc/hosts /etc/host ls -l /etc/hosts /etc/host > test.txt cat test.txt # 8. 只把錯誤訊息導入檔案 ls -l /etc/hosts /etc/host 2> error.txt cat error.txt # 9. stdout + stderr 全部導入同一檔案 ls -l /etc/hosts /etc/host &> all.txt cat all.txt # 10. 追加模式 ls -l /etc/hosts /etc/host &>> all.txt ls -l /etc/hosts /etc/host 2>> error.txt cat error.txt # 11. 創建文件(Here Document) cat > demo.txt << EOF this is here document EOF cat demo.txt ``` - 製作結果: ![image](https://hackmd.io/_uploads/Bk52GTtIZg.png) --- <a id="第0-2天"></a> # vim文字編輯器 2026/01/30 ```bash= 1️⃣ 模式操作 i :在游標前方插入文字 a :在游標後方插入文字 o :在下一行開新行並插入 I :在行首插入 A :在行尾插入 ESC :離開 Insert Mode,回到 Normal Mode 2️⃣ 存檔與退出 :w :存檔 :q :離開 Vim :q! :不存檔強制退出 :wq :存檔後退出 3️⃣ 復原與操作 u :復原上一步操作 yy :複製整行 dd :刪除整行 p :貼在游標後 P :貼在游標前 4️⃣ 游標移動 h :向左 l :向右 j :向下 k :向上 0 :跳到行首 $ :跳到行尾 gg :跳到檔案第一行 G :跳到檔案最後一行 w :跳到下一個單字開頭 b :跳到前一個單字開頭 5️⃣ 搜尋與取代 /Nco :搜尋文字 Nco n :搜尋下一筆 N :搜尋上一筆 :s/Nco/No/ :取代當前行第一個匹配 :%s/Nco/No/g :取代整個檔案所有匹配 :%s/20260130/0130/gc :整個檔案取代 20260130 → 0130,每筆都確認 6️⃣ 系統相關 vim --version | head -n 1 :查看 Vim 版本 dnf install -y vim :安裝 Vim(Fedora / RHEL 系統) ``` --- <a id="第1天"></a> # Linux 從零開始指令實務速成|不廢話實戰 ```bash= ## SSH 遠端登入 ssh ansible@192.168.88.131 ssh server@192.168.88.130 exit Ctrl+D ## 查看 IP 位址 ifconfig ip addr ip a ## 目錄與路徑操作 pwd cd / cd .. cd - cd cd ~ ## 檔案與使用者資訊 whoami hostname ## 建立檔案 touch demo1 touch demo_2 touch demo_{2..4} ## 清除畫面 clear Ctrl+L ## 列出檔案 ls ls -l ls -la ls -ltr ## 檔案複製 cp demo_2 demo_3 cp demo_1 demo_4 cp demo_1 /tmp ## 文字編輯(vi) vi demo_1 i Esc :q :q! :wq ## 刪除檔案 rm demo_1 demo_2 rm demo_{3..4} ## 建立與切換目錄 mkdir dir_1 mkdir dir_{2..3} cd dir_1 cd .. cd dir_2 cd ../dir_3 ## 寫入與查看檔案內容 echo "demo to demo_1" > demo_1 cat demo_1 ## 檔案搬移與改名 mv demo_2 dir_1 mv demo_2 dir_demo_1 ## 多層目錄操作 mkdir -p dir_1-1/dir_1-2/dir1-3 ls -R rm -r dir_1-1 ## 空目錄刪除 mkdir dir_1-1 rmdir dir_1-1 touch dir_1-1/file_1 rmdir dir_1-1 ## 終端機快捷鍵 Ctrl+a Ctrl+e Ctrl+w Alt+d Ctrl+u Ctrl+k ## 指令說明文件 ls --help man ls / q ## 系統檔案操作 sudo cp /etc/passwd . ls ## 檔案檢視工具 cat passwd more passwd less passwd ## 查看檔案開頭與結尾 head passwd head -n 5 passwd tail passwd tail -n 3 passwd ``` --- <a id="第2-1天"></a> # Linux基礎指令加強 2026/02/01 ```bash= # 1. 切換到 root 的家目錄 cd ~ # 2. 查看目前目錄 pwd # 3. 切換到 /home cd /home ls # 4. 切換到根目錄 cd / # 5. 切換回 root 家目錄 cd ~ # 6. 進入 /etc 目錄 cd /etc ls # 7. 建立目錄 cd /home mkdir dir_1 ls -l mkdir dir_1/dir_2 cd dir_1 ls # 8. 建立多層目錄 cd /home mkdir -p dir_3/dir_4/dir_5 tree dir_3 # 9. 刪除檔案 cd /home rm all.txt rm -f test.txt # 10. 刪除目錄 rm -r dir_1 rm -rf dir_3 # 11. 複製檔案 cp demo.txt demo_1.txt mv demo_1.txt demo_2.txt # 12. 批次建立檔案 mkdir test cd test touch file{1..10} ls # 13. 檔名匹配操作 ls file1* ls file1? mkdir tmp cp file1? tmp rm -f tmp/* mv file? tmp/ ls tmp/ # 14. 顯示檔案內容 cat /etc/passwd # 15. 分頁瀏覽 more /etc/passwd less /etc/passwd # 16. less 搜尋 less /etc/passwd # 搜尋 /sshd # n:下一個, N:上一個 # 17. 查看前後幾行 head /etc/passwd head -n3 /etc/passwd head -n1 /etc/passwd tail /etc/passwd tail -n3 /etc/passwd # 18. 即時監控日誌 tail -f /var/log/messages ``` <a id="第2-2天"></a> # Linux-grep正規表示式及使用者帳號管理 (2026/02/02) ```bash # grep 基本操作 cat /etc/passwd cat /etc/passwd | grep root cat /etc/passwd | grep -n root ls -l ls -l | grep test grep root /etc/passwd grep -vn nologin /etc/passwd # grep 正規表示式 grep -n ^root /etc/passwd # sshd_config 過濾 cat /etc/ssh/sshd_config grep ^# /etc/ssh/sshd_config grep -vn ^# /etc/ssh/sshd_config grep -vnE "(^$|^#)" /etc/ssh/sshd_config # 遞迴搜尋 password grep -r password /etc/ grep -rl password /etc/ # 大小寫處理 grep -rE "[Pp]assword" /etc/ grep -ri password /etc/ # 使用者帳號管理 id lisa useradd lisa passwd lisa su lisa pwd cd pwd exit userdel -r lisa id lisa ``` <a id="第2-3天"></a> # 文件與目錄權限介紹及umask設定 ```bash= # 1. 切換使用者 id lisa su lisa whoami groups pwd # 2. 在 /root 嘗試建立檔案 touch test.txt # 3. 回到家目錄建立檔案 cd echo test > test.txt ls -la # 4. 查看檔案權限 ls -l all.txt ls -l test.txt # 5. 建立目錄並查看權限 mkdir test ls -l # 6. 查看 umask umask # 7. 改變 umask 並建立檔案 umask 0022 rm test.txt touch test.txt ls -l test.txt # 8. 刪除目錄並重新建立 rm -r test mkdir test ls -l # 9. 使用符號方式設定 umask umask -S umask u-w umask -S # 10. 建立只讀檔案測試 touch test1.txt ls -l test1.txt rm -rf test1.txt touch test1.txt vim test1.txt ``` ## umask設定與chmod遞迴改權限 (2026/02/04) ```bash= # 1️⃣ 建立檔案 touch file_1 ls -l file_1 # 2️⃣ 改權限:所有人讀寫 chmod -v 666 file_1 # 3️⃣ 擁有者加執行權限 rm -f file_1 touch file_1 chmod -v u+x file_1 # 4️⃣ 群組加寫入權限 chmod -v g+w file_1 # 5️⃣ 其他人加執行權限 chmod -v o+x file_1 # 6️⃣ 數字方式一次改所有人執行權限 rm -f file_1 touch file_1 chmod -v 755 file_1 ls -l file_1 # 7️⃣ 符號模式一次改所有人執行權限 rm -f file_1 touch file_1 chmod -v a+x file_1 # 8️⃣ 改 umask umask 007 rm -f file_1 touch file_1 ls -l file_1 # 9️⃣ 建立多層目錄 mkdir -p u/{d1,d2} ls -lR # 10️⃣ 在多個子目錄建立檔案 touch u/{d1,d2}/file ls -lR u # 11️⃣ 遞迴加執行權限 chmod -R a+x u ls -lR u # 12️⃣ 詳細模式查看改動 chmod -vR a+x u ``` - 製作結果: ![image](https://hackmd.io/_uploads/rkxVJ2LlPZl.png) ## chown chgrp 管理檔案與目錄擁有權限 (2026/02/05) ```bash 1️⃣ 建立環境(使用者 lisa) su lisa rm * cd ls mkdir test cd test mkdir file_01 touch test.txt ls -l 2️⃣ 在 file_01 內建立檔案,查看結構 cd file_01 touch test.txt cd .. ls -lR test 3️⃣ 切回 root,確認位置與目錄結構 exit whoami pwd cd /home/lisa/ ls -lR test 4️⃣ 修改檔案 owner(test.txt) cd test ls -l chown root test.txt ls -l test.txt 5️⃣ 修改檔案 group(test.txt) chgrp root test.txt ls -l test.txt 6️⃣ 同時修改 owner 與 group(改回 lisa) chown lisa:lisa test.txt ls -l test.txt 7️⃣ 使用簡寫方式同時改 owner 與 group(改成 root) chown root: test.txt ls -l test.txt 8️⃣ 修改目錄 owner(file_01) chown lisa: test.txt ls -l chown root: file_01 ls -l 9️⃣ 遞迴修改目錄與內部檔案 owner ls -l file_01/ chown lisa: file_01 ls -lR file_01/ chown -R root: file_01 ls -lR file_01/ ``` - 製作結果: ![image](https://hackmd.io/_uploads/SkciQcZwbg.png) <a id="第0-1天"></a> ## Linux ACL:精準控制檔案使用者權限 (2026/02/05) ```bash # 前置作業 sudo su - mkdir tmp cd tmp touch test.txt ls -l test.txt # 切換使用者 su lisa cd /root/tmp ls -l # 查看 ACL getfacl /root/tmp/test.txt # 回到 root 增加 Lisa 寫入權限 sudo setfacl -m u:lisa:rw /root/tmp/test.txt # Lisa 查看 ACL getfacl test.txt ls -l # Lisa 編輯檔案測試 vi test.txt cat test.txt ls -l # 收回寫入權限 sudo setfacl -x u:lisa test.txt # Lisa 嘗試修改 vi test.txt ``` - 結果參考 ![image](https://hackmd.io/_uploads/H131ihWPWx.png) <a id="第2-4天"></a> # 管理用戶user and groups (2026/02/05) ```bash= whoami # 查看目前登入的使用者名稱 id # 查看目前使用者的 UID/GID/所屬群組 id lisa # 查看指定使用者 lisa 的資訊 cat /etc/passwd # 查看系統所有使用者的基本資訊 grep lisa /etc/passwd # 找出 lisa 的使用者資料 grep lisa /etc/shadow # 查看加密密碼欄位(不可讀) useradd user1 # 建立新使用者 user1 id user1 # 查看 user1 的 UID/GID/群組 grep user1 /etc/passwd # 查看 user1 的詳細資訊 cat /etc/group # 查看系統所有群組 grep user1 /etc/group # 查看 user1 所屬群組 useradd -D # 查看 useradd 的預設配置 man useradd # 查看 useradd 說明與選項 useradd -N -M -g user1 user2 # 建立特殊用戶 user2:無家目錄、無同名群組、主要群組是 user1 id user2 # 查看 user2 的 UID/GID/群組 ls /home # 查看家目錄列表 ls -ld /home/user* # 查看所有以 user 開頭的家目錄,驗證 -M 是否生效 ``` 製作結果: ![image](https://hackmd.io/_uploads/B1dUGyGw-x.png) ## 精細掌控 Linux 使用者與群組的建立、編輯與刪除 (2026/02/06) ```bash= # 查看目前登入使用者 whoami # 查看使用者資訊 id id lisa # 查看所有使用者 cat /etc/passwd # 查詢指定使用者 grep lisa /etc/passwd # 查詢使用者密碼雜湊 grep lisa /etc/shadow # 建立使用者 useradd user1 # 查看新使用者資訊 id user1 # 查詢使用者設定 grep user1 /etc/passwd # 查看群組 cat /etc/group grep user1 /etc/group # 查看 useradd 預設設定 useradd -D # 查看 useradd 說明 man useradd # 建立使用者(不建家目錄、不建同名群組、指定主要群組) useradd -N -M -g user1 user2 # 驗證使用者 id user1 id user2 # 查看家目錄 ls /home ls -ld /home/user* # 刪除使用者(不刪家目錄) userdel user1 # 刪除使用者(含家目錄) userdel -r user1 # 修改使用者主要群組 usermod -g nginx user2 # 刪除群組 groupdel user1 ``` ## Linux 使用者管理:建立、群組與密碼操作 (2026/02/07) ```bash= 1️⃣ 建立使用者 useradd user1 useradd user2 重複建立會出現: useradd user1 # user 'user1' already exists 2️⃣ 將 user2 加入 user1 群組(使用者已存在) usermod -aG user1 user2 id user2 id user1 3️⃣ 刪除使用者與群組保留行為 userdel user2 grep user* /etc/group (user1 群組仍存在) 4️⃣ 同名群組已存在時建立使用者 useradd user1 # group user1 exists useradd -g user1 user1 id user1 5️⃣ 建立 user2 並加入群組(建立時指定) useradd user2 id user1 id user2 userdel user2 useradd -G user1 user2 id user2 6️⃣ 重新建立 user2(單一群組) userdel user2 useradd user2 id user2 7️⃣ 建立後修改群組(覆蓋 vs 追加) usermod -G user1 user2 id user2 追加方式: usermod -aG user1 user2 id user2 8️⃣ 使用 primary / secondary group 建立檔案 su user2 cd id touch test.txt ls -l 9️⃣ 切換 current group newgrp user1 touch test1.txt ls -l 🔟 重建使用者並查看密碼檔 id user1 id user2 userdel user1 userdel user2 clear useradd user1 grep user1 /etc/shadow ls -l /etc/shadow 1️⃣1️⃣ 設定密碼 passwd user1 grep user1 /etc/shadow 1️⃣2️⃣ 使用者切換(su) useradd user2 passwd user2 su - user2 su - user1 ``` - 製作結果: ![image](https://hackmd.io/_uploads/H1YAs8Ev-e.png) ## Linux 密碼管理進階實戰:getent、加密演算法 (2026/02/07) ```bash= # 查詢 getent 可用資料庫 getent --help # 查詢使用者帳號資訊 getent passwd user1 # 查詢使用者 shadow 資訊 getent shadow user1 # 直接查看 passwd / shadow grep user1 /etc/passwd grep user1 /etc/shadow # 查看密碼預設規則 cat /etc/login.defs # 修改密碼有效期限 passwd -n 30 -x 60 -w 10 user1 # 再次確認 shadow 內容 getent shadow user1 # 編輯 PAM 密碼設定 vi /etc/pam.d/system-auth # 更新使用者密碼 passwd user1 # 檢查加密演算法是否變更 getent shadow user1 # 使用 OpenSSL 嘗試產生 hash openssl passwd -6 -salt 21KksCKhl62hMXbT user1 # Python 驗證(crypt 模組) python3 test_hash.py ``` python程式參考 ```python= import crypt password = "user1" # 假設密碼是 user1 salt = "$6$rounds=100000$21KksCKhl62hMXbT$" # 注意格式,去掉開頭的 / hashed = crypt.crypt(password, salt) print(hashed) ``` - 製作結果: ![image](https://hackmd.io/_uploads/HkU8FiNDWg.png) ## Linux-密碼管理與策略設定實務操作 (2026/02/08) ```bash= # 查看密碼政策 chage -l user1 # 修改使用者密碼(互動式) passwd user1 # 非互動式修改密碼(支援 --stdin 的系統) echo user1 | passwd user1 --stdin # 查看使用者密碼雜湊值 getent shadow user1 # 使用 chpasswd 修改密碼(非互動式) echo "user1:user1" | chpasswd # 查看修改後的密碼雜湊值 getent shadow user1 # 查看密碼狀態 passwd -S user1 # 鎖定密碼 passwd -l user1 # 解鎖密碼 passwd -u user1 # 查 passwd 命令參數 man passwd ``` ## Linux 群組管理指令與使用者群組操作 ```bash # 查看使用者資訊與群組 id user1 # 查看 user1 的 UID、GID、次要群組 getent group user1 # 查詢 user1 所在群組 getent passwd user1 # 查看 user1 的使用者資訊與主要群組 # 建立群組 groupadd group1 # 新增群組 group1 getent group group1 # 確認 group1 是否建立成功 groupadd group2 # 新增群組 group2 getent group group2 # 確認 group2 是否建立成功 # 刪除群組 groupdel group1 # 刪除 group1 getent group group1 # 確認 group1 已不存在 groupdel group2 # 刪除 group2 getent group group2 # 確認 group2 已不存在 # 修改使用者次要群組 usermod -G group1 user1 # 設定次要群組為 group1(會覆蓋原本的) id user1 # 查看次要群組 # 覆蓋與新增次要群組 groupadd group2 usermod -G group2 user1 # 覆蓋次要群組為 group2 id user1 usermod -aG group1 user1 # 新增 group1 為次要群組,不覆蓋原有 id user1 # 使用 gpasswd 管理群組成員 groupadd group3 gpasswd -a user1 group3 # 將 user1 加入 group3 id user1 gpasswd -d user1 group3 # 將 user1 從 group3 移除 id user1 # 實驗主要與次要群組刪除 groupdel user1 # 嘗試刪除主要群組(會失敗) groupdel group2 # 刪除次要群組 id user1 # 查看結果 ``` - 製作結果: ![image](https://hackmd.io/_uploads/SJUCYl8vbx.png) <a id="第2-5天"></a> # su 與 sudo 到底差在哪?Linux 使用者切換與權限提升 ## su ```bash= userdel -r user1 # 刪除 user1 帳號及家目錄 userdel -r user2 # 刪除 user2 帳號及家目錄 useradd user1 # 新增 user1 帳號 id user1 # 查看 user1 的 UID、GID 和群組 passwd -S user1 # 查看 user1 密碼狀態 (locked/unlocked) su user1 # 切換到 user1 (保留目前環境路徑) pwd # 查看目前所在路徑 su - user1 # 切換到 user1 並載入完整登入環境 pwd # 查看目前所在路徑 (應該在 /home/user1) exit # 退出 user1 回到上一個使用者 passwd user1 # 設定 user1 的密碼 useradd user2 # 新增 user2 帳號 su user2 # 切換到 user2 su user1 # 從 user2 切換到 user1 (需輸入密碼) Ctrl + D # 登出目前使用者,回到上一層 su user2 # 由 root 切換到 user2 passwd -S user2 # 查看 user2 密碼狀態 passwd -S user2 # 再次查看 user2 密碼狀態 passwd -S user1 # 查看 user1 密碼狀態 ``` - 製作結果: ![image](https://hackmd.io/_uploads/H17152LPWe.png) ## sudo 權限管理與 visudo 安全設定 ```bash= # ========== sudo 基本概念 ========== # 切換到 user1 su - user1 cd # 嘗試讀取 shadow(會失敗) cat /etc/shadow # Permission denied # 使用 sudo(會失敗) sudo cat /etc/shadow # user1 is not in the sudoers file # ========== 查看 sudoers 設定 ========== # 回到 root exit # 查看 sudoers 內容 cat /etc/sudoers # 手動編輯 sudoers(不推薦) vim /etc/sudoers # 加入這一行: # user1 ALL=(ALL) ALL # 存檔 :wq! # ========== 測試 sudo 權限 ========== # 切換到 user1 su - user1 cd # 測試 sudo sudo cat /etc/shadow # 輸入密碼 user1,成功 # 查看 sudoers sudo cat /etc/sudoers # ========== wheel 群組管理 ========== # 回到 root exit # 移除 user1 的 sudoers 設定 vim /etc/sudoers # 刪除 user1 那一行 # :wq! # 切換到 user1 測試 su - user1 sudo cat /etc/shadow # user1 is not in the sudoers file # 回到 root exit # 將 user1 加入 wheel 群組 usermod -aG wheel user1 # 切換到 user1 測試 su - user1 sudo cat /etc/shadow # 成功! # ========== 移除 wheel 群組 ========== # 回到 root exit # 從 wheel 群組移除 user1 gpasswd -d user1 wheel # ========== visudo 安全編輯 ========== # 加回 user1 權限 vim /etc/sudoers # 加入:user1 ALL=(ALL) ALL # :wq # 切換到 user1 su - user1 cd # 使用 visudo(安全) sudo visudo # 故意打錯:user1 ALL=(ALL)) ALL # 存檔 :wq # 會出現錯誤提示 # 按 q 離開 # ========== 錯誤示範:直接用 vim ========== # 使用 vim 編輯(危險) sudo vim /etc/sudoers # 故意打錯:user1 ALL=(ALL)) ALL # :wq 存檔 # 測試 sudo(會失敗) sudo cat /etc/shadow # sudo 已經壞掉 ``` ### 總結 ========== 總結 ========== ✅ 推薦:sudo visudo(有語法檢查) ❌ 不推薦:sudo vim /etc/sudoers(無保護) ✅ 推薦:wheel 群組管理(集中管理) ❌ 不推薦:直接改 sudoers(難維護) - 結果參考: ![image](https://hackmd.io/_uploads/BkedsxDv-x.png) <a id="第2天"></a> # 常用指令快速上手:shutdown、reboot、poweroff ```bash= # 查看 shutdown 的使用說明 shutdown --help # 立即關機 shutdown -h now # 設定 10 分鐘後關機,附自訂訊息 shutdown -h +10 "shutdown" # 設定 5 分鐘後關機,覆蓋先前排程 shutdown -h +5 "shutdown" # 取消排程 shutdown -c # 指定精確時間關機,例如今天 21:00 shutdown -h 21:00 "shutdown" # 5 分鐘後重新啟動 shutdown -r +5 # 查看 /run/nologin 是否存在 ls /run/nologin # 查看 /run/nologin 內容 cat /run/nologin # 手動建立 /run/nologin touch /run/nologin ls -l /run/nologin # 刪除 /run/nologin rm -fr /run/nologin # 嘗試使用 ssh 登入另一台主機 ssh nameless@student # 直接關機 poweroff # 直接重啟 reboot # 查詢 reboot 指令位置 which reboot # 查看 reboot 詳細資訊 ls -lh $(which reboot) # 使用 systemctl 關機或重啟 systemctl poweroff systemctl reboot ``` <a id="第3天"></a> # 使用ip指令操作介面與地址 ```bash= # 查看 ip 指令完整手冊 man ip # 查看所有 IP ip a ip addr ip address show # 查看特定介面 ens160 ip a s ens160 ip a s ens160 # 顯示彩色 ip -c a ip -c a s ens160 ip -c -4 a s ens160 ip -c -6 a s ens160 # 新增 IPv4 位址 sudo ip a add 192.168.1.1/24 dev ens160 # 查看新增後的介面 ip -c a s ens160 # 刪除剛新增的 IP sudo ip a del 192.168.1.1/24 dev ens160 # 查看刪除後的介面 ip -c a s ens160 # 重啟系統(臨時 IP 會消失) sudo reboot # 重啟後查看 IP ip -c a s ens160 ``` <a id="第4天"></a> # Firewalld-基礎操作:查詢狀態與新增防火牆規則 ```bash= 1️⃣ 建立使用者 id student useradd student passwd student 2️⃣ 確認並設定 SELinux 為 Enforcing getenforce setenforce 1 getenforce 3️⃣ 編輯 SSH 設定檔 vi /etc/ssh/sshd_config 設定內容(確認存在): Port 22 Port 2022 AllowUsers student 4️⃣ 重啟 SSH 並檢查狀態 systemctl restart sshd systemctl status -l sshd 5️⃣ 設定 SELinux 允許 SSH 使用 2022 semanage port -a -t ssh_port_t -p tcp 2022 6️⃣ 開放防火牆 2022 埠 firewall-cmd --add-port=2022/tcp firewall-cmd --add-port=2022/tcp --permanent firewall-cmd --reload 7️⃣ 重新啟動並確認 SSH systemctl restart sshd systemctl status -l sshd 8️⃣ 從另一台主機連線測試 ssh -p 2022 student@192.168.127.128 9️⃣ 切換 root su ``` 製作結果: ![image](https://hackmd.io/_uploads/S1keevzB-e.png) ## 還原方式 ``` 1️⃣ 刪除 student 使用者 userdel -r student 2️⃣ 還原 SSH 配置檔 vi /etc/ssh/sshd_config # 刪除或註解掉新增的 Port 2022 # 刪除 AllowUsers student # 確認只保留原本 Port 22 systemctl restart sshd 3️⃣ 移除 SELinux 對 2022 埠的授權 semanage port -d -t ssh_port_t -p tcp 2022 4️⃣ 移除防火牆放行的 2022 埠 firewall-cmd --remove-port=2022/tcp firewall-cmd --remove-port=2022/tcp --permanent firewall-cmd --reload 5️⃣ 檢查 SSH 是否只監聽 22 埠 systemctl status -l sshd ``` ## Lab 🎯 Lab 目標 完成本 Lab 後,你將能夠: 確認 Firewalld 狀態 查詢預設 zone 與可用 zones 查看系統中可用的 services 檢視目前 zone 的防火牆設定分辨「執行中設定 (runtime)」與「永久設定 (permanent)」 ```bash= # Step 0: 確認 Firewalld 狀態 systemctl status firewalld systemctl enable --now firewalld # Step 1: 查看預設 zone firewall-cmd --get-default-zone # Step 2: 查看所有可用 zones firewall-cmd --get-zones # Step 3: 查看所有可用 services firewall-cmd --get-services # Step 4: 查看當前 zone 啟用的 services firewall-cmd --list-services # Step 5: 查看當前 zone 完整設定 firewall-cmd --list-all firewall-cmd --list-all --zone=public # Step 6: 新增 service (runtime) firewall-cmd --add-service=vnc-server firewall-cmd --list-all # Step 7: 新增 service (permanent) firewall-cmd --add-service=vnc-server --permanent firewall-cmd --reload firewall-cmd --list-all # Step 8: 新增 port (permanent) firewall-cmd --add-port=2020/tcp --permanent firewall-cmd --reload firewall-cmd --list-all ``` - 製作結果: ![image](https://hackmd.io/_uploads/HJpgdvg8bg.png) ### 還原方式 ``` # 移除 vnc-server service (runtime) firewall-cmd --remove-service=vnc-server # 移除 vnc-server service (permanent) firewall-cmd --remove-service=vnc-server --permanent # 移除 port 2020/tcp (permanent) firewall-cmd --remove-port=2020/tcp --permanent # 重新載入使永久設定生效 firewall-cmd --reload # 確認已移除 firewall-cmd --list-all ``` <a id="第5天"></a> # 使用systemctl管理Linux服務 ## 使用 systemctl 管理服務單元 - 安裝服務:安裝 vsftpd(FTP 伺服器) - 啟動服務:使用 systemctl start 命令 - 查看狀態:檢查服務是否運行、是否開機自動啟動 - 設定開機自啟:使用 systemctl enable 讓服務在系統重啟後自動啟動 --- ## systemctl 基本操作 在 Linux 系統裡面,systemd 就是負責管理整個系統和各種服務的總管。我們主要透過一個指令叫做 `systemctl` 來跟它溝通,告訴它我們要做什麼事情。那先從最基本的操作開始講起。 ## systemctl 基本指令 ```bash # 啟動服務 systemctl start foo # 停止服務 systemctl stop foo # 重新啟動服務 systemctl restart foo # 查看服務狀態 systemctl status foo # 設定開機自動啟動 systemctl enable foo # 停用開機自動啟動 systemctl disable foo # 禁止服務啟動 systemctl mask foo # 解除禁止 systemctl unmask foo # 檢查是否設定開機自啟 systemctl is-enabled foo ``` --- ## 實作練習:管理 vsftpd 服務 ```bash # 步驟 1:安裝 vsftpd dnf list vsftpd dnf install vsftpd -y # 步驟 2:啟動服務 systemctl start vsftpd # 步驟 3:查看狀態 systemctl status vsftpd # 步驟 4:設定開機自動啟動 systemctl enable vsftpd # 步驟 5:再次確認狀態 systemctl status vsftpd ``` 結果參考: ![image](https://hackmd.io/_uploads/HJGm6B5Nbx.png) --- ## 參考資料 - [systemd 理解和管理 - Fedora 文件](https://docs.fedoraproject.org/zh_Hans/quick-docs/systemd-understanding-and-administering/) - [vsftpd 手冊頁面](https://manpages.debian.org/trixie/vsftpd/vsftpd.8.en.html) --- 以下預計1/7-1/8 練習 ## 實作練習:修改服務配置 - 安裝 Apache 網頁伺服器(httpd) - 查看單元配置:使用 systemctl cat 和 systemctl show 查看配置選項 - 編輯服務配置:使用 systemctl edit 添加自定義配置 - 設定自動重啟:配置服務在停止或出現問題後自動重新啟動 - 重新載入配置:使用 systemctl daemon-reload 讓 systemd 讀取新配置 - 測試自動重啟:手動終止服務進程,驗證它會自動重啟 - ## Apache httpd systemd 自動重啟設定指南 - STEP 1|安裝 Apache(httpd) ```bash dnf install httpd -y ``` - STEP 2|查看 httpd 的 unit 檔案 ```bash systemctl cat httpd.service ``` **unit 檔案位置:** ``` /usr/lib/systemd/system/httpd.service ``` - STEP 3|查看 httpd Unit 設定資訊 ```bash systemctl show httpd.service ``` - STEP 4|設定 systemd 編輯器為 vim ```bash export SYSTEMD_EDITOR=/bin/vim ``` - STEP 5|建立 httpd Override 設定 ```bash systemctl edit httpd.service ``` **新增以下內容:** ```ini [Service] Restart=always RestartSec=5s ``` **override 設定檔位置:** ``` /etc/systemd/system/httpd.service.d/override.conf ``` - STEP 6|重新載入 systemd 設定 ```bash systemctl daemon-reload ``` - STEP 7|啟動 httpd 並確認狀態 ```bash systemctl start httpd systemctl status httpd ``` - STEP 8|強制終止 httpd 行程 ```bash killall httpd ``` - STEP 9|驗證 httpd 自動重啟 ```bash systemctl status httpd ``` **預期狀態應為:** ``` Active: active (running) ``` --- ## 補充指令 ```bash # 查看完整 unit 檔案(包含 override) systemctl cat httpd.service # 列出 override 目錄內容 ls /etc/systemd/system/httpd.service.d/ ``` --- <a id="第6天"></a> # managing jobs 2025/01/04 🏃‍♂️ & → 背景跑 ⏸️ Ctrl-Z → 暫停前景 🔄 bg / fg → 背景 ↔ 前景 📋 jobs → 看工作列表 ❌ Ctrl-C → 終止前景 🚪⚠️ 關終端 ≠ 程序結束 🔥📊 top + k → 安全結束程序 ```bash= # 切換 root sudo su # 背景執行 sleep sleep 3600 & # 背景執行 dd dd if=/dev/zero of=/dev/null & # 前景執行 sleep sleep 7200 # 暫停前景工作 Ctrl + Z # 查看工作列表 jobs # 背景繼續執行停止的工作 bg 3 # 拉回前景工作 fg 1 # 終止前景工作 Ctrl + C fg 2 Ctrl + C fg 3 Ctrl + C # 開第二個終端,背景執行 dd dd if=/dev/zero of=/dev/null & # 關閉第二個終端 exit # 回到第一個終端,檢查程序 top # 在 top 中終止程序 k 輸入 PID Enter ``` ## Linux行程管理(1):ps、jobs、fg 與背景運行 (2026/02/16) ```bash= # 系統狀態 uptime # 查看系統運行時間、使用者數量、負載平均 top # 即時監控系統資源與行程 htop # top 的進階版本,顯示記憶體與 CPU 使用狀況 # CPU 資訊 lscpu # 查看 CPU 硬體資訊與核心數量 # 查看行程 ps # 列出目前行程 ps -e # 列出所有行程 ps -e | less # 分頁顯示所有行程 ps -fe | less # 顯示所有行程及所屬使用者和父行程 ps -fel | less # 顯示詳細行程資訊 # 過濾行程 ps -fel | grep ssh # 只顯示名稱含 ssh 的行程 # 背景執行 sh -c "sleep 1000" & # 執行腳本並放到背景 jobs # 查看背景行程 fg # 將最後一個背景行程放到前景 fg 1 # 將指定編號的背景行程放到前景 ``` - 製作結果: ![image](https://hackmd.io/_uploads/HJ8LjheuZg.png) ## 優先級 (2026/02/17) 在 Linux 裡面, 每個進程其實都有「優先順序」。 👉 有些程式可以比較常被 CPU 執行 👉 有些程式會排比較後面 1️⃣ 背景工作建立與刪除 ```bash= jobs sh -c "sleep 1000" & sh -c "sleep 2000" & ps -ef | grep sleep kill PID # 結束指定 PID 的進程 ``` 2️⃣ 用 pgrep 找 PID ```bash= pgrep sleep sh -c "sleep 1000" & pgrep sleep # 查看 PID kill $(pgrep sleep) # 一次刪除所有 sleep 進程 ``` 3️⃣ 用 pkill 刪除進程 ```bash= sh -c "sleep 1000" & sh -c "sleep 2000" & pgrep sleep ps -ef | grep sleep pkill sleep # 依關鍵字刪除所有符合的進程 ``` 4️⃣ 查看進程優先級 ```bash= ps -elf | less # 查看欄位:PRI(Priority)、NI(Nice 值) ``` 5️⃣ nice 值範圍與概念 NI 範圍:-20(最高優先) → 19(最低優先) 預設 nice 值:0 高優先級 → nice 值小或 PRI 高 低優先級 → nice 值大或 PRI 低 6️⃣ 創建背景進程並查看優先級 ```bash= sh -c "sleep 1000" & jobs ps -elf | grep sleep pkill sleep # 先刪掉進程,方便重新設定優先級 ``` 7️⃣ 設定最低優先級 ```bash= nice -n 19 sh -c "sleep 1000" & ps -elf | grep sleep # PRI → 99, NI → 19 pkill sleep ``` 8️⃣ 設定最高優先級 ```bash= nice -n -20 sh -c "sleep 1000" & ps -elf | grep sleep # PRI → 60, NI → -20 ``` 9️⃣ 修改已存在進程的 nice 值 ```bash= ps -elf | grep sleep renice -10 -p 2492 # PID 為 2492, nice 值改成 -10 renice 10 -p 2492 # nice 值改成 10 ps -elf | grep sleep # 查看修改後的 PRI 和 NI ``` - 製作結果: ![image](https://hackmd.io/_uploads/Bk9gFo-_-e.png) | 項目 | 說明 | 數值範圍 | 數字越大代表 | | -------------- | ---------- | -------- | --------- | | PRI (Priority) | 核心實際排程優先級 | 動態變動 | 不一定固定 | | NI (Nice值) | 使用者可調整的優先級 | -20 ~ 19 | 越大 → 越不優先 | | 預設 Nice | 一般程式啟動時的值 | 0 | 標準優先級 | | 高優先級 | 需要較多 CPU | -20 | 最優先 | | 低優先級 | 背景、不重要工作 | 19 | 最不優先 | <a id="第7天"></a> # journalctl相關操作 (2026/01/08) - 1. 顯示自系統上次啟動以來的所有 journal 記錄 ```bash= journalctl ``` - 2. 分頁搜尋文字 `進入 journalctl 後,按 / 搜尋文字,n 往下找,N 往回找,q 離開` - 3. 不使用分頁器一次看完 ```bash= journalctl --no-pager ``` - 4. 即時追蹤新產生的日誌訊息 ```bash= journalctl -f ``` - 5. 顯示最後 20 行日誌 ```bash= journalctl -n 20 ``` - 6. 查看特定使用者產生的日誌 ```bash= journalctl _UID=1000 ``` - 7. 查看特定使用者執行特定程式的日誌 ```bash= journalctl _UID=1000 _COMM=firefox ``` - 8. 快速找錯誤 ```bash= journalctl -p err ``` - 9. 查看警告訊息及以上 ```bash= journalctl -p warning ``` - 10. 從昨天到現在的日誌 ```bash= journalctl --since yesterday ``` - 11. 指定時間範圍的日誌 ```bash= journalctl --since "2026-01-07 18:00" --until "2026-01-08 20:00" ``` - 12. 從昨天到現在的錯誤訊息 ```bash= journalctl --since yesterday -p err ``` - 13. 從指定時間開始的錯誤訊息 ```bash= journalctl --since "2026-01-08 09:00" -p err ``` - 14. 顯示最詳細的日誌格式 ```bash= journalctl -o verbose ``` - 15. 查看特定服務的日誌 ```bash= journalctl _SYSTEMD_UNIT=sshd.service ``` - 16. 查看核心(Kernel)訊息 ```bash= journalctl --dmesg ``` - 17. 查看核心訊息(人類可讀時間) ```bash= dmesg -T ``` <a id="第8天"></a> # MariaDB安裝與連線 ```bash= # ---------- 1. 停止服務 ---------- sudo systemctl stop mysql sudo systemctl stop mariadb # ---------- 2. 移除軟體 ---------- sudo dnf remove -y mysql-server mysql mariadb-server mariadb # ---------- 3. 刪除資料與設定檔 ---------- sudo rm -rf /var/lib/mysql sudo rm -rf /etc/mysql sudo rm -rf /etc/my.cnf # ---------- 4. 安裝 MariaDB Server(第二台遠端) ---------- sudo dnf list mariadb-server sudo dnf install -y mariadb-server sudo systemctl enable --now mariadb sudo systemctl status mariadb # ---------- 5. 基本安全設定 ---------- sudo mysql_secure_installation # ---------- 6. 測試本地登入 ---------- mysql -u root -p -h localhost show databases; ctrl+D # ---------- 7. 第一台本地端安裝 MariaDB Client ---------- sudo dnf install -y mariadb mysql -u root -p -h 192.168.88.129 # ---------- 8. 防火牆開啟 MySQL Port ---------- sudo firewall-cmd --permanent --add-service=mysql sudo firewall-cmd --reload # ---------- 9. 第二台遠端建立允許遠端連線的帳號 ---------- mysql -u root -p -h localhost CREATE USER 'root'@'192.168.88.131' IDENTIFIED BY 'password'; # ---------- 10. 客戶端測試連線 ---------- mysql -u root -p -h 192.168.88.129 SHOW DATABASES; # ---------- 11. 回到遠端授權 ---------- mysql -u root -p -h localhost GRANT ALL ON *.* TO 'root'@'192.168.88.131' WITH GRANT OPTION; FLUSH PRIVILEGES; # ---------- 12. 客戶端重新登入 ---------- mysql -u root -p -h 192.168.88.129 SHOW DATABASES; ``` <a id="第9天"></a> # MySQL 8.0 安裝(RHEL 8 / RPM) 官方下載頁 ```bash= https://dev.mysql.com/downloads/file/?id=546016 ``` MySQL 8.0 RPM Bundle(RHEL 8) https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.44-1.el8.x86_64.rpm-bundle.tar 1️⃣ 安裝前置作業(移除舊版 MySQL / MariaDB) 在下載與安裝 MySQL 8.0 前,先確認系統內是否已有 MySQL 或 MariaDB,避免版本衝突。 ```bash= systemctl stop mysql systemctl stop mariadb ``` ```bash= dnf remove -y mysql-server mysql mariadb-server mariadb ``` 2️⃣ 建立安裝目錄並下載 MySQL 8.0 RPM 建立目錄並切換進去: ```bash= mkdir /opt/mysql8 cd /opt/mysql8 ``` 下載 MySQL 8.0 RPM Bundle: ```bash= curl -OJL https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.44-1.el8.x86_64.rpm-bundle.tar ``` ``` 參數說明: -O:儲存檔案 -J:使用 HTTP header 指定的檔名 -L:跟隨重新導向 下載時間約 3~5 分鐘,請耐心等候 ``` 3️⃣ 解壓縮 RPM 套件 確認檔案: ```bash= ls ``` 解壓縮 .tar 檔: ```bash= tar xf mysql-8.0.44-1.el8.x86_64.rpm-bundle.tar ``` ``` 參數說明: x:extract(解壓縮) f:指定檔案名稱 ``` 解壓後再次確認: ```bash= ls ``` 會看到多個 .rpm 檔,例如: ```bash= mysql-community-server-debug-8.0.44-1.el8.x86_64.rpm ``` 4️⃣ 為什麼不能直接安裝 RPM? 如果直接執行: ```bash= dnf localinstall mysql-community-client-8.0.44-1.el8.x86_64.rpm ``` 會 失敗,原因是 RPM 套件有相依性,不能單獨安裝。 解法: 👉 把整個目錄做成本地套件倉庫(local repo) 5️⃣ 安裝 createrepo 並建立本地 Repo 先找出 createrepo 指令屬於哪個套件: ```bash= dnf provides '*bin/createrepo' ``` 可以看到: ``` createrepo_c-0.17.7-6.el8.x86_64 ``` 安裝工具: ```bash= dnf install -y createrepo_c ``` 建立本地套件倉庫(在 /opt/mysql8 目錄下執行): ```bash= createrepo ./ ``` 檢查結果: ```bash= ls ls repodata/ ``` 會看到: ```bash= repodata/ repomd.xml ``` 各種 metadata 檔案 6️⃣ 建立本地 YUM Repo 設定 進入 repo 設定目錄: ```bash= cd /etc/yum.repos.d/ vi mysql8.repo ``` 內容如下: ```bash= [mysql8] name = MySQL 8 from local baseurl=file:///opt/mysql8 enabled=1 gpgcheck=0 ``` 設定說明: ``` file://:本機檔案來源 /opt/mysql8:RPM 與 repodata 所在目錄 enabled=1:啟用 repo gpgcheck=0:不檢查簽章(本地 repo) ``` 清除快取: ```bash= dnf clean all ``` 7️⃣ 確認 DNF 是否能找到 MySQL 套件 ```bash= dnf list mysql-community-server dnf list mysql-community* ``` 若只看到少數套件或找不到 mysql-community-server,代表: 系統的 MySQL module 還在作用,封鎖了本地 repo 8️⃣ 停用官方 MySQL Module 並安裝 MySQL 停用 module: ```bash= yum module disable mysql ``` 再次確認套件: ```bash= dnf list mysql* ``` 應該能看到: ``` mysql-community-server ``` 安裝 MySQL Server: ```bash= dnf install -y mysql-community-server ``` 9️⃣ 啟動 MySQL 並取得臨時密碼 設定開機自動啟動並立即啟動: ```bash= systemctl enable --now mysqld ``` 查看 MySQL root 的臨時密碼: ```bash= grep password /var/log/mysqld.log ``` 範例輸出: ``` ytf8W?(QoJ;K ``` ⚠️ 請務必記下這組密碼 🔟 執行 MySQL 安全設定精靈 ```bash= mysql_secure_installation ``` ``` 設定流程建議: 輸入臨時密碼 設定新密碼:P@ssw0rd Change root password? → N Remove anonymous users? → Y Disallow root login remotely? → Y Remove test database? → Y Reload privilege tables? → Y ``` 1️⃣1️⃣ 測試登入 MySQL ```bash= mysql -u root -p ``` 成功登入即完成 MySQL 8.0 安裝 🎉 📚 參考文件 - MySQL 官方文件 https://dev.mysql.com/doc/ - MySQL 8.0 RPM 安裝說明 https://dev.mysql.com/doc/refman/8.0/en/linux-installation-rpm.html - RHEL 8 DNF Module 說明 https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_software_with_dnf/index <a id="第10天"></a> # 設定SSH金鑰免密登入伺服器主機 (2026/02/21) ```bash= ## 1. 遠端伺服器確認 ls ~/.ssh/ # 確認有 authorized_keys 2. 備份舊金鑰(可選) mv ~/.ssh ~/.ssh.bak 3. 修改 SSH 設定 sudo vi /etc/ssh/sshd_config # 確認如下 PasswordAuthentication no PubkeyAuthentication yes 4. 重啟 SSH sudo systemctl restart sshd 5. 本地端清除 known_hosts(可選) rm ~/.ssh/known_hosts 6. 產生本地 SSH Key ssh-keygen -t ed25519 7. 複製公鑰到遠端 # 建立 .ssh 目錄 mkdir -p ~/.ssh chmod 700 ~/.ssh # 貼上公鑰到 authorized_keys echo "你的公鑰內容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys 8. 本地端設定 SSH config(可選) # ~/.ssh/config Host control HostName 192.168.88.131 User ansible 9. 測試連線 ssh control # 不需要密碼即可登入 ``` - 結果如下: ![image](https://hackmd.io/_uploads/Syq5pbD_bl.png) ## 控制端公鑰傳送與建立 SSH 免密連線 (2026/02/22) ```bash= # 控制端產生 SSH 金鑰 ssh-keygen -t ed25519 # server 確認允許公鑰登入 sudo vi /etc/ssh/sshd_config # 修改為 PubkeyAuthentication yes sudo systemctl restart sshd # server 清空舊公鑰 cd ~/.ssh rm -f authorized_keys ls -l # 控制端複製公鑰到 server ssh-copy-id server@server # 測試免密登入 ssh server@server ``` - 製作結果: ![image](https://hackmd.io/_uploads/BJiT2Pu_Zg.png) <a id="第11天"></a> # LVM邏輯卷建立與容量擴展實作 先用`lsblk` 確認是否有一個sda磁碟 範例如下: ![image](https://hackmd.io/_uploads/B1Az9GCNZl.png) ```bash= # 建立 Physical Volume pvcreate /dev/sda pvs # 建立 Volume Group vgcreate vg_01 /dev/sda vgs # 建立 Logical Volume(500MB) lvcreate -L 500M -n lvgroup vg_01 lvs # 建立 XFS 檔案系統 mkfs.xfs /dev/vg_01/lvgroup # 建立掛載點並掛載 mkdir /groups mount /dev/vg_01/lvgroup /groups # 設定開機自動掛載 vi /etc/fstab /dev/vg_01/lvgroup /groups xfs defaults 0 0 # 重開機 reboot # 重開後確認掛載 df -h /groups # 擴展 Logical Volume(+250MB) lvextend -L +250M /dev/vg_01/lvgroup # 擴展 XFS 檔案系統 xfs_growfs /groups # 驗證 Logical Volume 大小 lvs # 驗證檔案系統大小 df -h /groups ``` 結果: ![image](https://hackmd.io/_uploads/H16WTfRVZl.png) <a id="第12天"></a> # Nginx 反向代理進階 Upstream 群組管理與 SELinux 設定 前置作業: ![image](https://hackmd.io/_uploads/ByjIq2yHbx.png) SELinux阻擋問題: ![image](https://hackmd.io/_uploads/S1hHc3yHWx.png) ```bash= # ===== 第一台主機:192.168.88.131 (Nginx / control) ===== # 停止並移除舊 Nginx systemctl stop nginx dnf remove -y nginx rm -rf /etc/nginx /var/log/nginx /var/cache/nginx /usr/share/nginx # 安裝並啟動 Nginx dnf install -y nginx systemctl enable --now nginx # 防火牆放行 80 firewall-cmd --permanent --add-service=http firewall-cmd --reload # 建立 upstream 設定 cd /etc/nginx/conf.d/ cat > 0_upstream.conf << 'EOF' upstream proxy.control.local { server 192.168.88.129:8081; } EOF # 建立 server block cat > proxy.control.local.conf << 'EOF' server { listen 80; server_name proxy.control.local; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $host; proxy_set_header Port $server_port; proxy_set_header Schema $scheme; proxy_set_header URI $uri; proxy_pass http://proxy.control.local; } } EOF # hosts 設定 echo "192.168.88.131 proxy.control.local" >> /etc/hosts # SELinux 允許 Nginx 連線 setsebool -P httpd_can_network_connect on # 檢查並重啟 nginx -t systemctl restart nginx ![Uploading file..._x756mr91o]() # ===== 第二台主機:192.168.88.129 (backend / student) ===== # 防火牆放行 8081 firewall-cmd --permanent --add-port=8081/tcp firewall-cmd --reload # 確認 8081 監聽 ss -ntlp | grep 8081 ``` 補充第二台: ``` # 安裝 Nginx(如果還沒裝) sudo dnf install -y nginx # 建立網站目錄 sudo mkdir -p /var/www/backend # 建立測試頁面 sudo tee /var/www/backend/index.html > /dev/null << 'EOF' <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>後端服務</title> </head> <body> <h1>🎉 成功!來自後端主機 (192.168.88.129:8081)</h1> <p>這是第二台主機提供的內容</p> <p>你現在看到的頁面是透過第一台 Nginx 反向代理轉發過來的!</p> </body> </html> EOF # 建立 Nginx 後端站台設定 sudo tee /etc/nginx/conf.d/backend_8081.conf > /dev/null << 'EOF' server { listen 8081; server_name localhost; root /var/www/backend; index index.html; location / { try_files $uri $uri/ =404; } } EOF # 測試 Nginx 設定 sudo nginx -t # 啟動 Nginx sudo systemctl enable --now nginx # 或如果已經在運行,重新載入 sudo systemctl reload nginx ``` - 結果如下 -![image](https://hackmd.io/_uploads/SkxzFuh1HZe.png) <a id="第13天"></a> # 設定SELinux規則讓Apache可讀取/web目錄 1. Open a root shell and type dnf install httpd curl -y. 2. Still from the root shell, type mkdir /web. 3. Type vim /web/index.html and put the following contents in the file: welcome to my web server. 4. Type vim /etc/httpd/conf/httpd.conf to open the Apache configuration file and find the DocumentRoot parameter. Change it so that it reads DocumentRoot "/web". 5. In the same httpd.conf configuration file, add the following section, as without this section it will be Apache and not SELinux blocking access to the new DocumentRoot: DocumentRoot "/web" <Directory "/web"> AllowOverride None Require all granted </Directory> 6. Type systemctl enable --now httpd to start and enable the httpd service. Note that if the httpd service was already running, you'll need to use systemctl restart httpd to restart it so that it can pick up the changes you've made to the httpd. conf configuration file. 7. Type curl http://localhost. You'll see the default Red Hat web page and not the contents of the index.html file you have just created. 8. Type setenforce 0 to switch SELinux to permissive mode. 9. Repeat step 7. You'll now get access to your custom web page, which proves that SELinux was doing something to block access. 10. Type semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?" to apply the new context label to /web. 11. Type restorecon -R -v /web. The -v (verbose) option ensures that you see what is happening and that you will see the new context being applied to /web. 12. Set SELinux back in enforcing mode, using setenforce 1. 13. Type curl http://localhost. You' ```bash= # 1️⃣ 安裝 Apache 與 curl dnf install httpd curl -y # 2️⃣ 建立網站資料夾 mkdir /web # 3️⃣ 建立首頁 vim /web/index.html # 4️⃣ 修改 Apache 根目錄 vim /etc/httpd/conf/httpd.conf # 設定 DocumentRoot "/web" # 並加入 <Directory "/web"> 相關設定 # 5️⃣ 啟動或重啟 Apache systemctl enable --now httpd # 如果已在跑:systemctl restart httpd # 6️⃣ 測試網站 curl http://localhost # 7️⃣ 暫時切換 SELinux 為寬鬆模式 setenforce 0 # 8️⃣ 再次測試網站 curl http://localhost # 9️⃣ 設定 SELinux 標籤 semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?" # 🔟 套用標籤 restorecon -R -v /web # 1️⃣1️⃣ 切回強制模式 setenforce 1 # 1️⃣2️⃣ 最後測試網站 curl http://localhost ``` 製作結果: ![image](https://hackmd.io/_uploads/rkoQ00ELZe.png) <a id="第14天"></a> # Managing Apache HTTP Services ## 安裝與測試基本 Apache Web 伺服器 ```bash= 安裝 Apache HTTP 伺服器 dnf install -y httpd 啟動並設定開機自動啟動 systemctl enable --now httpd 查看 Apache 主設定檔的網站根目錄 # 預設網站根目錄 /var/www/html # 建立首頁檔案 cd /var/www/html vi index.html 在檔案中輸入以下內容: Welcome to my web server. 存檔並離開編輯器 # 檢查 Apache 是否正在監聽網路連接 ss -tlnp | grep httpd # 測試網站是否能連線 curl http://localhost ``` ## 設定兩個虛擬主機(Virtual Host) ```mermaid flowchart TD A[編輯 /etc/hosts] B[編輯 /etc/httpd/conf/httpd.conf] C[建立虛擬主機設定檔] D[建立網站目錄] E[建立首頁文件] F[暫時關閉 SELinux] G[重啟 Apache] H[測試網站是否可訪問] I[複製虛擬主機設定檔(給新網站用)] J[批次修改虛擬主機名稱] A --> B B --> C C --> D D --> E E --> F F --> G G --> H H --> I I --> J ``` 製作順序: -目錄結構: /etc/ └── httpd/ ├── conf/ │ └── httpd.conf ⚙️ (主配置) └── conf.d/ ├── account.example.com.conf 🏢 └── sales.example.com.conf 🏪 /www/ └── docs/ ├── account.example.com/ 🏢 │ └── index.html └── sales.example.com/ 🏪 └── index.html --- ```bash= # 編輯 /etc/hosts (server1) vi /etc/hosts 加入以下內容: 192.168.127.129 server2.example.com server2 192.168.127.128 account.example.com account 192.168.127.128 sales.example.com sales 存檔並退出 :wq # 編輯 /etc/hosts (server2) vi /etc/hosts 加入以下內容: 192.168.127.128 server1.example.com server1 192.168.127.129 account.example.com account 192.168.127.129 sales.example.com sales 存檔並退出 :wq # 修改 Apache 目錄權限設定 vi /etc/httpd/conf/httpd.conf 新增以下內容: <Directory /www/docs> Require all granted AllowOverride None </Directory> 存檔並退出 :wq # 設定 ServerName vi /etc/httpd/conf/httpd.conf 在檔案最底下加入: ServerName 192.168.127.128 存檔並退出 :wq # 檢查設定語法 httpd -t # 測試連線 ping account.example.com ping sales.example.com # 建立 account 虛擬主機設定檔 vi /etc/httpd/conf.d/account.example.com.conf 檔案內容: <VirtualHost *:80> ServerAdmin webmaster@account.example.com DocumentRoot /www/docs/account.example.com ServerName account.example.com ErrorLog logs/account.example.com-error_log CustomLog logs/account.example.com-access_log common </VirtualHost> 存檔並退出 :wq # 建立網站目錄與首頁 mkdir -p /www/docs/account.example.com vi /www/docs/account.example.com/index.html 檔案內容: Welcome to account. 存檔並退出 :wq # 暫時關閉 SELinux setenforce 0 getenforce # 重新啟動 Apache 並測試 systemctl restart httpd curl http://account.example.com # 複製設定檔建立 sales 虛擬主機 cp /etc/httpd/conf.d/account.example.com.conf /etc/httpd/conf.d/sales.example.com.conf # 編輯 sales 虛擬主機設定 vi /etc/httpd/conf.d/sales.example.com.conf 執行替換指令: :%s/account/sales/g 存檔並退出 :wq # 建立 sales 網站目錄與首頁 mkdir -p /www/docs/sales.example.com vi /www/docs/sales.example.com/index.html 檔案內容: Welcome to sales. 存檔並退出 :wq # 重啟 Apache 並測試 systemctl restart httpd curl http://sales.example.com ``` <a id="第14-1天"></a> # 短名與預設 registry:Podman 自動拉取映像機制 ```bash= # 查看 Podman 安裝狀態 dnf list podman dnf install -y podman # 安裝 podman-compose dnf list podman* dnf install -y podman-compose podman --version podman-compose --version # 測試 Podman podman run -it hello # 查看本地映像 podman image ls podman images # 刪除容器與映像 podman ps -a podman stop <container_id> podman rm <container_id> podman rmi <image_id> # Podman image 常用指令 podman image podman image build <options> podman image pull <image> podman image push <image> podman image rm <image> podman image inspect <image> podman image list podman image save <image> podman image load <archive> podman image tag <image> <new_name> podman image untag <image> podman image history <image> podman image prune # 查看容器 podman ps podman ps -a # 搜尋映像 podman image search ubuntu podman image search hello # 拉取映像 podman image pull docker.io/library/ubuntu podman image pull hello podman image pull python # 查看 registry 設定 less /etc/containers/registries.conf more /etc/containers/registries.conf.d/000-shortnames.conf ``` <a id="第15天"></a> # Podman-啟動、進入、暫時離開 (detach) 以及停止容器 (2026/01/29) 1️⃣ 安裝 Podman ```bash dnf install -y podman ``` 2️⃣ 查看系統中所有容器(包括停止的) ```bash podman ps -a ``` 3️⃣ 啟動 nginx 容器並在背景執行 ```bash podman run -d nginx ``` 4️⃣ 查看正在執行的容器 ```bash podman ps ``` 5️⃣ 啟動 BusyBox 容器進入互動式 shell ```bash podman run -it busybox ``` 6️⃣ 在 BusyBox 容器內查看進程 ```bash ps aux ``` 7️⃣ 離開 BusyBox 容器 ```bash exit ``` 8️⃣ 再次啟動 BusyBox 容器並 detach(中斷連線) ```bash podman run -it busybox ``` `容器內按下 Ctrl+P 然後 Ctrl+Q 來 detach` 9️⃣ 查看仍在運行的容器 ```bash podman ps ``` 🔟 重新連線到已經在運行的容器 ```bash podman attach <name> ``` `將 <name> 替換成 podman ps 中的容器名稱` 1️⃣1️⃣ 在容器內 detach 再次中斷連線 ```bash # 容器內按下 Ctrl+P 然後 Ctrl+Q ``` 1️⃣2️⃣ 停止 BusyBox 容器 ```bash podman stop <name> ``` `將 <name> 替換成容器名稱` <a id="第16天"></a> # Podman-自建容器image上傳到 Docker Hub 參考文獻: - https://app.docker.com/ ```bash= Step 1:確認 Podman 環境 podman version Step 2:從 Registry 拉取 image podman pull docker.io/library/alpine:latest Step 3:確認 image 是否存在 podman images Step 4:執行官方 Alpine image podman run -it alpine cat /etc/os-release exit Step 5:建立專案目錄與 Containerfile mkdir alpmap cd alpmap vi Containerfile Containerfile 內容 FROM docker.io/library/alpine:latest RUN apk add --no-cache nmap CMD ["nmap", "-sn", "172.16.0.0/24"] Step 6:建構自訂 image podman build -t alpmap:1.0 . Step 7:確認建構完成 podman images Step 8:執行自訂 image podman run alpmap:1.0 Step 9:為 image 加上 Docker Hub 標籤 podman tag alpmap:1.0 docker.io/nameless1234/alpmap:1.0 Step 10:確認標籤 podman images Step 11:登入 Docker Hub podman login docker.io -u nameless1234 Step 12:推送 image 到 Registry podman push docker.io/nameless1234/alpmap:1.0 ``` - 製作結果: ![image](https://hackmd.io/_uploads/r1qP8LUBWl.png) <a id="第17天"></a> # Ansible 的 Loop 與 Items ❓ 為什麼需要 Loop? ✅ 有些模組支援 list(不需要 loop) 例:dnf / yum 💾 → 一次安裝多個套件 📦📦📦 ❌ 有些模組不支援 list(需要 loop) 例:service 🛠 → 一次只能操作一個服務 🖥️ --- 📋 清單 (List) - vsftpd - httpd - smb Loop 🔄 逐一處理 ┌───────────────┐ │ item = vsftpd │ → Ansible 處理 Task ✅ │ item = httpd │ → Ansible 處理 Task ✅ │ item = smb │ → Ansible 處理 Task ✅ --- ## 2️⃣ 舉例 dnf / yum 支援 list ```bash= - name: Install packages dnf: name: - httpd - vsftpd - samba state: latest ``` ## 失敗範例 ```bash= - name: Start services service: name: - httpd - vsftpd - smb state: started ``` <a id="第18天"></a> # 使用 Ansible 變數建立使用者與系統資訊 2026/01/19 🧩 Ansible 的變數與 Facts 👤 Variable(使用者定義) ➡️ 自己設定 (vars) ➡️ 用 {{ }} 使用 🖥️ Facts(系統資訊) ➡️ Ansible 自動收集 ➡️ 來自主機系統 ⚙️ 每次執行 Playbook ➡️ 先 Gathering Facts `create_user.yml` ```bash= --- - name: create a user using a variable hosts: server1 become: yes vars: users: lisa tasks: - name: create a user {{ users }} on host {{ ansible_hostname }} user: name: "{{ users }}" state: present ``` ```bash= ansible-playbook -i inventory create_user.yml --syntax-check ansible-playbook -i inventory create_user.yml ansible server1 -i inventory -m command -a "id lisa" ``` - 製作結果 ![image](https://hackmd.io/_uploads/rJqOw_sSZe.png) ## Ansible YAML-多行文字:直立線與大於符號應用 2026/01/20 - 步驟 1:建立 Playbook 檔案 ```bash= vim multiline.yml ``` ```bash= # Playbook 內容 --- - name: copy multiline text hosts: server1 tasks: - name: copy text copy: content: | line 1 line 2 dest: /tmp/multiline1.txt - name: copy more text copy: content: > line 1 line 2 dest: /tmp/multiline2.txt ``` ```bash= # 步驟 4:執行 Playbook ansible-playbook -i inventory multiline.yml # 步驟 5:驗證第一個檔案(保留換行) ansible server1 -a "cat /tmp/multiline1.txt" # 步驟 6:驗證第二個檔案(合併成一行) ansible server1 -a "cat /tmp/multiline2.txt" ``` 製作結果: ![image](https://hackmd.io/_uploads/r1LHZj3Sbg.png) ## Ansible Vault 加密變數檔案建立與密碼管理實作 ``` # Step 1:建立 Vault 加密檔案 ansible-vault create secrets.yaml # Step 2:建立 Playbook 檔案 # (在 create-users.yaml 中撰寫以下內容) ``` ```bash= --- - name: create a user with vaulted variables hosts: ansible1 vars_files: - secrets.yaml become: yes tasks: - name: creating user user: name: "{{ username }}" password: "{{ pwhash }}" ``` ``` # Step 3:語法檢查 ansible-playbook -i inventory create-users.yaml --syntax-check --ask-vault-pass # Step 4:執行 Playbook(手動輸入 Vault 密碼) ansible-playbook -i inventory create-users.yaml --ask-vault-pass # Step 5:變更 Vault 密碼(rekey) ansible-vault rekey secrets.yaml # Step 6:建立 Vault 密碼檔 echo secretpassword > vault-pass # Step 7:保護 Vault 密碼檔 chmod 400 vault-pass # Step 8:使用 Vault 密碼檔執行 Playbook ansible-playbook -i inventory --vault-password-file=vault-pass create-users.yaml ``` - 結果參考: ![image](https://hackmd.io/_uploads/H1gkv_wL-l.png) <!DOCTYPE html> <html lang="zh-Hant"> <head> <meta charset="UTF-8"> <title>Ansible Vault Lab 流程</title> <style> body { font-family: Arial, sans-serif; } .flowchart { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.8; } .step { margin: 10px 0; } .arrow { margin-left: 20px; } </style> </head> <body> <h2>🔒 Ansible Vault Lab 流程</h2> <div class="flowchart"> <div class="step">🟢 開始 Lab</div> <div class="arrow">│</div> <div class="step">📄 建立 Vault 加密變數檔案 (secrets.yaml)</div> <div class="arrow">│</div> <div class="step">✏️ 輸入敏感變數<br> username: bob<br> pwhash: password </div> <div class="arrow">│</div> <div class="step">📘 編寫 Playbook 使用 Vault 變數</div> <div class="arrow">│</div> <div class="step">▶️ 執行 Playbook<br>(--ask-vault-pass & --ask-become-pass)</div> <div class="arrow">│</div> <div class="step">❓ 是否需要更換 Vault 密碼?</div> <div class="arrow">│</div> <div class="step">🔄 是 → 使用 ansible-vault rekey 更新密碼</div> <div class="arrow">│</div> <div class="step">📂 使用 Vault 密碼檔自動化執行 Playbook</div> <div class="arrow">│</div> <div class="step">✅ Lab 完成</div> </div> </body> </html> - 製作結果: ![image](https://hackmd.io/_uploads/BylSuBDI-g.png) <a id="第19天"></a> # shell scripts ## 自動化倒數計時shell程式完整範例 這個腳本只需要一個參數,就是分鐘數。 它會每秒顯示剩餘秒數, 直到時間到,最後顯示『time is over』。 我們會一步一步來,看程式如何檢查參數、轉換秒數、 再進行倒數迴圈。 `vi countdown.sh` ```bash= #!/bin/bash if [ $# -ne 1 ]; then echo "Usage: $0 <minutes>" exit 1 fi minutes=$1 seconds=$(( minutes * 60 )) while [ $seconds -gt 0 ]; do echo "$seconds sec left" sleep 1 seconds=$(( seconds -1 )) done echo "time is over" # /countdown.sh ``` ```mermaid flowchart TD A[Ad Hoc Commands] --> B[一次性的 Ansible 指令] A --> C[不需要寫完整 playbook] A --> D[立即在管理主機執行操作] A --> E[可以做什麼] E --> F[安裝套件 httpd] E --> G[啟動服務並設定開機自動啟動] E --> H[建立使用者 anna] E --> I[複製檔案 /etc/hosts -> /tmp/hosts] ``` ## 用 Shell Script 批次執行 Ansible 臨時指令 1. 前置作業 `vi ansible.cfg` ```bash= [defaults] inventory = ./inventory ``` 2. 建立腳本檔案 ```bash= vim install.sh ``` 3. 編輯 `install.sh` ```bash= #!/bin/bash # 安裝 httpd 套件 ansible server1 -m dnf -a "name=httpd state=present" -b # 啟動 httpd 並設定開機自動啟動 ansible server1 -m service -a "name=httpd state=started enabled=yes" -b # 建立使用者 anna ansible all -m user -a "name=anna state=present" -b # 複製 /etc/hosts 到受控主機 ansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts" -b ``` 4. 給腳本執行權限 ```bash= chmod +x install.sh ``` 5. 執行腳本 ```bash= ./install.sh ``` 6. 驗證受控端 ```bash= 檢查 httpd 服務 ansible server1 -m service -a "name=httpd" -b 檢查使用者 anna ansible server1 -m command -a "id anna" 檢查檔案內容 ansible server1 -m command -a "cat /tmp/hosts" ``` 製作成果: ![image](https://hackmd.io/_uploads/SyzNrqhr-x.png) ## Shell Script-參數判斷與本地郵件測試實作 (2026/01/09) Write a script that works with arguments. If the argument one is used, the script should create a file named /tmp/one. If the argument two is used, the script should send a message containing the subject "two" to the root user. ```bash= [使用者輸入參數] | / \ "one" "two" | | 建立 /tmp/one 寄信給 root ``` 1️⃣ 安裝必要套件並啟動郵件服務 ```bash= sudo dnf install -y mailx postfix sudo systemctl enable --now postfix ``` 2️⃣ 建立工作目錄(假設叫 0109) ```bash= mkdir -p ~/0109 cd ~/0109 ``` 3️⃣ 建立腳本 lab_1.sh ```bash= vi lab_1.sh ``` 然後把以下內容貼進去 ```bash= #!/bin/bash if [ "$1" == "one" ]; then touch /tmp/one elif [ "$1" == "two" ]; then echo "two" | mail -s "two" root else echo "Usage: $0 {one|two}" exit 1 fi ``` 4️⃣ 給腳本執行權限 ```bash= chmod +x lab_1.sh ``` 5️⃣ 測試腳本 ```bash= ./lab_1.sh one # 建立 /tmp/one ls /tmp # 確認 /tmp/one 存在 ./lab_1.sh two # 寄信給 root ``` 6️⃣ 在 root 終端檢查信件 ```bash= sudo su - # 切換到 root mail # 查看信件 ``` ``` # 在 mail 介面操作 # d 1 (刪除第一封信) # q (退出 mail) ``` 7️⃣ 清理測試檔案 ```bash= rm -f /tmp/one rm -f ~/0109/lab_1.sh ``` 8️⃣ 停止郵件服務(如果不再使用) ```bash= sudo systemctl stop postfix sudo systemctl disable postfix ``` ``` 指令涵蓋: 安裝 mailx 和 postfix 建立腳本 給予權限 執行腳本測試 收信並刪信 刪除測試檔案與停止服務 ``` 製作結果: ![image](https://hackmd.io/_uploads/BkauIgAEWe.png) <a id="第20天"></a> # 從本地到容器:Flask 應用 Docker 化實戰 ![image](https://hackmd.io/_uploads/rkW7fg5rbl.png) app.py ``` FROM python:3.14.2-slim # 設定工作目錄 WORKDIR /src/app.py # 複製檔案到工作目錄 COPY app.py . # 安裝 Flask RUN pip install flask # 設定環境變數 ENV FLASK_APP=app.py # 執行程式 CMD ["python", "app.py"] ``` ```bash= # 啟動虛擬環境 source my_flask/bin/activate # 建立 Docker 映像 docker image build -t flask_demo . # 查看映像檔 docker images # 停掉舊容器 docker stop 87af3ca22edd # 刪除舊容器 docker rm 87af3ca22edd # 重新啟動容器並做端口映射 docker run -d -p 5000:5000 flask_demo # 查看正在運行的容器 docker ps # 訪問 Flask 網頁 http://127.0.0.1:5000 # 或在區網其他裝置訪問 http://<Pi的IP>:5000 ``` 製作結果: ![image](https://hackmd.io/_uploads/SygT-x5r-e.png) ![image](https://hackmd.io/_uploads/ryClfl9HWx.png) <a id="第22天"></a> # Dockerfile完全指南 ## 選擇基礎image 1. 建置 image ```bash= docker image build -t mynginx . docker images ``` 2. 修改 Dockerfile 使用 alpine 並建置 ```bash= docker image build -t mynginx_alpine . docker images ``` 3. 執行容器 ```bash= docker run -d --name mynginx -p 8080:80 mynginx ``` 4. 進入容器 ```bash= docker exec -it mynginx sh ``` 5. 查看網頁資料夾 ```bash= cd /usr/share/nginx/html ls cat index.html ``` 製作結果 ![image](https://hackmd.io/_uploads/rJ97d79rWe.png) ![image](https://hackmd.io/_uploads/B15omQqSWl.png) ## Docker 基礎映像與檔案操作練習指令 ```bash # 建置 nginx 映像 docker image build -t mynginx . # 查看現有映像 docker images # 修改 Dockerfile 用 alpine docker image build -t mynginx_alpine . # 執行 nginx 容器 docker run -d --name mynginx -p 8080:80 mynginx # 進入容器查看檔案 docker exec -it mynginx sh cd /usr/share/nginx/html ls cat index.html # 建置 Python hello.py 映像 (COPY) docker image build -f Dockerfile_1 -t hello_py . # 查看映像分層 docker image history hello_py # 進入 hello_py 容器 docker run -it hello_py sh cd /app ls -l # 建置 Python hello.py 映像 (ADD) docker image build -f Dockerfile_2 -t hello_add . # 查看映像分層 docker image history hello_add # 壓縮 hello.py 並用 ADD tar -czf hello.tar.gz hello.py docker image build -f Dockerfile_3 -t hello_gz . # 查看分層並進容器 docker image history hello_gz docker run -it hello_gz sh cd /app ls # 建置 Python hello.py 映像 (WORKDIR) docker image build -f Dockerfile_4 -t hello_workdir . # 查看映像 docker images # 進入 hello_workdir 容器 docker run -it hello_workdir sh pwd ls ``` ``` # 範例 1:使用 COPY FROM python:3.14.2-slim COPY hello.py /app/hello.py # 範例 2:使用 ADD FROM python:3.14.2-slim ADD hello.py /app/hello.py # 範例 3:設定工作目錄再 COPY FROM python:3.14.2-slim WORKDIR /app COPY hello.py hello.py # 範例 4:設定工作目錄再 ADD FROM python:3.14.2-slim WORKDIR /app ADD hello.py hello.py ``` - 製作結果: ![image](https://hackmd.io/_uploads/rk3AsBqBWl.png) <a id="第21天"></a> # Linux 排程實務:cron、at 與 systemd timer 1️⃣ 建立一個 cron 工作 每天晚上 11 點更新電腦上的所有軟體。 2️⃣ 排程你的機器在明天早上 3 點重新開機。 3️⃣ 使用 systemd timer 在系統啟動後 5 分鐘啟動 vsftpd 服務。 ``` * * * * * ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ └─ 星期幾 (0-7, 0 或 7 = Sunday) │ │ │ └───── 月份 (1-12) │ │ └───────── 日 (1-31) │ └───────────── 小時 (0-23) └───────────────── 分鐘 (0-59) ``` ```bash= # Lab 1-1:每天晚上 11 點更新系統(cron) crontab -e 0 23 * * * dnf update -y # Lab 1-2:明天早上 3 點重新開機(at) at 03:00 tomorrow /sbin/reboot Ctrl+D atq atrm <job_number> # Lab 1-3:系統開機後 5 分鐘啟動 vsftpd(systemd timer) # 安裝 vsftpd dnf install -y vsftpd # 建立 service vi /etc/systemd/system/vsftpd-start.service [Unit] Description=Start vsftpd after boot delay [Service] Type=oneshot ExecStart=/usr/bin/systemctl start vsftpd # 建立 timer vi /etc/systemd/system/vsftpd-start.timer [Unit] Description=Run vsftpd 5 minutes after boot [Timer] OnBootSec=5min Unit=vsftpd-start.service [Install] WantedBy=timers.target # 重新載入並啟用 timer systemctl daemon-reload systemctl enable --now vsftpd-start.timer # 驗證 systemctl list-timers systemctl status vsftpd-start.timer systemctl status vsftpd ``` - 製作結果: ![image](https://hackmd.io/_uploads/S1lp6t51Ibx.png) ## Linux 排程任務管理:at、cron 與 systemd timer(review) ```bash= # 查看目前 crontab crontab -l # 編輯使用者 crontab crontab -e # 檢查 cron 服務狀態 systemctl status crond # 查看系統 cron 目錄 ls /etc/cron* # 建立每小時執行的腳本 vim /etc/cron.hourly/test.sh # 內容: # #!/usr/bin/bash # date > /tmp/cron-test.txt # 查看 at 是否安裝 dnf list at # 檢查 at 背景服務狀態 systemctl status atd # 用 at 排程單次任務 at 12:45 # 進入提示符輸入命令: # echo test > test.py # Ctrl+D 離開 # 查看目前 at 任務 atq # 刪除 at 任務 atrm <job_id> # 查看系統預設 cron 任務 more /etc/cron.d/0hourly # 建立自訂 cron 任務 cd /etc/cron.d vim test.cron # 內容: # 2 1 * * * root python /tmp/test.py # 查看 systemd 的 timer units systemctl list-units -t timer systemctl list-timers # 查看 timer 設定檔 systemctl cat dnf-makecache.timer ``` - 參考文獻 https://crontab.guru/# <a id="第22天"></a> # 在Ubuntu容器中安裝 Python 並執行程式 1️⃣ 啟動 nginx container ```bash= docker run -d -p 80:80 nginx:latest docker ps ``` 2️⃣ 進入 container 看檔案 ```bash= docker exec -it <container_id> sh cd /usr/share/nginx/html ls cat index.html more index.html ``` 3️⃣ 修改首頁內容 ```bash= echo "<h1>hello docker</h1>" > index.html cat index.html docker stop <container_id> docker start <container_id> ``` 4️⃣ 保存 container 成新的 image ```bash= docker commit <container_id> name1234/nginx docker images ``` 5️⃣ 在 Ubuntu container 互動並安裝 Python ```bash= docker run -it ubuntu:22.04 sh ``` - 安裝 Python ```bash= apt-get update && apt-get install -y python3 python3-pip ``` - 或使用 noninteractive 方式 ```bash= apt-get update && apt-get install -y python3 python3-pip ``` 6️⃣ 建立 hello.py 並執行 ```bash= clear cd / echo 'print("hello docker")' > hello.py ls python3 hello.py exit ``` 7️⃣ 保存 Python container 成 image ```bash= docker ps -a docker commit <container_id> name1234/python-demo docker images ``` 8️⃣ 執行 Python 程式 ```bash= docker run -it name1234/python-demo python3 /hello.py ``` - 參考文件 https://dockerdocs.tw/build/concepts/dockerfile - 製作結果: ![image](https://hackmd.io/_uploads/S1pWYNz8bg.png) <a id="第23天"></a> # Linux 網路工具筆記 (2026/02/18) ## ping ### 1. ping 檢查網路 ping -c 4 example.com -c 4 → 只測 4 次 回應資訊: ``` 64 bytes from 104.18.27.120 → 封包大小與對方 IP icmp_seq=1 → 封包編號 ttl=128 → 封包生命值(最多可經過多少節點) time=14.3 ms → 往返延遲時間 ``` 統計結果: ``` 4 packets transmitted, 4 received, 0% packet loss, time 3006ms ``` 封包都回來 → 網路正常 ping 可能被防火牆阻擋 → 只是初步檢查 ### 2. Socket / 連線檢查 什麼是 Socket 電腦程式和網路的「接口」 由 IP + 埠號 組成 TCP / UDP TCP → 可靠連線(像打電話📞) UDP → 不可靠快速傳輸(像寄明信片📬) ## ss指令 查看所有監聽埠和 socket ```bash ss -ntulp ``` ``` -t → TCP -u → UDP -l → LISTEN(監聽) -n → 不解析名稱,直接顯示 IP / Port -p → 顯示程式資訊 ``` 欄位解釋 ``` Recv-Q → 接收佇列(還沒處理的資料) Send-Q → 傳送佇列(已送出但未被接收的資料) Local Address:Port → 本機 IP/Port Peer Address:Port → 對方 IP/Port State → 連線狀態,LISTEN / ESTAB / UNCONN ``` 查看正在連線的對方 ```bash= ss -ntu ``` 不加 -l → 不看監聽埠 不加 -p → 不看程式資訊 範例輸出: ![image](https://hackmd.io/_uploads/HJffg7md-e.png) ✅ 總共 5 條連線(1 UDP + 4 TCP) ## Linux 連不上 server?用五個指令找出問題出在哪一層 (2026/02/27) ```bash # 1️⃣ 查看本機 IP ip addr # 2️⃣ 測試連線能力 ping google.com # 測試 hostname ping 8.8.8.8 # 測試 IP # 3️⃣ DNS 解析測試 nslookup google.com # 正確 nslookup google.con # 錯誤測試 # 4️⃣ 查看本地 hosts cat /etc/hosts # 5️⃣ 查看 DNS 設定 cat /etc/resolv.conf # 6️⃣ 查看解析順序 cat /etc/nsswitch.conf # 7️⃣ 檢查路由表 netstat -rn ip route # 8️⃣ 測試 gateway ping 192.168.88.2 ``` - 製作結果: ![image](https://hackmd.io/_uploads/Bk6hfJyF-l.png) <a id="第24天"></a> # 從零建立Linux網路Namespace:veth虛擬連線讓兩個隔離空間互相ping通 (2026/03/01) 網路的 namespace。 Namespace 中文叫「命名空間」, 你可以把它理解成一 種把網路環境隔離開來的技術。 就像兩個房間, 裡面可以各自有自己的網路設定, 互不干擾。 目標是:建立兩個獨立的 namespace, 然後讓它們可以互相 ping 通。 ![image](https://hackmd.io/_uploads/BkFGNiWF-l.png) 一、建立 Namespace ```bash ip netns add ns1 ip netns add ns2 ip netns list ``` 二、查看 Namespace 裡的網路介面 ```bash ip netns exec ns1 ip a ip netns exec ns2 ip a ``` 三、建立 veth 虛擬網路線 ```bash ip netns exec ns1 ip link add veth1 type veth peer name veth2 netns ns2 ``` 四、給 veth 分配 IP ```bash ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth1 ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth2 ``` 五、啟動 veth 與 lo ```bash ip netns exec ns1 ip link set lo up ip netns exec ns1 ip link set veth1 up ``` ```bash ip netns exec ns2 ip link set lo up ip netns exec ns2 ip link set veth2 up ``` 六、確認狀態並測試 ping ```bash ip netns exec ns1 ip a ip netns exec ns2 ip a ``` ```bash ip netns exec ns1 ping 10.0.0.1 ip netns exec ns2 ping 10.0.0.2 ``` ```bash ip netns exec ns1 ping 10.0.0.2 ip netns exec ns2 ping 10.0.0.1 ``` - 製作結果: ![image](https://hackmd.io/_uploads/ByBqHi-FZe.png) ## DNS ```bash # 查看系統使用的 DNS cat /etc/resolv.conf # 查看啟用網卡和路由 ip route # 查看 ens160 設定 nmcli c s ens160 nmcli device show ens160 # 清空 DNS nmcli c m ens160 ipv4.dns "" nmcli c up ens160 # 手動設定 DNS nmcli c m ens160 ipv4.dns 8.8.8.8 nmcli c up ens160 # 調整 ens160 路由優先權 nmcli c m ens160 ipv4.route-metric 100 nmcli c up ens160 # 測試網路 ping google.com ping 8.8.8.8 ``` - 製作結果: ![image](https://hackmd.io/_uploads/Sk9WnBVFZg.png) <a id="第25天"></a> # Linux 網管:使用 nmcli 建立永久連線並設定靜態 IP | 網卡 | 狀態 | IP | 說明 | |--------|------|-----------------------|----------------------------------------| | lo | UP | 127.0.0.1 | 本機迴路,不會連網 | | ens160 | UP | 192.168.127.128/24 | 主網卡,已連上 NAT,能上網 | | ens224 | UP | 無 | 第二張 NAT 網卡,沒有 IP,暫時無法使用 | ```bash # 1️⃣ 查看網卡狀態 ip addr # 2️⃣ 查看路由表 ip route # 3️⃣ 臨時給 ens224 設定 IP(測試用) ip addr add 192.168.127.200/24 dev ens224 metric 200 ip link set ens224 up ip route # 4️⃣ 查看外網連線(測試) ping -c 3 8.8.8.8 # 5️⃣ 檢查 NetworkManager 狀態 systemctl status NetworkManager # 6️⃣ 查看永久設定檔位置 (RHEL8) ls /etc/sysconfig/network-scripts/ # 7️⃣ 建立永久靜態 IP 連線 nmcli connection add type ethernet con-name ens224-static ifname ens224 \ ipv4.addresses 10.0.0.16/24 ipv4.gateway 10.0.0.1 \ ipv4.dns 8.8.8.8 ipv4.method manual autoconnect yes # 8️⃣ 套用設定 nmcli connection up ens224-static ip addr show ens224 ip route # 9️⃣ 重新啟動 NetworkManager(選擇性) systemctl restart NetworkManager # 🔟 重新開機確認 reboot ip addr ip route ``` - 製作結果: ![image](https://hackmd.io/_uploads/HkmiPpzKbl.png) <a id="第26天"></a> # Linux 防火牆:iptables封鎖與開放連線操作 (2026/03/04) ## 🖥 實驗環境(兩台 VM) | VM | 用途 | IP 範例 | |------|-------------------------|-----------------| | VM1 | 當伺服器(設定 iptables) | 192.168.127.128 | | VM2 | 當測試機(發送請求) | 192.168.127.129 | 👉 兩台設成 **同一個內部網路**(Host-only 或 Internal Network) | 步驟 | 指令 | 說明 | |------|------|------| | 清空規則並封鎖所有進入流量 | `sudo iptables -F`<br>`sudo iptables -P INPUT DROP` | `-F`:清空規則<br>`-P INPUT DROP`:預設封鎖所有進入流量 | | 允許 ICMP(ping) | `sudo iptables -A INPUT -p icmp -j ACCEPT` | `-A INPUT`:新增規則到 INPUT 鏈<br>`-p icmp`:ICMP 協定<br>`-j ACCEPT`:允許封包 | | 允許 SSH(TCP 22 port) | `sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT` | `-p tcp --dport 22`:TCP 22 port<br>`-j ACCEPT`:允許封包 | | 測試 SSH 連線 | `ssh nameless@student@192.168.127.128` | 從 VM2 登入 VM1,驗證防火牆效果 | ## 🔹 防火牆基本設定指令 | 指令 | 功能 | | ------------------------ | --------------- | | `iptables -F` | 清空所有規則 | | `iptables -P INPUT DROP` | 設定預設政策為拒絕(DROP) | ## 🔹 允許 ICMP(ping)的指令參數 | 參數 | 功能 | | ----------- | ---------------------------------------- | | `-A INPUT` | append 加到 INPUT 這條鏈的最後面;INPUT 是「進入本機的封包」 | | `-p icmp` | 指定協定為 ICMP(像 ping 封包) | | `-j ACCEPT` | 動作(jump),允許這個封包通過 | ## 範例 ```bash= # VM1(伺服器) # 1️⃣ 查看目前規則 iptables -L -n -v # 2️⃣ 清空規則 iptables -F # 3️⃣ 設定預設拒絕 iptables -P INPUT DROP # 4️⃣ 再次確認 iptables -L -n -v # 5️⃣ 允許 ping(ICMP) iptables -A INPUT -p icmp -j ACCEPT # 6️⃣ 查看規則 iptables -L -n -v # 7️⃣ 允許 SSH(22) iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 8️⃣ 查看規則 iptables -L -n -v # (測試用)刪除 SSH 規則 iptables -D INPUT -p tcp --dport 22 -j ACCEPT # (全部重置) iptables -F iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT ``` ## SSH 與防火牆設定實務 (2026/03/06) 主機 | IP 位址 | 使用者帳號 | |------|----------------|------------------| | 第一台 | 192.168.88.129 | nameless@student | | 第二台 | 192.168.88.130 | server@server | 1. 環境檢查與準備 * **執行機器:** 第二台 (Server: .130) ```bash= # 檢查是否運行舊版 iptables ps -ef | grep iptables ``` 檢查新版 firewalld 狀態 ```bash= systemctl status firewalld ``` 檢查 SSH 服務狀態 (Port 22) ```bash= systemctl status sshd # (若未啟動) sudo systemctl start sshd ``` 2. 建立基準測試 (連線成功) 執行機器: 第一台 (Client: .129) 測試 SSH Port 連線 ```bash= telnet 192.168.88.130 22 # 離開方式: 按 Ctrl + ] 後輸入 quit ``` 3. 設定防火牆阻擋規則 (模擬故障) 執行機器: 第二台 (Server: .130) 切換 root 權限 ```bash= sudo -i ``` 查看目前規則清單 ```bash= firewall-cmd --list-all ``` 1. 移除預設 SSH 服務允許 (避免白名單干擾) ```bash= firewall-cmd --remove-service=ssh --permanent ``` 2. 移除ssh服務 ```bash= firewall-cmd --remove-service=ssh --permanent ``` 3. 重新載入規則使其生效 ```bash= firewall-cmd --reload ``` 4. 驗證阻擋現象 執行機器: 第一台 (Client: .129) ```bash= # 再次測試,預期會失敗 (Timeout 或 No route to host) telnet 192.168.88.130 22 ``` 5.第二台:重新允許 SSH ```bash= firewall-cmd --add-service=ssh --permanent sudo firewall-cmd --reload ``` 6. 最終驗證 執行機器: 第一台 (Client: .129) - 確認連線恢復正常 (Connected) ```bash= telnet 192.168.88.130 22 ``` --- ![image](https://hackmd.io/_uploads/HJxPZHOKbe.png) <a id="第27天"></a> # 3/8 網路管理 ## 基本指令 ```bash 1️⃣ ping 基本用法 $ ping -c 4 8.8.8.8 2️⃣ flood ping $ ping -i 0.002 -f 127.0.0.1 3️⃣ 安裝 traceroute $ sudo apt install traceroute traceroute 範例 $ traceroute 8.8.8.8 $ traceroute -n 8.8.8.8 # 不反解 IP 4️⃣ tracepath 範例 $ tracepath 8.8.8.8 $ tracepath 8.8.8.8 -p 3000 # 指定連接埠 5️⃣ ip 指令 $ ip addr # 查看所有網路介面 $ ip a # 簡寫 $ ip a show ens33 # 查看指定介面 $ ip a s ens33 # 簡寫 $ ip -br addr # 簡潔模式 $ ip route # 查看本機路由表 ``` ## Netplan 靜態 IP 設定 (2026/03/09) ```bash # 1️⃣ 確認目前網卡 IP ip a # 2️⃣ 先切換到 Netplan 設定目錄 cd /etc/netplan ls # 3️⃣ 備份舊的 YAML 設定檔 sudo mv *.yaml *.yaml.bak # 4️⃣ 建立新的靜態 IP YAML 設定檔 sudo nano /etc/netplan/01-static.yaml 在 nano 編輯器中貼上以下內容(注意縮排): network: version: 2 renderer: networkd ethernets: ens33: # 網卡名稱,可用 ip link 查 dhcp4: false # 關閉 DHCP addresses: - 192.168.127.123/24 # 靜態 IP routes: - to: default via: 192.168.127.2 # 預設閘道 nameservers: addresses: - 8.8.8.8 - 8.8.4.4 ``` ```bash= # 5️⃣ 套用新的 Netplan 設定 sudo netplan apply # 6️⃣ 驗證網卡是否套用靜態 IP ip a s ens33 # 8️⃣ 測試網路連線 ping -c 4 8.8.8.8 # 測試網路是否通 ping -c 4 google.com # 測試 DNS 是否正常 # 9️⃣ 最後可以重新開機確保設定永久生效 sudo reboot ``` - 製作結果: ![image](https://hackmd.io/_uploads/BJWo0RoFZl.png) ## network manager (2026/03/15) NetworkManager - nmtui 設定 IP 使用 NetworkManager 的文字介面工具 nmtui 來修改 IP。 1. 主機資訊 | 主機 | 使用者 | 主機名稱 | 原 IP | 修改後 IP | |------|--------|----------|--------|------------| | 🖥️ 主機一 (Control Node) | ansible | control | 192.168.88.131 | **192.168.88.121** | | 🖥️ 主機二 (Student Node) | nameless | student | 192.168.88.129 | **192.168.88.122** | 2. 設定流程 - Step 1 開啟 nmtui sudo nmtui - Step 2 進入網卡設定 選擇: Edit a connection - Step 3 修改 IPv4 設定 找到: IPv4 CONFIGURATION 將 Automatic 改為 Manual - Step 4 設定 IP Address 主機一: Addresses : 192.168.88.121 主機二: Addresses : 192.168.88.122 - Step 5 設定 Gateway Gateway : 192.168.88.2 - Step 6 設定 DNS DNS Servers : 8.8.8.8 168.95.1.1 - Step 7 重新啟動網路連線 回到主畫面,選擇: Activate a connection 重新啟用網卡讓設定生效。 3. 確認 IP 是否生效 離開 nmtui 後執行: ```bash= ip a ``` 如果設定成功,會看到: ``` 192.168.88.121 或 192.168.88.122 ``` ## Linux 網路管理 - ARP 協議與局域網 MAC 管理 (2026/03/11) ```bash # 查看 ARP 表 ip neighbor show # 簡寫 ip n # 使用舊版 arp 指令(需先安裝 net-tools) sudo apt install net-tools arp -a # 列出所有 ARP Cache,會嘗試解析名稱 arp -an # 只顯示數字形式 IP → MAC,輸出簡潔 # 刪除單一 ARP 紀錄 sudo ip neigh del 192.168.88.1 dev ens33 # 清空整個 ARP Cache sudo ip neigh flush all # 查看 STALE 時間設定 sudo sysctl -a | grep gc_stale # 臨時修改 STALE 時間為 120 秒 sudo sysctl -w net.ipv4.neigh.default.gc_stale_time=120 # 永久修改 STALE 時間 sudo vi /etc/sysctl.conf # 在檔案末尾添加: net.ipv4.neigh.default.gc_stale_time=120 # 套用所有永久設定 sudo sysctl --system # 刪除單一 ARP 紀錄 sudo ip neigh del 192.168.88.1 dev ens33 # 刪除後查看 ARP 表 ip n # 注意: # 如果之後再對該 IP 發送 ping,ARP 紀錄會重新生成 ping 192.168.88.1 ip n # 就會看到 ARP 又回來了 ``` - 製作結果: ![image](https://hackmd.io/_uploads/S1dmV0RtWl.png) <a id="第28天"></a> # Bonding Active-Backup主備備援實作 (2026/03/13) Active-Backup,也叫 mode 1, 中文名稱為「主備模式」 是一種網路 Bonding 模式,它的核心概念很簡單: 一張網卡負責主要傳輸(Active) 其他網卡作為備援(Backup) 當主要網卡故障或失效時,系統會自動切換到備援網卡 達到 高可用性,確保網路不中斷 這種模式的好處是 簡單、穩定、可靠, 不需要對交換器做任何額外設定, 幾乎可以在任何 Linux 或虛擬化環境直接使用。 ## 前置作業 - 1. 準備兩張網卡 network adapter1(ens37) network adapter2(ens38) - 2 確認 /etc/netplan 底下目前沒有其它yaml文件 ## yaml檔參考 ```bash= network: version: 2 renderer: networkd bonds: bond0: interfaces: - ens37 - ens38 parameters: mode: active-backup # 主備模式 mii-monitor-interval: 100 # 每 100ms 檢測一次網卡是否存活 primary: ens37 # 指定 ens37 為主要網卡 addresses: - 192.168.127.200/24 routes: - to: default via: 192.168.127.2 nameservers: addresses: - 8.8.8.8 - 8.8.4.4 ``` ## 製作流程 1️⃣ 確認目前網卡 ```bash= ip a ``` 2️⃣ 啟用新增的網卡 ```bash= sudo ip link set ens37 up sudo ip link set ens38 up ``` 再次確認: ```bash= ip a ``` 3️⃣ 進入 Netplan 設定目錄 ```bash= cd /etc/netplan ls ``` 4️⃣ 編輯 YAML 設定檔 ```bash= sudo vi 02-bond.yaml ``` 5️⃣ Netplan 測試設定 先測試設定: ```bash= sudo netplan try ``` 確認沒有問題後正式套用: ```bash= sudo netplan apply ``` 6️⃣ 確認 bond0 是否建立 ```bash= ip a ``` 應該會看到: ``` bond0 ``` 7️⃣ 測試 IP 是否可連線 ```bash= ping 192.168.127.200 ``` 8️⃣ 查看 Bonding 狀態 ```bash= cat /proc/net/bonding/bond0 ``` 重點查看: ``` Bonding Mode Primary Slave Currently Active Slave ``` 9️⃣ Failover 測試(模擬主網卡斷線) 先讓主網卡斷線: ```bash= sudo ip link set ens37 down ``` 再次查看 Bond 狀態: ```bash= cat /proc/net/bonding/bond0 ``` 應該會看到: ``` Currently Active Slave: ens38 ``` 🔟 恢復主網卡 ```bash= sudo ip link set ens37 up ``` 再次確認: ```bash= cat /proc/net/bonding/bond0 ``` 應該會恢復: ```bash= Currently Active Slave: ens37 ``` - 製作結果: ![image](https://hackmd.io/_uploads/SksfwXZ5be.png) ## Rocky Linux 防火牆管理:開放 HTTP 和 SSH (2026/03/16) ``` # 1. 安裝 Apache sudo dnf install -y httpd # 2. 啟動並設定開機啟動 sudo systemctl enable --now httpd sudo systemctl status httpd # 3. 建立首頁 cd /var/www/html sudo vi index.html # → 輸入內容,例如:linux20260316 cat index.html # 4. 查看 Apache 是否監聽 ss -ntl # 5. 查看防火牆狀態 sudo firewall-cmd --state sudo firewall-cmd --list-all # 6. 開放 HTTP(80/tcp) sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --reload sudo firewall-cmd --list-all # 7. 測試瀏覽器輸入伺服器 IP # http://192.168.88.121 # 8. 移除 SSH 服務 sudo firewall-cmd --permanent --remove-service=ssh sudo firewall-cmd --reload sudo firewall-cmd --list-services # 9. 測試 SSH 連線 ssh ansible@192.168.88.121 # 10. 新增 SSH 服務 sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --reload sudo firewall-cmd --list-services # 11. 再次測試 SSH 連線 ssh ansible@192.168.88.121 ``` - 製作結果: ![image](https://hackmd.io/_uploads/BkEwYOBcbg.png) ## DNS-架構與網域名稱從根到子網域的層級關係 (2026/03/17) ```bash= # 查 A 記錄(IPv4) host www.example.com # 查 MX 記錄(郵件伺服器) host -t MX example.com # 查 NS 記錄(名稱伺服器) host -t NS example.com # 反向查詢(IP → 網域名稱) dig -x 104.18.26.120 ```