systemd 单元配置实战:常驻服务、定时任务,以及跑在容器里的命令

一个后台程序要一直跑着,挂了自动拉起来;另一个程序要每 10 分钟跑一次,跑完就退出。这两件事在 Linux 上都归 systemd 管,前者写成 .service,后者要 .service + .timer 一对。 本文把这两种单元的每个字段拆开讲清楚,说明为什么定时任务用 timer 比 crontab 更合适,以及命令实际跑在 Docker 容器里时最容易踩的那个坑。 一、先分清楚 service 和 timer 很多人第一次配 timer 时会困惑:「定时任务为什么要写两个文件?」 因为这是两件事: .service 回答「这个程序该怎么跑」——跑什么命令、用哪个用户、挂了要不要重启、超时多久算失败 .timer 回答「什么时候去启动它」——每 10 分钟、每天凌晨 3 点、开机 5 分钟后 .service 是名词,.timer 是闹钟。闹钟响了就去按一下那个 service 的启动按钮,至于按下去之后发生什么,是 service 自己的事。 所以常驻型的程序只要一个 .service(它自己不停,不需要闹钟),周期型的要一对,而且两个文件必须同名:myapp-sync.service 配 myapp-sync.timer——timer 靠文件名找到对应的 service,改错一个字母就是「闹钟响了但没有任何反应」。 两种文件都放在 /etc/systemd/system/。 二、常驻型:Type=simple + Restart=always 先看一个真实的例子。一个 Python 写的后台 worker,从队列里领任务、执行、再领下一个,永远不退出: [Unit] Description=myapp 后台 worker After=network-online.target docker.service Wants=network-online.target [Service] Type=simple Environment=TZ=Asia/Shanghai WorkingDirectory=/var/www/myapp ExecStart=/var/www/myapp/.venv/bin/python -m worker Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target 逐段拆开。 ...

September 2, 2026 · 5 min · 翼橙

SSH 隧道详解:本地转发、远程转发与动态转发

数据库端口不想对公网开,但本地又要用图形工具连;内网的服务想临时给外面看一眼;出差时想让所有流量走回自己的服务器——这几件事都不用装额外软件,SSH 自带的端口转发就能做。 本文讲清楚三种转发方式的区别、参数怎么记、以及那些一看就懂但一用就错的地方。 一、先理解一件事:转发的是「连接」,不是「端口」 很多教程一上来就给命令,看完照抄能跑,但换个场景就不会改了。原因是没想清楚数据往哪边流。 SSH 转发的本质是:在一台机器上开个监听端口,谁连上来,就把这条连接通过已建立的 SSH 加密通道,转到另一端去替他连目标地址。 所以每次写命令,只需要回答三个问题: 在哪台机器上监听?(决定用 -L 还是 -R) 监听哪个端口? 连接最终要送到哪个地址、哪个端口?——从哪一端的视角看? 第三个问题是所有困惑的来源,后面会反复强调。 二、本地转发 -L:把远端的服务搬到本地 这是最常用的一种。典型场景:数据库只监听 127.0.0.1,不对公网开放,但你要用本地的图形工具连它。 ssh -L 13306:127.0.0.1:3306 root@db-server 参数怎么读 -L 13306:127.0.0.1:3306 └─┬─┘ └────┬────┘ └┬─┘ │ │ └─ 目标端口 │ └─ 目标地址(★ 从 db-server 的视角看 ★) └─ 在你本机监听的端口 中间那个地址是站在服务器上看的,这是最容易搞错的地方。127.0.0.1 在这里指的不是你的电脑,而是 db-server 自己。 数据怎么走 你的电脑 db-server mysql -h 127.0.0.1 -P 13306 │ └─→ 本机 13306(ssh 在监听) │ │ ═══ SSH 加密隧道(走 22 端口)═══ │ └─→ 127.0.0.1:3306(MySQL) 关键在于:MySQL 看到的连接来自它自己的 127.0.0.1,因为最后一跳是 db-server 内部发起的。所以数据库完全不用对外开放端口,防火墙只需要放行 22。 ...

September 2, 2026 · 3 min · 翼橙

Ubuntu 部署 Zsh + Oh My Zsh:自动补全、语法高亮与终端快捷键速查

在 Linux 工业级运维和日常高效开发中,终端(Terminal)是我们交互最频繁的工具。默认的 Bash 虽然稳定,但在自动补全、语法高亮和历史命令检索等日常痛点上显得力不从心。 通过升级至 Zsh,配合 Oh My Zsh 生态以及核心的双核插件(zsh-autosuggestions 与 zsh-syntax-highlighting),你将在光标后获得灰色的历史命令暗影提示,只需按右方向键或 Ctrl + E 即可一键补全,效率瞬间拉满。 本教程将提供一份详尽的、面向生产环境与本地开发环境的部署指南,并在文章后半部分梳理了 Bash/Zsh 通用的终端输入快捷键,建议收藏以备速查。 一、部署 Zsh + Oh My Zsh 第一步:安装 zsh 基础环境并切换默认 Shell Ubuntu 纯净系统默认使用的是 Bash,我们需要先安装 Zsh 以及克隆插件所需的 git 和下载工具 curl。 # 1. 更新包管理器并安装 zsh、git 和 curl sudo apt update && sudo apt install zsh git curl -y # 2. 将当前用户的默认 Shell 切换为 zsh chsh -s $(which zsh) 💡 重要说明: 执行完 chsh 切换默认 Shell 后,当前终端会话并不会立刻改变。你需要完全关闭当前终端连接(注销账户、重新打开 Terminal 窗口,或者断开当前的 SSH 连接后重新登入)。 重新进入终端后,系统会检测到首次使用 Zsh 并弹出初始化菜单(通常有 0、1、2 等选项)。直接输入 0 创建一个空白的 .zshrc 配置文件即可,因为后续步骤中 Oh My Zsh 会自动为我们生成并覆盖该配置。 可以通过命令 echo $SHELL 来验证当前默认 Shell,若输出类似 /bin/zsh 或 /usr/bin/zsh,则说明切换成功。 第二步:一键安装 Oh My Zsh 骨架 Oh My Zsh 是一个社区驱动的、用于管理 Zsh 配置的开箱即用框架。利用官方提供的标准安装脚本,我们可以将核心生态直接拉取到当前用户的家目录下: ...

