跳转到内容

第 29 章 · Linux 服务器基本功

一句话:登录一台 Linux 服务器后最常做的几件事:看权限、找进程、查端口、看磁盘和日志、开防火墙、定时跑任务、管用户。 用它还是用别的:云服务器、VPS、公司的 Linux 机器都按这一章操作;只想在自己电脑上跑项目,用 WSL 或 Docker(第 12 章)就够了,不必另租一台服务器练手。 核对版本:Ubuntu 24.04.3(WSL 2.6,内核 6.6)、PowerShell 7.6,2026-10

租来的云服务器、VPS 开机就是装好的 Linux,选镜像时选 Ubuntu 24.04 LTS 即可,本章命令以它为准。本地练习,Windows 上用 WSL 装一个 Ubuntu,以管理员身份在 PowerShell 里运行,完整步骤见第 4 章 4.4:

终端窗口
wsl --install

macOS 没有 WSL,用 Canonical 出的 Multipass 起一台 Ubuntu 虚拟机,再 multipass shell dev 进去:

终端窗口
brew install --cask multipass
multipass launch 24.04 --name dev

WSL 和虚拟机适合练文件、权限、进程、cron;SSH 登录、防火墙这几样要在真服务器上才完整,WSL 默认不跑 SSH 服务,外面也连不进来。

查发行版和版本,前一条看 VERSION,后一条看内核版本,在 WSL 里结尾是 microsoft-standard-WSL2:

终端窗口
cat /etc/os-release
uname -r
  • 用户与 root:每个用户有一个数字编号(UID),root 的 UID 是 0,什么都能改、什么都能删。平时用普通用户登录,要管理员权限的命令前面加 sudo,输的是自己的密码。能用 sudo 的用户在 Ubuntu 上属于 sudo 组,在 RHEL、Rocky 上属于 wheel 组,id 能看到自己在哪些组。
  • 文件权限(Permission):每个文件有一个属主(owner)和一个属组(group),权限分三段:属主、属组、其他人,每段三位 r 读、w 写、x 执行。三位换成数字是 r=4、w=2、x=1 相加,三段连起来就是 chmod 用的八进制写法,如 750。对目录来说,x 表示能进入,没有它连目录里的文件名都打不开。
  • 进程与信号(Signal):每个运行中的程序是一个进程,有一个进程号(PID)。kill 实际是给进程发信号:默认发 SIGTERM(15),请它收尾后退出;kill -9 发 SIGKILL,内核直接结束它,程序没有任何收尾机会。
  • 端口与监听地址:服务启动时要绑定“地址加端口”。绑在 0.0.0.0 表示所有网卡上来的请求都收,外面能连;绑在 127.0.0.1 只收本机来的请求,外面根本连不上,数据库、Redis 这类后端服务应该这样绑。端口号小于 1024 的要 root 权限才能绑。
  • 包管理器:Ubuntu、Debian 用 apt,软件源列表在 /etc/apt/ 下;RHEL、Rocky、Fedora 用 dnf,写法差不多,如 sudo dnf install nginx。
  • 日志在哪:用 systemd 管理的服务,输出由 journald 收集,用 journalctl 看(第 30 章);还有一部分程序自己写文本日志到 /var/log/ 下,如 /var/log/syslog、/var/log/auth.log(SSH 登录记录)、/var/log/nginx/。

ls -l 输出的第一列,如 -rwxr-x---,按下图拆成四段读:第一位是类型,后面三段各三位,分别是属主、属组和其他人的权限。三段各自换算成一个数字,合起来就是 chmod 750:属主能读写执行,属组能读和执行,其他人什么都不能做。

-rwxr-x— 拆成类型、属主、属组、其他人四段,属主 rwx 等于 7,属组 r-x 等于 5,其他人 — 等于 0,合起来是 750

监听地址和防火墙是两道关:请求先过防火墙,再看有没有程序在那个地址和端口上收。下图里 PostgreSQL 只绑了 127.0.0.1,即使防火墙放行 5432,外部请求也没人接。

外部请求先经过只放行 22、80、443 的防火墙,到达监听 0.0.0.0 的 Nginx;监听 127.0.0.1 的 PostgreSQL 只接收本机程序的连接

需要 root 的命令前面已经写了 sudo。<PID>、<服务> 这类尖括号里的内容换成自己的。ss -ltnp 不加 sudo 时,最后一列只显示自己启动的进程。

