---
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
```
- 製作結果:

<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
```
- 製作結果:

<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
```
- 製作結果:

---
<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
```
- 製作結果:

## 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/
```
- 製作結果:

<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
```
- 結果參考

<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 是否生效
```
製作結果:

## 精細掌控 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
```
- 製作結果:

## 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)
```
- 製作結果:

## 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 # 查看結果
```
- 製作結果:

<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 密碼狀態
```
- 製作結果:

## 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(難維護)
- 結果參考:

<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
```
製作結果:

## 還原方式
```
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
```
- 製作結果:

### 還原方式
```
# 移除 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
```
結果參考:

---
## 參考資料
- [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 # 將指定編號的背景行程放到前景
```
- 製作結果:

## 優先級
(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
```
- 製作結果:

| 項目 | 說明 | 數值範圍 | 數字越大代表 |
| -------------- | ---------- | -------- | --------- |
| 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
# 不需要密碼即可登入
```
- 結果如下:

## 控制端公鑰傳送與建立 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
```
- 製作結果:

<a id="第11天"></a>
# LVM邏輯卷建立與容量擴展實作
先用`lsblk` 確認是否有一個sda磁碟
範例如下:

```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
```
結果:

<a id="第12天"></a>
# Nginx 反向代理進階 Upstream 群組管理與 SELinux 設定
前置作業:

SELinux阻擋問題:

```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
```
- 結果如下
-
<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
```
製作結果:

<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
```
- 製作結果:

<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"
```
- 製作結果

## 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"
```
製作結果:

## 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
```
- 結果參考:

<!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>
- 製作結果:

<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"
```
製作成果:

## 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
建立腳本
給予權限
執行腳本測試
收信並刪信
刪除測試檔案與停止服務
```
製作結果:

<a id="第20天"></a>
# 從本地到容器:Flask 應用 Docker 化實戰

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
```
製作結果:


<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
```
製作結果


## 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
```
- 製作結果:

<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
```
- 製作結果:

## 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
- 製作結果:

<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 → 不看程式資訊
範例輸出:

✅ 總共 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
```
- 製作結果:

<a id="第24天"></a>
# 從零建立Linux網路Namespace:veth虛擬連線讓兩個隔離空間互相ping通
(2026/03/01)
網路的 namespace。
Namespace 中文叫「命名空間」,
你可以把它理解成一
種把網路環境隔離開來的技術。
就像兩個房間,
裡面可以各自有自己的網路設定,
互不干擾。
目標是:建立兩個獨立的 namespace,
然後讓它們可以互相 ping 通。

一、建立 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
```
- 製作結果:

## 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
```
- 製作結果:

<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
```
- 製作結果:

<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
```
---

<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
```
- 製作結果:

## 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 又回來了
```
- 製作結果:

<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
```
- 製作結果:

## 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
```
- 製作結果:

## 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
```