logrotate 不支持自由指定归档路径,仅可通过 olddir 将旧日志移至同一文件系统下的已有目录,跨挂载点会报错;如需自定义路径(如远程备份),必须配合 sharedscripts 和 postrotate 脚本搬运。

logrotate 本身不支持自定义归档路径,只能用 olddir
logrotate 没有 “把切割后的日志存到 /backup/logs/” 这种自由指定目标目录的机制。它只允许通过 olddir 参数把旧日志(比如 access.log.1、access.log.2.gz)移到**同一文件系统下的另一个目录**,且该目录必须已存在、权限正确、不能跨挂载点。
例如你想把 Nginx 日志轮转后存到 /var/log/nginx/archive/,得先创建目录并赋权:
sudo mkdir -p /var/log/nginx/archive sudo chown root:root /var/log/nginx/archive sudo chmod 755 /var/log/nginx/archive
然后在 /etc/logrotate.d/nginx 中写:
/var/log/nginx/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 nginx nginx
olddir /var/log/nginx/archive
}-
olddir必须是绝对路径,且不能和日志主路径在同一子路径下(比如不能设成/var/log/nginx,否则会循环移动) - 如果
olddir不在同一个 mount point(比如/var/log是独立挂载的 ext4 分区,而/backup是另一个挂载的 XFS),logrotate 会报错error: cannot move ... across filesystems -
olddir下的文件仍按默认规则命名(access.log.1→access.log.2),不会自动加日期或哈希
想真正自定义归档路径,得靠 postrotate 脚本搬运
当 olddir 不够用(比如要存到 NFS、Ceph 或远程备份目录),就得在轮转完成后手动移动文件。这时必须用 postrotate + endscript,且注意 sharedscripts 的作用范围。
示例:把刚生成的 .gz 文件同步到 /backup/nginx-logs/:
/var/log/nginx/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 644 nginx nginx
sharedscripts
postrotate
# 注意:logrotate 已完成重命名+压缩,最新归档是 *.log.1.gz
find /var/log/nginx/archive/ -name "*.log.[0-9]*.gz" -mtime -1 -exec cp {} /backup/nginx-logs/ \; 2>/dev/null || true
# 或用 rsync 保证原子性
rsync -a --remove-source-files /var/log/nginx/archive/*.log.[0-9]*.gz /backup/nginx-logs/ 2>/dev/null || true
endscript
}- 务必加
sharedscripts,否则每个匹配到的日志文件(如access.log、error.log)都会单独执行一次postrotate,容易重复搬运 -
find ... -mtime -1是为了只搬本次轮转产生的文件,避免历史残留干扰 - 不要在
postrotate里直接mv—— 如果目标目录不可写,会导致 logrotate 认为失败,后续所有配置都跳过
olddir 和 postrotate 混用时的坑
两者可以共存,但行为容易混淆:logrotate 先把旧文件移到 olddir,再执行 postrotate;如果你在脚本里又把它们从 olddir 搬走,那 olddir 就只剩空目录——这本身没问题,但要注意 rotate N 统计的是 olddir 里的文件数,不是最终归档目录里的。
- 比如设了
olddir /tmp/archive+rotate 10,但postrotate把文件全拷走并rm -f /tmp/archive/*,那么下次轮转时 logrotate 会发现/tmp/archive/里只有 0 个旧文件,直接从.1开始编号,导致覆盖风险 - 更稳妥的做法是:只用
postrotate搬运,去掉olddir,让所有归档留在原位置直到搬运完成,再由脚本清理原位置(rm -f /var/log/nginx/*.log.[1-9]*) - 任何涉及磁盘 I/O 的操作(尤其是跨网络搬运)都要加超时和错误忽略(
|| true),否则一个失败就中断整个 logrotate 流程
为什么不能直接改 logrotate.conf 主配置来统一设置归档路径
因为 olddir 是 per-log-path 参数,不能在全局配置里声明。你在 /etc/logrotate.conf 里写 olddir /some/path 是无效的,logrotate 会静默忽略——它只接受在具体日志块(即 /path/to/log { ... } 内)中定义。
所以必须为每个服务单独配,比如:
-
/etc/logrotate.d/nginx里设olddir /var/log/nginx/archive -
/etc/logrotate.d/mysql里设olddir /var/log/mysql/archive - 别指望“一劳永逸”,这是设计使然,也是避免误操作影响全局的保护机制
真正需要集中管理路径时,建议用配置管理工具(Ansible、Puppet)生成这些分散的 /etc/logrotate.d/xxx 文件,而不是手写或硬编码路径。


