任务 命令 说明
文件与权限
看权限、属主、属组 ls -l 第一列如 -rwxr-x---,第三、四列是属主和属组
看八进制权限 stat -c '%a %A %U %G %n' deploy.sh 输出 750 -rwxr-x--- deploy deploy deploy.sh
按数字设权限 chmod 750 deploy.sh 目录常用 755,普通文件 644,私钥和密码文件 600
只加执行位 chmod u+x deploy.sh u 属主、g 属组、o 其他人;o-r 是去掉其他人的读
改属主和属组 sudo chown -R www-data:www-data /srv/app 不是 root 时报 Operation not permitted
找 7 天前的日志 find /var/log -name '*.gz' -mtime +7 确认列表无误再在末尾加 -delete
找大文件 sudo find / -xdev -type f -size +100M -xdev 不跨到别的磁盘和挂载点
建或换软链接 ln -sfn /srv/app/releases/20261008 /srv/app/current 发版时切换 current 指向,ls -l current 看指向哪里
进程
列出所有进程 ps aux USER、PID、%CPU、%MEM、COMMAND 几列最常看
按内存排序 ps aux --sort=-%mem | head 按 CPU 排序改成 --sort=-%cpu
实时看负载 top 按 P 按 CPU 排、M 按内存排、q 退出;htop 更好用,要先 sudo apt install htop
按名字找 PID pgrep -af node -a 连完整命令行一起显示
请进程退出 kill <PID> 发 SIGTERM,进程收尾后退出
强制结束 kill -9 <PID> 最后手段,见 29.6
退出登录后照样跑 nohup ./job.sh > job.log 2>&1 & 长期运行的服务交给 systemd(第 30 章)
端口与网络
哪些端口在监听、归谁 sudo ss -ltnp 第四列是监听地址,最后一列是进程名和 pid=
只看某个端口 sudo ss -ltnp | grep :8080 没有输出就是没人在听
看 HTTP 响应头 curl -I https://example.com 第一行是状态码,如 HTTP/2 301
看本机 IP ip a ip -br a 每块网卡一行
查域名解析 dig +short example.com 没有就 sudo apt install dnsutils,或用 nslookup example.com
磁盘
各分区用了多少 df -h 看 Use% 和 Mounted on,/ 那一行最要紧
一个目录占多少 du -sh /var/log 看下一级各占多少:sudo du -sh /var/log/* | sort -h
有哪些磁盘 lsblk 新挂的云硬盘在这里出现,还没有挂载点
日志
看某个服务的日志 journalctl -u nginx -n 50 加 -f 持续跟踪,--since "1 hour ago" 限时间
只看错误 journalctl -p err -b 本次开机以来的错误级别日志
跟踪文本日志 tail -f /var/log/nginx/error.log Ctrl+C 停止
防火墙(ufw)
看状态和规则 sudo ufw status verbose 显示 Status: inactive 就是没开
放行端口 sudo ufw allow 80,443/tcp SSH 用 sudo ufw allow OpenSSH
启用 sudo ufw enable 先放行 SSH 再启用,见 29.6
定时任务(cron)
看自己的定时任务 crontab -l 没有时显示 no crontab for <用户>
编辑定时任务 crontab -e 第一次会让你选编辑器,保存即生效
一行的写法 30 3 * * * /home/deploy/bin/backup.sh 五段依次是分、时、日、月、星期,这行是每天 3:30
用户
建用户 sudo adduser deploy 交互式,会建家目录、让你设密码
加进 sudo 组 sudo usermod -aG sudo deploy 漏了 -a 会把用户从其他组里移出
看用户和所在组 id deploy 新加的组这里立刻能看到;那个用户已登录的会话要重新登录才生效

云厂商给了 IP 和 root 密码。有的镜像不开放 root,给的是 ubuntu 用户加密钥,那就用它登录,第 2、3 步的命令前面加 sudo。做完后:日常用普通用户、只能用密钥登录、root 不能登录、只开 22、80、443:

  1. 以 root 登录:ssh root@<服务器IP>。
  2. 更新系统:apt update && apt upgrade -y。
  3. 建普通用户,按提示设密码,再加进 sudo 组:adduser deploy && usermod -aG sudo deploy。
  4. 在本机另开终端,把公钥装给新用户,原理和 Windows 写法见第 6 章 6.3、6.4:ssh-copy-id deploy@<服务器IP>。
  5. 用新用户登录,再运行 sudo whoami,输出 root 就对了:ssh deploy@<服务器IP>。
  6. 保持这个窗口不关,新建 SSH 配置文件,写入 29.5 的片段:sudo nano /etc/ssh/sshd_config.d/00-local.conf。
  7. 检查并让配置生效:sudo sshd -t && sudo systemctl restart ssh。
  8. 再开一个本机终端,确认密钥登录照样能进,而 ssh root@<服务器IP> 被拒绝:ssh deploy@<服务器IP>。
  9. 放行 SSH 和网站端口:sudo ufw allow OpenSSH && sudo ufw allow 80,443/tcp。
  10. 启用防火墙,问 Proceed with operation (y|n)? 时输 y:sudo ufw enable。

最后打开自动安全更新,选 Yes,它写的是 /etc/apt/apt.conf.d/20auto-upgrades,Ubuntu 24.04 的镜像通常已经开好:sudo dpkg-reconfigure -plow unattended-upgrades。第 8 步登不上,回到第 6 步的窗口删掉 00-local.conf 再重启 ssh。

启动程序报端口被占,或想知道 8080 上跑的是什么:

  1. 找出监听 8080 的进程,最后一列形如 users:(("node",pid=1234,fd=20)):sudo ss -ltnp | grep :8080。
  2. 看第四列地址:127.0.0.1:8080 只有本机能连,0.0.0.0:8080 或 *:8080 外面也能连。
  3. 看这个进程是谁、什么时候启动、完整命令行:ps -o pid,user,lstart,cmd -p 1234。
  4. 看它在哪个目录下运行,判断是哪个项目:sudo ls -l /proc/1234/cwd。
  5. 看它是不是 systemd 管的服务,第一行就是服务名:systemctl status 1234。
  6. 从自己电脑上试能不能连到,连不上再查防火墙和监听地址:curl -I http://<服务器IP>:8080。
  7. 确认不要了,是服务就停服务(第 30 章),不是就请它退出:kill 1234。

把 /srv/app/data 每天 3:30 打包到 ~/backup,只留最近一周的。先写脚本 ~/bin/backup.sh:

#!/bin/bash
set -euo pipefail # 任一步出错就停,不留半截备份
tar czf "$HOME/backup/app-$(date +%F).tar.gz" -C /srv/app data
find "$HOME/backup" -name 'app-*.tar.gz' -mtime +6 -delete # 删掉满 7 天的
  1. 建目录:mkdir -p ~/bin ~/backup。
  2. 写入上面的脚本:nano ~/bin/backup.sh。
  3. 只让自己能读写执行:chmod 700 ~/bin/backup.sh。
  4. 手动跑一次,看到当天的 app-2026-10-08.tar.gz 就对了:~/bin/backup.sh && ls -lh ~/backup。
  5. 打开自己的定时任务:crontab -e。
  6. 在文件末尾加一行,路径写全,输出和报错都进日志:30 3 * * * /home/deploy/bin/backup.sh >> /home/deploy/backup/cron.log 2>&1。
  7. 确认已保存:crontab -l。
  8. 第二天看 cron 有没有跑,日志里有 (deploy) CMD (/home/deploy/bin/backup.sh …) 一行:journalctl -u cron --since yesterday。
  9. 看脚本自己的输出和报错:tail ~/backup/cron.log。

备份放在同一台服务器上防不住磁盘坏或机器被删,再用 rsync 拷一份到别处(第 6 章)。

服务器上常改的配置文件,都在 /etc 下,改之前先 sudo cp <文件> <文件>.bak 备份:

范围 路径
SSH 服务端 /etc/ssh/sshd_config;自己的改动放 /etc/ssh/sshd_config.d/00-local.conf,原因见第 6 章 6.5
ufw 开关和规则 /etc/ufw/,ufw allow 写进的规则在 user.rules 里,用命令改,不手改
ufw 默认策略 /etc/default/ufw,默认拒绝入站、允许出站
系统定时任务 /etc/crontab 和 /etc/cron.d/ 下的文件,比 crontab -e 多一列用户名,如 30 3 * * * root /usr/local/bin/backup.sh
用户定时任务 /var/spool/cron/crontabs/<用户>,只用 crontab -e 改
软件源 /etc/apt/sources.list.d/ubuntu.sources(24.04 起),旧版本是 /etc/apt/sources.list
自动更新 /etc/apt/apt.conf.d/20auto-upgrades(开关)、50unattended-upgrades(装哪些更新)
sudo 规则 /etc/sudoers 和 /etc/sudoers.d/,只用 sudo visudo 改,写错了它会拒绝保存

sshd_config 值得改的项:

配置项 建议值 效果
PermitRootLogin no root 不能登录,已经有能 sudo 的普通用户后再设;第 6 章的 prohibit-password 允许 root 用密钥登录
PasswordAuthentication no 只能用密钥登录,挡住全网扫描的密码爆破
KbdInteractiveAuthentication no 关掉另一种输密码的方式,Ubuntu 默认已是 no
PubkeyAuthentication yes 允许密钥登录,默认就是 yes,写出来防止被别的文件改掉
AllowUsers deploy 只有列出的用户能登录,多个用空格隔开
MaxAuthTries 3 一次连接最多试 3 次,默认 6

最小片段,写进 /etc/ssh/sshd_config.d/00-local.conf。sshd_config 只认行首的 # 为注释,注释要单独一行;写完 sudo sshd -t 检查,sudo sshd -T | grep -i permitrootlogin 看最终生效的值:

# root 不能通过 SSH 登录,管理员操作用 sudo
PermitRootLogin no
# 不接受密码登录,只认密钥
PasswordAuthentication no
# 关掉键盘交互式认证,免得绕过上一行再问密码
KbdInteractiveAuthentication no
# 允许公钥登录
PubkeyAuthentication yes
# 只允许 deploy 这个用户登录
AllowUsers deploy
# 一次连接最多尝试 3 次
MaxAuthTries 3
  • ./deploy.sh: Permission denied 或 cat: /etc/shadow: Permission denied。 原因:当前用户在对应那段权限里没有 r、w 或 x,或属主不是自己。处理:ls -l 看缺哪一位;脚本缺执行位 chmod u+x deploy.sh;属主不对 sudo chown deploy:deploy <文件>。
  • chmod -R 777 之后程序能跑了。 原因:权限问题没解决,只是让所有用户都能改这些文件,任何被攻破的进程都能改代码和配置。处理:属主改成运行服务的用户,再改回目录 755、文件 644:find /srv/app -type d -exec chmod 755 {} +,文件把 -type d 换 -type f、755 换 644。
  • 服务器上 curl localhost:8080 正常,从外面连报 Connection refused。 原因:程序只监听本机,ss -ltnp 里是 127.0.0.1:8080。处理:改为监听 0.0.0.0(如 --host 0.0.0.0)并 sudo ufw allow 8080/tcp;对外网站更好的做法是前面放 Nginx(第 16 章)。
  • sudo ufw enable 之后,新开的 SSH 连接一直超时。 原因:启用前没放行 22,ufw 默认拒绝所有入站连接,已连着的窗口一般还在。处理:在还没断的窗口里 sudo ufw allow OpenSSH;旧窗口也断了,就从云控制台的网页终端登录再放行;以后先 allow 再 enable。
  • 脚本手动跑正常,放进 cron 报 command not found。 原因:cron 不读 ~/.bashrc,PATH 只有 /usr/bin:/bin,nvm 装的命令找不到。处理:脚本里写绝对路径(command -v node 查);或在 crontab 首行写 PATH=,把 command -v node 所在目录加到 /usr/bin:/bin 前。
  • cron 里 date +%F 那一行只执行了一半,文件名没生成。 原因:crontab 里 % 表示换行,后面的内容被当成命令的标准输入。处理:写成 date +\%F,或者像 29.4 那样把命令放进脚本,crontab 里只写脚本路径。
  • df -h 显示 / 用到 100%,du 加起来却少很多。 原因:文件删了,但还被进程打开着(多是日志),空间要等进程关掉它才释放。处理:sudo lsof +L1 找到标着 (deleted) 的进程,重启它:sudo systemctl restart <服务>。
  • 用 kill -9 停了数据库或应用,再启动时数据少了一截,或报锁文件已存在。 原因:SIGKILL 不给程序收尾机会,缓冲区没落盘、锁文件没删。处理:先 kill <PID>,等十几秒还在再用 -9;交给 systemd 管的服务用 systemctl stop(第 30 章)。
  • cron 定在 0 3 * * * 的任务,实际在北京时间 11 点跑。 原因:服务器时区是 UTC,cron 按系统时区算。处理:timedatectl 查看,sudo timedatectl set-timezone Asia/Shanghai 后 sudo systemctl restart cron;或者按 UTC 换算时间来写。
  • Ubuntu Server 文档:Ubuntu 官方服务器文档,用户与权限、软件包、OpenSSH、防火墙、自动更新、备份都有分步说明。
  • 防火墙 ufw(Ubuntu Server 文档):ufw 的启用、放行端口、按应用名放行、查看与删除规则,以及日志。
  • Ubuntu 手册页:sshd_config:Ubuntu 24.04 上 sshd_config 每个配置项的含义和默认值,PermitRootLogin、PasswordAuthentication、AllowUsers 都在这里。
  • Linux man-pages(man7.org):Linux 命令和系统调用的手册页总目录,chmod、kill、信号(signal(7))、crontab(5) 等都能查到。
  • crontab.guru:输入五段的 cron 表达式,立刻用英文说明它什么时候运行,并显示接下来几次的时间。
  • Ubuntu 初始服务器设置(DigitalOcean 教程):新服务器建普通用户、授予 sudo、开 ufw、配置 SSH 密钥登录的分步教程,长期随 Ubuntu 版本更新。