释放小七猫的分享欲

搭建 Debian13 网站服务器全流程指南

tags: Linux
@ 14/10/2025

从零搭建一个 Debian13 网站服务器

最近发现家里面开通的移动宽带,在光猫中调整防火墙等级为“低”后,竟然可以从公网直接访问 80/443 端口??

这不拿来搭网站太浪费了,直接开干!

系统选择

对 Linux 比较熟的可以选择像我一样选 Debian,只懂基本命令的可以选 Fedora,喜欢 Snap(真的有吗?)的可以选 Ubuntu-Server,不怕死的选 Arch,系统洁癖选 NixOS。

  • Debian 13:稳,但是刚安装好过于毛胚,需要花大量时间配置,配好后爽。
  • Fedora:软件包新,功能强大,自带管理页面,但资源占用比 Debian 高一些,需要手动关 SE Linux。
  • Ubuntu Server:我不推荐,因为 Snap 要开始污染你的 apt 了,有 nvidia 显卡的可以选,驱动安装方便。
  • Archlinux:软件包丰富,现在基本上也不会滚挂了。安装复杂但也没那么难。维护麻烦,要定期更新。
  • NixOS:个人认为最适合做服务器的 Linux 系统,软件维护、回退、环境复现都完爆上面几个。但是上手门槛过高,应该会长期处于邪教状态。

我就折衷选了 Debian 13,上班了真没多少时间折腾 NixOS 咯。

系统配置

系统装好后,会有两个用户 root 和你自己创建的用户,这里假设为 admin。刚装好的毛胚连 sudo 都没有,因此要先用 root 用户进行配置。

换源

先清空 sources.list:echo > /etc/apt/sources.list.

然后 vi /etc/apt/sources.list.d/debian13.sources,粘贴下面的内容

# 默认注释了源码仓库,如有需要可自行取消注释
deb http://mirrors.ustc.edu.cn/debian trixie main contrib non-free non-free-firmware
# deb-src http://mirrors.ustc.edu.cn/debian trixie main contrib non-free non-free-firmware
deb http://mirrors.ustc.edu.cn/debian trixie-updates main contrib non-free non-free-firmware
# deb-src http://mirrors.ustc.edu.cn/debian trixie-updates main contrib non-free non-free-firmware

# backports 软件源,请按需启用
# deb http://mirrors.ustc.edu.cn/debian trixie-backports main contrib non-free non-free-firmware
# deb-src http://mirrors.ustc.edu.cn/debian trixie-backports main contrib non-free non-free-firmware

apt update; apt upgrade -y 升级一下软件包和内核。

安装必备软件

apt install neovim sudo zsh git

visudo 添加 admin 用户的 root 权限。NOPASSWD 参数表示不用输密码就能用 root 权限,新手一定不要添加该参数。

# User privilege specification
root    ALL=(ALL:ALL) ALL
admin ALL=(ALL:ALL) NOPASSWD: ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

Clash

本方案将 clash 作为 systemd 服务进行自启动,配合 Zsh 配置中的 proxy_on、proxy_off函数来进行使用。

Clash-Premium

下载 clashpremium-nightly-linux-amd64.tar.gz 文件并上传到服务器。使用 root 用户登录到服务器(所有涉及到服务的操作最好都用 root 用户)。

sudo su
mkdir /opt/clash/
mv clashpremium-nightly-linux-amd64.tar.gz /opt/clash/
cd /opt/clash/
tar -zxvf clashpremium-nightly-linux-amd64.tar.gz
chmod +x CrashCore

会解压出一个/opt/clash/CrashCore文件。

wget -O config.yaml "https://0b3....b/lin...k/gVLd?cla...sh=3"

拉取自己的配置文件,放置到 /opt/clash/,此时应该有以下文件:

❯ cd /opt/clash
❯ ls
.  ..  config.yaml  CrashCore

通过命令 /opt/clash/CrashCore -d /opt/clash/ 可以启动。

vim /etc/systemd/system/clash.service vim 一个 systemd service,填入以下内容,如果路径跟我不一样要记得更改。

[Unit]
Description=Clash Meta Core Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/clash
ExecStart=/opt/clash/CrashCore -d /opt/clash
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

然后添加自启动:

systemctl daemon-reload
systemctl enable --now clash

通过 systemctl status clash 可以查看服务状态。

❯ systemctl status clash
● clash.service - Clash Meta Core Service
     Loaded: loaded (/etc/systemd/system/clash.service; enabled; preset: enabled)
     Active: active (running) since Tue 2025-10-14 08:27:39 CST; 2h 40min ago
 Invocation: fc105af99f394b7fadb5d0a5d01fa3da
   Main PID: 897 (CrashCore)
      Tasks: 8 (limit: 18716)
     Memory: 31.8M (peak: 32.2M)
        CPU: 3.984s
     CGroup: /system.slice/clash.service
             └─897 /opt/clash/CrashCore -d /opt/clash

Warning: some journal files were not opened due to insufficient permissions.

通过 proxy_on、proxy_off 可以在终端中启用和关闭。

Zsh