June 3, 2026 · 3 min · 翼橙

update-alternatives 使用笔记:多版本共存的软链接管理器

在 Linux 系统中,update-alternatives 是一种用于管理命令软链接的工具,适合管理多个版本共存的程序,例如不同版本的 PHP、Java、GCC、Python 等。通过它可以灵活控制哪个版本被调用、切换默认版本、统一管理系统路径下的可执行程序。 一、基本原理 Linux 中大多数命令其实都是 /usr/bin/xxx 的可执行文件,这些文件很多是软链接: ls -l /usr/bin/php # 可能指向 -> /etc/alternatives/php # 再指向 -> /usr/bin/php8.2 update-alternatives 就是负责管理 /etc/alternatives/ 中的这些链接,并允许你注册多个候选路径、设置优先级、手动切换或自动切换。 二、常用参数 参数 说明 --install 添加一个新候选版本 --remove 移除某个候选路径 --config 手动选择当前使用哪个版本 --set 直接设置当前使用路径 --display / --query 查看当前配置状态 --auto 恢复为优先级自动选择模式 –install 的四个位置参数 update-alternatives --install 是添加“候选版本”的关键命令,它的完整语法格式如下: sudo update-alternatives --install <链接路径> <名字> <实际可执行路径> <优先级> 参数位置 含义 示例值 说明 链接路径 创建的统一入口点 /usr/bin/php 这是用户最终执行命令时调用的路径 名字 系统识别用的名称 php 是“组名”,管理同类版本的别名 实际路径 程序的真实可执行文件路径 /usr/bin/php7.4 要加入的某个版本路径 优先级 一个整数 74 数值越大,优先级越高,自动模式下会选择它 实例 你系统中已经安装了 PHP 7.4 和 PHP 8.2,可以这样添加: ...

July 23, 2025 · 2 min · 翼橙

配置 Docker 国内镜像加速:daemon.json 写法、生效验证与排错

从国内直接拉 Docker Hub 的镜像,常见的表现是速度只有几十 KB/s,或者干脆卡在 Retrying in 5 seconds 反复重试。解决办法是给 Docker 配一组镜像加速源—— 它们是 Docker Hub 的只读缓存,你 docker pull 时 Docker 先去这些地址找, 找不到才回源。 一、写入 daemon.json /etc/docker/daemon.json 是 Docker 守护进程的配置文件,registry-mirrors 就是加速源列表。配多个是为了容错:某个源挂了会自动试下一个。 执行以下命令: sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<EOF { "registry-mirrors": [ "https://docker.1panel.live", "https://docker.1ms.run", "https://dytt.online", "https://docker-0.unsee.tech", "https://lispy.org", "https://docker.xiaogenban1993.com", "https://666860.xyz", "https://hub.rat.dev", "https://docker.m.daocloud.io", "https://demo.52013120.xyz", "https://proxy.vvvv.ee" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker 这些镜像源来自 GitHub 项目 dongyubin/DockerHub, 那里有一份持续更新的可用列表。 ...

June 27, 2025 · 1 min · 翼橙

从零搭建邮件服务器接收验证码

本文适用于:需要自建域名邮箱来注册平台账号、接收验证码的场景。全程命令行, 不用写 Python 脚本也能收码。 只讲收信。 对外发信要额外处理 rDNS、DKIM、DMARC 和 IP 信誉, 自建服务器发出去的信大概率进垃圾箱,那是另一件事。 一、背景说明 很多平台注册账号时会要求填写邮箱地址并接收验证码。为了批量注册或控制邮箱来源,一些用户希望自建域名邮箱系统,从而: 自己控制域名和邮箱地址 本地接收邮件,免费无限用 配合脚本自动抽取验证码 二、工作环境准备 1. 需要的条件 项目 说明 一台 VPS Ubuntu 20.04+,25 端口必须能入站。多数云厂商默认封 25,要向主机商申请解封 一个可配置 DNS 的域名 如 mail.example.com 2. 安装必要软件 apt update apt install postfix dovecot-core dovecot-imapd -y postfix = SMTP 邮件服务器,用于接收邮件 dovecot = IMAP 邮箱读取服务器,允许脚本/网页读邮件 三、配置 DNS 记录 到域名控制面板(如 Cloudflare、阿里云、Namecheap)添加以下 DNS 记录: 类型 主机记录 值 A mail VPS IP MX @ mail.example.com (10) TXT @ v=spf1 mx ~all 说明:MX 是接收邮件的域名服务器,SPF 是为了防止邮件被伪造,非必但建议配置 ...

May 27, 2025 · 2 min · 翼橙