Automatic upgrades with CRON

Automatic upgrades with CRON

Keeping your Linux system updated is important for security, stability, and performance. Updates fix security issues, improve speed, and prevent software conflicts. They also add new features and ensure everything runs smoothly. Regular updates keep your system safe and reliable.

On Proxmox, it's important to keep both your host and each LXC container up to date. However, managing updates manually can quickly become tedious. In this article, I'll show you how to automate these tasks, making maintenance easier and more efficient.

Upgrade host packages

The first step in maintaining your Proxmox system is keeping the host's packages up to date. The basic command to do this is:

apt update && apt dist-upgrade -y

This command first updates the package list and then upgrades any packages with available new versions. We use dist-upgrade instead of upgrade because it handles dependencies more intelligently, ensuring that required package changes are applied. The -y option automatically confirms the updates, so you don’t have to approve them manually.

Now, we want to automate this command to run on a schedule. We need to define how often it should run and at what time. I've chosen to perform updates weekly to maintain system security and stability. To ensure high availability, the updates will run every Monday at 1:00 AM.

So, I create a cron task. For that I edit the file /etc/crontab and I add the line:

0 1 * * 1  root  apt update && apt dist-upgrade -y >> /var/log/apt_upgrade.log 2>&1

The 0 1 * * 1 schedule follows the mm hh dd MMM WWW format, where each value defines a specific time unit. The file itself contains comments explaining how it works.

  • 0 1 means the task runs at 1:00 AM.
  • The two asterisks (* *) mean it runs every day of the month and every month, regardless of the date.
  • The final 1 specifies the day of the week—in this case, Monday.

This setup ensures the update process runs automatically every Monday at 1:00 AM.

The next parameter specifies the user who will execute the command — here, it is root.

Next, we define the command itself and direct its output to a log file for tracking. To capture both standard output and errors in the same log file, we use 2>&1. This ensures that any issues encountered during execution are also logged. Keeping logs isn’t necessarily useful for everyday monitoring, but it provides a way to verify that the task is being executed as expected.

The edited file should be like this:

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6    * * 7   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6    1 * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
0  1    * * 1   root    apt update && apt dist-upgrade -y >> /var/log/apt_upgrade.log 2>&1

#

Once you have modified your file, you need to restart the cron daemon with this command:

systemctl restart cron

Now that the packages on the Proxmox host will stay up to date automatically, we can move on to the next step: managing updates for LXC containers.

Upgrade LXC packages

One solution is to apply the same approach as we did for the host—adding a cron job inside each LXC container to handle updates. This method works, but it has several drawbacks:

  • It takes time to set up on every LXC.
  • It lacks scalability—each time we create a new LXC, we must manually add the script again.
  • Any changes, such as modifying the update frequency, require editing the script inside each container one by one.

To avoid these issues, a better approach is to create a single script on the Proxmox host that runs the update command inside all LXC containers. This makes management easier and more efficient.

To automate updates for all LXC containers, start by creating a script file:

nano /usr/local/bin/update_lxc.sh

In this file, add the following lines:

#!/bin/bash

# List all LXC containers
containers=$(lxc-ls --running)

for container in $containers; do
    # Execute the update command inside each LXC
    lxc-attach -n "$container" -- bash -c "apt update && apt dist-upgrade -y"
done

If you want to log the update process for verification, use the following line instead:

lxc-attach -n "$container" -- bash -c "apt update && apt dist-upgrade -y >> /var/log/apt_upgrade.log 2>&1"

Once the script is created, make it executable by running:

chmod +x /usr/local/bin/update_lxc.sh

Finally, test the script to ensure it works as expected:

/usr/local/bin/update_lxc.sh

The last step is to automate the script execution. To do this, create a new cron task.

Open the crontab file:

nano /etc/crontab

Add the following line at the end of the file:

15 1 * * 1 root /usr/local/bin/update_lxc.sh

With this schedule, the updates will run every Monday at 1:15 AM, right after the host update. You can adjust the frequency or timing based on your needs. Additionally, you can choose whether to log the operation.

To apply the changes, restart the cron service:

systemctl restart cron

Now, all the packages on your Proxmox server, including both the host and LXC containers, will be automatically updated every week! This ensures your system stays secure, stable, and up to date with minimal effort.

Update Docker Images

Our script works well, but we can improve it further. The goal is to enhance it so that, in addition to updating packages, it also pulls the latest Docker images and restarts containers inside the Docker LXC.

Since I use Docker Compose, this process is straightforward. I only need to check if the LXC currently being updated is my Docker LXC and adjust the commands accordingly.

#!/bin/bash

# List all LXC containers
containers=$(lxc-ls --running)

for container in $containers; do
    # Execute the update command inside each LXC
    lxc-attach -n "$container" -- bash -c "apt update && apt dist-upgrade -y"
    
    if [ "$container" == "110" ]; then
        # Execute specific commands if it is the Docker LXC
        lxc-attach -n "$container" -- bash -c "cd /docker && docker compose pull && docker compose up -d"
    fi
done

All commands inside the Docker LXC must be executed in a single line. Running lxc-attach again would create a new session, causing the working directory to reset. By combining the commands, we ensure that the script correctly updates the Docker containers.

Now you know how to keep everything up to date, from your LXC packages to your Docker containers. This automation saves time and ensures your system runs smoothly without manual intervention.

Credit

cron - Wikipedia
Docker Compose
Learn how to use Docker Compose to define and run multi-container applications with this detailed introduction to the tool.