我不用 oh-my-zsh 这类插件,而是自行配置。首先使用普通用户登入(例如 admin),拉取功能插件,记得先 proxy_on 解决网络连接问题。

# 自动补全
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/plugins/zsh-autosuggestions

# 语法高亮
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting ~/.zsh/plugins/zsh-syntax-highlighting

# 这个插件我也没弄明白是干嘛的,可选。。。。
git clone --depth=1 https://github.com/zsh-users/zsh-completions ~/.zsh/plugins/zsh-completions

# p10k 主题
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/.zsh/plugins/powerlevel10k

将 zsh 的插件统一放置在 ~/.zsh/plugins/ 下,这一步可以顺便把访问终端的字体更新一下,推荐使用 nerd-fonts-hack 字体作为终端字体。

环境变量存放位置为 ~/.zprofile,配置文件在 ~/.zshrc,主要编写 ~/. zshrc 文件

将以下代码加入 .zshrc 以使用插件

### 常用命令别名 {{{
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
alias ls='ls -a --color=auto'
alias ll='ls -al --color=auto'
alias grep='grep --color=auto'
# alias nvim="nvim -u ~/.config/nvim/init-plugin.lua"
# }}}

### 个性化功能配置 {{{
# 容器相关
pm_stop_all() { podman stop $(podman ps -q); }
pm_list_ct()  { podman ps -a; }
pm_list_net() { podman network ls; }
pm_list_pod() { podman pod ls; }
pm_clean()    { echo "y" | podman system prune -a --volumes; }

# 更新软件
update() { sudo apt update; sudo apt full-upgrade -y; }

# 清理垃圾
clean() { sudo apt clean; sudo apt autoremove -y; pm_clean; }

# 双击 ESC 在命令前插入 sudo
sudo-command-line() {
    [[ -z $BUFFER ]] && zle up-history
    [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
    zle end-of-line                 #光标移动到行末
}
zle -N sudo-command-line
bindkey "\e\e" sudo-command-line
# }}}

### 终端代理 {{{
hostip="127.0.0.1"
# hostip=$(cat /etc/resolv.conf |grep -oP '(?<=nameserver\ ).*')
proxy_on() {
    proxy_status="on"
    export https_proxy="http://${hostip}:7890"
    export http_proxy="http://${hostip}:7890"
    export all_proxy="socks5://${hostip}:7890"
    echo -e "终端代理已开启。"
}

proxy_off(){
    unset http_proxy https_proxy all_proxy
    echo -e "终端代理已关闭。"
    proxy_status="off"
}
# }}}

### 历史纪录相关配置 {{{
# 历史文件路径
export HISTFILE="$HOME/.zsh_history"
# 历史纪录条目数量
export HISTSIZE=200
# 注销后保存的历史纪录条目数量
export SAVEHIST=200
# 以附加的方式写入历史纪录
setopt INC_APPEND_HISTORY
# 如果连续输入的命令相同,历史纪录中只保留一个
setopt HIST_IGNORE_DUPS
# 为历史纪录中的命令添加时间戳
setopt EXTENDED_HISTORY
# 启用 cd 命令的历史纪录,cd -[TAB]进入历史路径
setopt AUTO_PUSHD
# 相同的历史路径只保留一个
setopt PUSHD_IGNORE_DUPS
#  转换时间戳并打印历史命令
hist() {
  # 获取参数:不传则显示全部,传数字则显示最近 N 条
  local lines="${1:-0}"

  awk -F': |:0;' '
    /^: [0-9]+:[0-9]*;/ {
      printf "%s | %s\n", strftime("%Y-%m-%d %H:%M:%S", $2), $3
    }
  ' $HOME/.zsh_history | if [ "$lines" -gt 0 ] 2>/dev/null; then
    tail -n "$lines"
  else
    cat
  fi
}
# }}}

### 杂项 {{{
# 编辑器
export EDITOR=vim
export VISUAL=vim
# 禁用 core dumps
limit coredumpsize 0
# 以下字符视为单词的一部分
WORDCHARS='*?_-[]~=&;!#$%^(){}<>'
# }}}

p10k 在首次进入时需要进行配置,按照提示进行即可,配置之后,会在 .zshrc 行首和行尾分别添加

if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

以及

# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

需要把上边 if 那三句代码移动到 4 个 source 的下面,否则每次启动终端都会报错。

Neovim(可选)

虽然说这台机器只是一个网页服务器,但有一个好看好用的瑞士军刀也不是不行。

首先确保安装好 neovim。

教程:LazyVim 让我删掉了以前的 config

容器

docker hub 现在几乎无法通过软路由之外的方式解决网络问题,所以使用 podman 进行代替。

sudo apt install podman podman-compose

在 pull/up -d 之前先用 proxy_on 开启代理即可。

podman 相比 docker 缺少了守护进程,这导致 podman 跑起来的容器在终端用户退出之后被 systemd 清理机制杀掉。因此需要运行 podman 容器的用户来执行

loginctl enable-linger $USER

启用后,用户级 systemd 实例会在系统启动时即常驻,即使用户注销,容器进程也不会被清理。这也比较符合服务器的基本使用习惯。

DDNS 与反向代理

原本想用 lucky 来进行 DDNS 和反向代理,毕竟这个一站式管理工具确实很方便。但仔细想了想,还是拥抱开源算了,毕竟有 AI 之后写配置没有以前麻烦。

ddns-go

下载地址,选择 ddns-go_XXXX_linux_x86_64.tar.gz

jeessy2/ddns-go

将文件上传到 /opt/ddns-go,这个步骤就不细说了。

登录到服务器系统,切换到 root 用户,cd /opt/clash/,解压缩 tar- zxvf ddns-go_XXXX_linux_x86_64.tar.gz 后出现以下程序,该程序默认拥有可执行权限。

❯ ls
.  ..  ddns-go

安装 ddns-go 服务:/opt/ddns-go/ddns-go -s install,最好使用绝对路径。

在网页中访问 ip:9876 就可以进行 ddns-go 配置页面。

顺带说一下 IPv6 解析问题,推荐关闭有状态 DHCPv6,仅采用 SLAAC(无状态 DHCPv6)模式,安全性高一些,实在需要固定后缀的话,通过 EUI-64 方式进行固定。

SLAAC + EUI-64 + 运营商动态前缀,没有被扫到的可能性。

Nginx 反向代理

现在反向代理门槛比以前低很多了,搭配 certbot,连 SSL 证书都不需要操心。首先登录到 root 用户。

apt install certbot nginx python3-certbot-nginx

创建反向代理配置,这里用 ddns-go 做示例,ddns-go 默认禁止从公网访问,配置反向代理后,实际访问者是本机,就可以从公网访问了。

cd /etc/nginx/sites-available 然后创建一个 ddns-go 文件,输入以下内容:

❯ cat sites-available/ddns-go
# 默认 server,强制跳 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name youdomain;
    return 301 https://$host$request_uri;
}

