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 逐段拆开。 ...
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。 ...
MySQL 用户最佳实践:按站分离、改密码、改授权、限制 IP
一台服务器上跑着好几个站,图省事全用 root 连库——这是最常见的做法,也是出事时代价最大的做法。本文讲怎么把数据库账号按站拆开、怎么安全地改密码和授权、怎么把账号锁到指定来源 IP,以及几个容易被忽略的配套问题。 文中场景与配置均已脱敏。 一、为什么要按站分离 假设一台机器上跑两个站:一个商城前台,一个用 WordPress 做的收单页。两个站各有各的库。 如果两个站都用 root 连库,那么任何一个站被打穿,攻击者拿到的就是整台机器上所有库的完全控制权——包括另一个站的订单、用户、支付记录。一个不起眼的插件漏洞,赔上的是全部数据。 正确做法是一站一账号,每个账号只授权自己那个库: CREATE USER 'shop_app'@'%' IDENTIFIED BY '强密码'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON `shop`.* TO 'shop_app'@'%'; CREATE USER 'wp_app'@'%' IDENTIFIED BY '另一个强密码'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `wordpress`.* TO 'wp_app'@'%'; FLUSH PRIVILEGES; 这样 WordPress 那个站即使被完全控制,攻击者在数据库层面也只能看到 wordpress 库,商城的数据碰不到。 权限给到什么程度 Web 应用需要的其实就两类: 数据操作:SELECT INSERT UPDATE DELETE——日常读写 结构操作:CREATE DROP INDEX ALTER——迁移(migration)要用 CREATE TEMPORARY TABLES 和 LOCK TABLES 按框架需要给。剩下的一律不给,尤其这几个: 权限 作用 为什么不给 EVENT 数据库定时任务 应用调度一般在系统层(cron / systemd timer),用不上;给了等于让攻击者能植入定时后门 TRIGGER 触发器 业务逻辑写在应用里的项目用不到;给了能悄悄篡改写入的数据 EXECUTE 存储过程 同上 FILE 读写服务器文件 绝对不能给,能直接读 /etc/passwd、写 webshell GRANT OPTION 给别人授权 给了等于账号能自我提权 二、账号分离不等于安全 账号按上面的方式拆开之后,看起来隔离已经做到位了。但如果 WordPress 那个站被一个免登录 RCE 漏洞打穿,情况未必如预期。 ...
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 配置的开箱即用框架。利用官方提供的标准安装脚本,我们可以将核心生态直接拉取到当前用户的家目录下: ...
Linux Commands
常用 Linux 命令速查手册 📚 目录 certbot 配置 HTTPS 查看端口使用情况 查看文件或端口占用 查看系统运行状态 查看系统配置(CPU / 硬盘 / 内存) 下载工具 curl 下载工具 wget 文件查找 find 内容搜索 grep 系统清理命令(释放空间) 1. certbot 配置 HTTPS(以 Nginx 为例) 命令: sudo apt update sudo apt install certbot python3-certbot-nginx -y sudo certbot --nginx -d nice.yichengcode.com 命令说明: 安装 certbot 和 nginx 插件 自动申请并配置 SSL 证书 2. 查看端口使用情况 命令: ss -tulnp 命令说明: -t:显示 TCP 端口 -u:显示 UDP 端口 -l:仅列出监听端口 -n:不解析服务名,显示数字端口 -p:显示使用端口的进程信息 示例: ...
Vim 命令大全速查表
本文整理自 vim cheat sheet 与实际使用经验,覆盖从基本移动、插入、编辑、寄存器、宏、折叠到 diff 模式等常用命令,适合日常参考使用。 基础命令 命令 说明 :h {keyword} 查看帮助文档 :saveas {文件名} 另存为 :close 关闭当前窗口 :terminal 打开终端窗口 vimtutor 启动 Vim 教程 光标移动 命令 说明 h 左移一个字符 j 下移一行 k 上移一行 l 右移一个字符 0 移动到行首 ^ 移动到本行第一个非空字符 $ 移动到行尾 w 跳到下一个单词开头 e 跳到单词末尾 b 跳到上一个单词开头 gg 跳到文件首行 G 跳到文件尾行 H 移动到屏幕顶部 M 移动到屏幕中间 L 移动到屏幕底部 Ctrl+d 向下滚动半屏 Ctrl+u 向上滚动半屏 Ctrl+f 向下滚动一屏 Ctrl+b 向上滚动一屏 % 跳转到匹配的括号 插入模式 命令 说明 i 在光标前插入 I 在行首插入 a 在光标后插入 A 在行尾插入 o 在当前行下方新开一行并插入 O 在当前行上方新开一行并插入 ea 在单词末尾插入 Ctrl+h 删除前一个字符(退格) Ctrl+w 删除前一个单词 Ctrl+u 删除整行插入内容 Ctrl+o 在插入模式下执行一条普通模式命令 编辑文本 命令 说明 r{char} 替换光标所在字符为{char} R 进入替换模式 J 合并下一行到当前行末尾 gJ 合并下一行到当前行末尾,不加空格 cc 修改整行(删除后进入插入模式) cw 修改从光标到单词末尾 ciw 修改光标所在的整个单词 S 整行替换(等同于 cc) s 删除光标所在字符并进入插入模式 xp 交换光标所在字符与下一字符 u 撤销 U 撤销整行修改 . 重复上一次修改命令 可视化模式与选择 命令 说明 v 进入字符可视模式 V 进入行可视模式 Ctrl+v 进入块可视模式 ab 选择一个块(包括空格) ib 选择一个块(不包括空格) at 选择一个标签块(包括标签) it 选择一个标签块(不包括标签) 剪切、复制、粘贴 命令 说明 yy 复制当前行 dd 删除当前行(剪切) p 粘贴到光标后 P 粘贴到光标前 gp 粘贴后光标停留在文本末尾 diw 删除光标所在单词 yaw 复制光标所在单词(包括空格) daw 删除光标所在单词(包括空格) :d 删除当前行 :.,$d 删除从当前行到文件末尾 :g/{pattern}/d 删除所有匹配模式的行 寄存器 Vim 中的寄存器用于存储文本,常用寄存器如下: ...
SQLite 与 MySQL 导入导出速查:整库、单表与 CSV
在开发和运维中,经常需要在 SQLite 和 MySQL 之间导入导出数据。本篇总结这两个数据库系统的常用导入导出命令,涵盖整库和单表操作,适用于备份、迁移和初始化场景。 一、SQLite3 命令详解 导出整个数据库为 SQL 文件 sqlite3 data.db .dump > backup.sql data.db 是数据库文件名; .dump 会导出数据库结构 + 全部数据; 生成的 backup.sql 可用 .read 或 < 命令导入。 导出单个表为 SQL 文件 sqlite3 data.db ".dump users" > users.sql 只导出 users 表的数据和结构。 导入 SQL 文件到 SQLite 数据库 sqlite3 data.db < backup.sql 或者交互模式下: sqlite3 data.db sqlite> .read backup.sql 导出为 CSV 文件 sqlite3 data.db sqlite> .headers on sqlite> .mode csv sqlite> .output users.csv sqlite> SELECT * FROM users; 说明: ...
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,可以这样添加: ...
MongoDB 用户管理详解:admin 用户 vs 数据库用户
在 MongoDB 中,用户建在哪个库决定了它的作用范围和管理方式,这一点和 MySQL 很不一样,也是新手最容易绕进去的地方。本文讲清楚两种用户的区别、各自的使用场景、 完整的管理操作,以及连接时那个必须写对的 authSource。 零、先确认认证是开着的 MongoDB 默认不开认证。 没开的时候,你建的用户一个都不生效——任何人连上来 都是完全权限,db.createUser() 只是往集合里写了几行数据而已。 编辑 /etc/mongod.conf: security: authorization: enabled 改完重启,之后所有操作都需要认证: sudo systemctl restart mongod 顺序很重要:先在没开认证的状态下建好第一个管理员账号,再打开认证重启。 反过来的话,认证开着但一个用户都没有,你就把自己关在门外了 (只能用 --noauth 重启一次救回来)。 一、两种类型的用户 1. admin 数据库创建的用户(全局用户) 这种用户是在 admin 数据库中创建的,可以访问多个数据库,并对多个数据库赋予不同权限。 use admin db.createUser({ user: "adminUser", pwd: "secure123", roles: [ { role: "readWrite", db: "sales" }, { role: "read", db: "analytics" } ] }) 特点 用户信息存储在 admin 库; 可以管理和访问多个数据库; 适合平台管理员、系统服务等集中权限场景。 使用场景 运维或 DevOps 脚本; 应用需要访问多个数据库; 多库统一管理权限。 2. 普通数据库创建的用户(局部用户) 这种用户只能在某一个数据库中创建,默认仅能访问该数据库。 use appdb db.createUser({ user: "appUser", pwd: "pass123", roles: [ { role: "readWrite", db: "appdb" } ] }) 特点 用户信息只存在于当前库; 默认只能访问当前数据库; 隔离性好,更安全。 使用场景 Web 应用访问自己的数据; 每个业务数据库独立授权; 多租户系统中的租户隔离。 二、常见用户管理操作 创建用户 db.createUser({ user: "user1", pwd: "123456", roles: [ { role: "readWrite", db: "mydb" } ] }) 修改用户密码 db.updateUser("user1", { pwd: "newpass" }) 要在用户所属数据库执行。 ...
配置 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, 那里有一份持续更新的可用列表。 ...