# =============================================================================
#  CloudPanel — log rotation
# -----------------------------------------------------------------------------
#  INSTALL PATH
#      /etc/logrotate.d/cloudpanel        owner root:root, mode 0644
#      Name it exactly "cloudpanel": logrotate ignores any file in
#      /etc/logrotate.d whose name matches its taboo list (*.bak, *.dpkg-dist,
#      *.rpmsave, *.disabled, *~ …), so a stray "cloudpanel.bak" left behind by
#      an edit is silently not applied.  logrotate also refuses to read a
#      configuration file that is group or world writable.
#
#  TEST BEFORE TRUSTING IT
#      logrotate -d /etc/logrotate.d/cloudpanel     # dry run, prints decisions
#      logrotate -f /etc/logrotate.d/cloudpanel     # force one rotation now
#      cat /var/lib/logrotate/status | grep -i cloudpanel
#
#  WHY TWO STRATEGIES
#      * Gunicorn reopens its log files on SIGUSR1, so its logs are rotated the
#        clean way: rename, then signal, then write to a fresh file.
#      * The daemon, Celery and the per-site OLS logs are rotated with
#        `copytruncate`, because those writers hold the file descriptor open
#        and there is no safe signal to make them reopen.  copytruncate can lose
#        the few lines written between the copy and the truncate — acceptable
#        for these, never acceptable for the audit log (see below).
# =============================================================================


# -----------------------------------------------------------------------------
#  Panel application logs (Django, Gunicorn, installer, upgrade).
#  The postrotate SIGUSR1 is what makes this rotation lossless.
# -----------------------------------------------------------------------------
/usr/local/CloudPanel/logs/gunicorn_access.log
/usr/local/CloudPanel/logs/gunicorn_error.log
/usr/local/CloudPanel/logs/cloudpanel.log
/usr/local/CloudPanel/logs/django.log
/usr/local/CloudPanel/logs/install.log
/usr/local/CloudPanel/logs/upgrade.log
{
    su cloudpanel cloudpanel
    daily
    rotate 30
    size 50M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    create 0640 cloudpanel cloudpanel
    sharedscripts
    postrotate
        # Gunicorn's master reopens every log file on SIGUSR1 (SIGHUP would
        # restart the workers instead, dropping in-flight panel requests).
        # `|| true` so that a stopped panel never fails the whole logrotate run.
        /usr/bin/systemctl kill --signal=SIGUSR1 cloudpanel.service 2>/dev/null || true
    endscript
}

# -----------------------------------------------------------------------------
#  Privileged daemon: operational log.
# -----------------------------------------------------------------------------
/usr/local/CloudPanel/logs/daemon.log
{
    su root root
    daily
    rotate 30
    size 50M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    # copytruncate: the daemon holds this fd open for the life of the process.
    # (No `create` here — with copytruncate the original file stays in place,
    # so a create stanza would be silently ignored.)
    copytruncate
}

# -----------------------------------------------------------------------------
#  Privileged daemon: AUDIT log — every privileged command the panel asked for.
#
#  This is forensic evidence.  Different rules from everything else:
#    * kept for a full year, not 30 days;
#    * never truncated in place while the daemon writes (the daemon opens it
#      with O_APPEND per record, so a plain rename-and-create is safe and
#      loses nothing);
#    * mode 0600 root:root — not even the panel user may read it back.
#  Ship it off the box if you care about an attacker with root deleting it.
# -----------------------------------------------------------------------------
/usr/local/CloudPanel/logs/daemon_audit.log
{
    su root root
    daily
    rotate 365
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    create 0600 root root
    # No copytruncate and no postrotate signal: the audit writer reopens the
    # path for every record, so it follows the new file by itself.
}

# -----------------------------------------------------------------------------
#  Celery worker and beat.
# -----------------------------------------------------------------------------
/usr/local/CloudPanel/logs/celery_worker.log
/usr/local/CloudPanel/logs/celery_beat.log
{
    su cloudpanel cloudpanel
    daily
    rotate 14
    size 50M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    # Celery has no "reopen logs" signal; copytruncate is the only safe option.
    copytruncate
}

# -----------------------------------------------------------------------------
#  OpenLiteSpeed logs for the panel vhost itself.
#  OLS also rolls these internally at 20M (see panel-vhost.conf); this stanza
#  exists to compress and expire what OLS leaves behind.
# -----------------------------------------------------------------------------
/usr/local/CloudPanel/logs/ols_panel_access.log
/usr/local/CloudPanel/logs/ols_panel_error.log
{
    su root root
    daily
    rotate 14
    size 100M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    copytruncate
}

# -----------------------------------------------------------------------------
#  Per-website logs: /home/<domain>/logs/*.
#
#  `su root root` is REQUIRED here and is not decoration: /home/<domain>/logs is
#  owned by the customer's system user, and logrotate refuses to rotate inside a
#  directory writable by a non-root user unless the config says which identity
#  to rotate as.  Without it you get
#      "skipping /home/... because parent directory has insecure permissions"
#  and the logs grow until the disk fills.  This is the single most common
#  logrotate failure on a hosting node.
#
#  copytruncate keeps the customer's ownership on the live file (the alternative,
#  `create`, cannot express "whatever user owns this particular site").
#
#  nocreate + copytruncate together also mean a deleted account's log directory
#  simply stops being rotated instead of being recreated as root-owned.
# -----------------------------------------------------------------------------
/home/*/logs/*.access_log
/home/*/logs/*.error_log
/home/*/logs/*.php_error_log
{
    su root root
    daily
    rotate 14
    size 100M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    copytruncate
    nocreate
    # Do not let one enormous site's rotation block the rest of the run.
    sharedscripts
}

# -----------------------------------------------------------------------------
#  Server-wide OpenLiteSpeed logs.
#  OLS reopens its logs on a graceful restart; `lswsctrl restart` is a graceful
#  reload (connections are drained, not dropped), so it is safe from cron.
# -----------------------------------------------------------------------------
/usr/local/lsws/logs/error.log
/usr/local/lsws/logs/access.log
/usr/local/lsws/logs/stderr.log
{
    su root root
    daily
    rotate 14
    size 100M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    copytruncate
}