# HTTPS 反代
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name youdomain;

    # SSL 证书路径(certbot 自动生成)
    ssl_certificate     /etc/letsencrypt/live/youdomain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/youdomain/privkey.pem;

    # 安全强化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 反代到 ddns-go
    location / {
        proxy_pass http://127.0.0.1:9876;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

如果使用 certbot 生成证书的话,就不用改这两行

    # SSL 证书路径(certbot 自动生成)
    ssl_certificate     /etc/letsencrypt/live/youdomain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/youdomain/privkey.pem;

如果公网是 IPv6,则一定要添加 IPv6 监听:

    listen [::]:80;

    listen [::]:443 ssl http2;

当然你也可以使用自己的证书。

那么如何使用 certbot 自动生成证书呢?

首先确保自己安装了 certbot python3-certbot-nginx,打开代理 proxy_on,使用

sudo certbot certonly --nginx -d "yourdomain"

输入你的邮箱,然后选择 Y、N,回车就完事了,失败的话就是网络有问题,注意修复。

防火墙

虽然之前有说 IPv6 很安全,但一旦别人得知你的域名,那么不需要扫描也可以得到你的 IPv6 地址,因此防火墙还是要做好的。

使用普通用户登入,sudo apt install ufw 安装防火墙

❯ sudo apt install ufw       # 安装(通常已预装)
将要安装:
  ufw
......
Creating config file /etc/ufw/after6.rules with new version
Created symlink '/etc/systemd/system/multi-user.target.wants/ufw.service' → '/usr/lib/systemd/system/ufw.service'.
正在处理用于 man-db (2.13.1-1) 的触发器 ...
sudo ufw status verbose      # 查看状态

安装后默认不会启用,我们先配置再启用,先把最重要的几个启用了,免得登陆不上。

首先是出入站行为设置:

# 兜底规则,拒绝入站,允许出站
sudo ufw default deny incoming
sudo ufw default allow outgoing

然后开放几个重要的应用层。

# 允许 SSH,HTTP,HTTPS
❯
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443

尤其是 ssh 一定要开放,输入 sudo ufw enable 激活防火墙,选择 y 即可。

❯ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

可以通过以下命令查看端口开放状态。

❯ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 80                         ALLOW IN    Anywhere
[ 3] 443                        ALLOW IN    Anywhere
[ 4] 22/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 5] 80 (v6)                    ALLOW IN    Anywhere (v6)
[ 6] 443 (v6)                   ALLOW IN    Anywhere (v6)

ufw 适合快速上手的常用操作手册:

  • 限制 IP 访问
sudo ufw allow from 192.168.1.100 to any port 22
  • 拒绝某个 IP
sudo ufw deny from 203.0.113.5
  • 删除规则
sudo ufw delete allow 8080/tcp
# 或按编号删除
sudo ufw status numbered
sudo ufw delete 3

注意,通过编号删除后,剩下的规则编号可能会发生变化,一定要一条一条删。

  • 关闭与重置
sudo ufw disable      # 关闭防火墙
sudo ufw reset        # 清除所有规则(谨慎)
  • 规则检查

使用 sudo ufw status verbose 随时检查规则是否生效。

❯ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80                         ALLOW IN    Anywhere
443                        ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
80 (v6)                    ALLOW IN    Anywhere (v6)
443 (v6)                   ALLOW IN    Anywhere (v6)