A cron expression is five fields separated by spaces, read left to right: minute, hour, day of month, month, day of week. 0 5 * * * means "at minute 0 of hour 5, every day" - five in the morning. */15 * * * * means "every fifteenth minute, of every hour, every day". That is ninety percent of it, and you can stop reading here if all you needed was the nightly restart.
The other ten percent is where people lose a weekend: the day-of-month and day-of-week fields do not behave the way you expect when you use both, */7 does not do what it looks like, the timezone is not the one you are sitting in, and a task with a sixty-second delay after a backup does not wait for the backup to finish. This post covers the syntax properly and then the handful of schedules actually worth running on a game server.
The five fields#
| Position | Field | Range | Also accepts |
|---|---|---|---|
| 1 | Minute | 0-59 | |
| 2 | Hour | 0-23 | 24-hour clock, no AM/PM |
| 3 | Day of month | 1-31 | |
| 4 | Month | 1-12 | JAN-DEC |
| 5 | Day of week | 0-7 | SUN-SAT; 0 and 7 are both Sunday |
Every field has to be present. There is no field for seconds and no field for the year in the standard five-field form, so the finest resolution you get is one minute. If a scheduler in front of you is asking for six fields, it is either a system crontab in /etc/crontab or /etc/cron.d, where the sixth column is the user to run as, or a Quartz-style parser where the first field is seconds. Those are different formats that look identical at a glance, and pasting an expression from one into the other is a common way to have a job fire sixty times more often than intended.
Names are case-insensitive, so MON, Mon and mon are the same. Ranges of names work in most implementations - MON-FRI is valid - but steps combined with names are not portable, so write 1-5 rather than MON-FRI/2 if you want to be sure.
Four operators, and that is all there is#
- **
*- every value.*** * * * *runs once a minute, forever. It is a fine way to test and a terrible thing to leave in place. - `,` - a list.
0,30 * * * *is on the hour and on the half hour. Lists can hold ranges:0 2,6,14,22 * * *. - `-` - a range, inclusive.
0 9-17 * * *is every hour from 09:00 to 17:00, which is nine runs and not eight. - `/` - a step.
*/15in the minute field is 0, 15, 30, 45. A step applies to whatever is on its left, so0-30/10is 0, 10, 20, 30, and5/10in the minute field means "start at 5 and step by 10 to the end of the range": 5, 15, 25, 35, 45, 55.
Some parsers also accept shorthand nicknames in place of all five fields: @hourly, @daily (also spelled @midnight), @weekly, @monthly, @yearly, and @reboot. They are convenient in a Linux crontab and unreliable in panel fields, many of which want five real fields. Write the expression out; it is five characters longer and it works everywhere.
There is no operator for "the last day of the month", "the first Thursday" or "every other week". Quartz-style parsers add L, W and # for some of that, standard cron does not, and a panel field is usually standard. The workaround is below.
Worked examples#
| Expression | When it fires |
|---|---|
0 5 * * * | 05:00 every day |
45 4 * * * | 04:45 every day |
*/15 * * * * | Every 15 minutes |
0 */6 * * * | 00:00, 06:00, 12:00, 18:00 |
0 5 * * 1 | 05:00 every Monday |
30 3 * * 0 | 03:30 every Sunday |
0 4 1 * * | 04:00 on the first of the month |
0 4 1,15 * * | 04:00 on the 1st and the 15th |
*/10 9-17 * * 1-5 | Every 10 minutes, 09:00-17:50, weekdays |
0 3 * * 4 | 03:00 every Thursday |
17 2 * * * | 02:17 every day |
That last one is not a typo. Midnight and the top of the hour are when everybody else's backups, log rotations and update checks run, and on shared hardware that is a measurable spike. Picking an odd minute costs nothing and puts your job somewhere quieter.
Read an unfamiliar expression by walking the fields in order and saying the word "of" between them. 30 3 * * 0 is "minute 30, of hour 3, of any day of the month, of any month, on Sunday". The habit catches most mistakes before they run.
The day-of-month and day-of-week trap#
This is the single most misread rule in cron, and it has cost more accidental wipes than any other.
If both the day-of-month field and the day-of-week field are restricted - neither is * - cron runs the job when either matches, not when both do. 0 0 13 * 5 does not mean "midnight on Friday the 13th". It means "midnight on every 13th, and also midnight on every Friday", which is roughly nine times a month rather than once or twice a year.
When one of the two is *, the behaviour is the ordinary one you expect: 0 4 * * 1 is Mondays only, 0 4 15 * * is the 15th only.
So: to say "the first Thursday of the month", you cannot use cron alone. On a Linux box you schedule it every Thursday and guard it in the command:
# 06:00 on the first Thursday of the month. Note the escaped % in a crontab.0 6 * * 4 [ "$(date +\%d)" -le 07 ] && /opt/scripts/wipe.sh >> /var/log/wipe.log 2>&1On a panel with only a cron field and a command list, the honest answer is that you run it manually, or you run it every Thursday and accept it, or you schedule it as a one-off each month. Rust's forced wipe is the usual reason people ask, and wipes without losing your players argues that the announcement matters more than the automation anyway.
Timezones, clock changes and what "midnight" means#
Cron has no timezone of its own. It uses the clock of whatever runs it, which is the machine's local time on a Linux box and the panel's configured timezone in a hosting panel. Neither is necessarily yours. A player in Tbilisi scheduling a restart for 0 5 * * * on hardware in Germany has scheduled it for 08:00 their time in winter and 07:00 in summer, which is well inside the evening for nobody and the middle of the morning for them.
Two things follow.
Find out which clock you are on before you trust a schedule. The quickest test is to set a harmless job - an in-game announcement, or echo on a Linux box - two minutes into the future and watch whether it fires when you expect. Do that once per host; it is faster than reading anybody's documentation.
Avoid the hours the clock moves. In the EU, including the German hardware ours runs on, clocks jump forward at 02:00 local on the last Sunday in March and back at 03:00 local on the last Sunday in October. In the forward jump the hour from 02:00 to 02:59 does not exist, and in the backward jump it happens twice. Different cron implementations resolve that differently - some skip, some run late, some run twice - and none of them is worth arguing with. Schedule maintenance for 04:00 or 05:00 and the question never arises. If you genuinely need exact intervals across a clock change, run the machine and the schedule on UTC.
Schedules worth having on a game server#
Four schedules prevent most of what people open tickets about. The times below assume nobody plays at five in the morning; move the block, keep the order.
| Expression | Task | Why |
|---|---|---|
40 4 * * * | Announce restart in 20 minutes | Nobody loses a build |
50 4 * * * | Save command, then backup | The backup contains the last ten minutes |
0 5 * * * | Restart | Clears leaks, entities, fragmentation |
0 4 * * 0 | Weekly backup, kept and locked | The one you restore from after a bad week |
The save command before the backup is the step people skip. A backup is a copy of files on disk, and most game servers hold the world in memory and write it out on a timer. Backing up without saving first gives you an archive of whatever the world looked like at the last automatic save, which could be twenty-five minutes ago. Send save-all in Minecraft, save in Valheim's console, saveworld or the equivalent in whatever you run, then wait a minute, then take the backup.
Beyond those four, add what your game needs: a database dump on its own schedule if you run one (database backups and restores), a mid-day save and announcement on a building server, a log rotation if the game writes its own logs (logs worth keeping). Scheduled tasks worth having is the short version of this list, and restart schedules that help covers how often is too often.
Ordering tasks, delays, and runs that overlap#
A panel schedule is usually one cron expression with several tasks under it, each with a delay in seconds from the one before. That delay is a wait, not a completion check. This matters more than it sounds:
- Task one: send
save-all. Delay 60 seconds. - Task two: create a backup. Delay 60 seconds.
- Task three: restart the server.
That looks correct and is not. A backup of a 30 GB server takes minutes, and the restart fires sixty seconds after the backup was started, not after it finished. You get a restart in the middle of an archive operation, and an archive that may or may not be usable. The fix is to give the backup room - several minutes of delay, sized to your world - or, better, to put the restart on a separate schedule at 0 5 * * * while the backup runs at 50 4 * * *. Two schedules ten minutes apart are easier to reason about than one schedule with a guessed delay.
On a Linux crontab the equivalent problem is a job that takes longer than its interval. */5 * * * * on a script that sometimes runs for seven minutes gives you two copies fighting over the same files. Wrap it:
*/5 * * * * flock -n /tmp/sync.lock /opt/scripts/sync.sh >> /var/log/sync.log 2>&1flock -n takes the lock or gives up immediately, so the second copy exits instead of running. It is one word and it removes an entire category of incident.
RE:NODE's Schedules tab takes a cron expression and a list of ordered tasks with delays, and a task is one of three things: a console command, a backup, or a power action. Backup slots are on every plan, a backup can be locked so rotation does not delete it, and copies are stored off the machine they protect. That covers the whole table above without a script anywhere. The schedules guide has the click-by-click version, and how the panel works underneath explains why the scheduler lives in the panel rather than inside your server.
Crontab on a Linux box: the extra rules#
If you are on a VDS rather than a panel, cron has a few behaviours that have nothing to do with the expression and break jobs anyway.
- Edit with `crontab -e`, list with `crontab -l`. Editing the spool files by hand is how you end up with a crontab that silently does not load.
- `PATH` is nearly empty. Cron does not read your shell profile.
node,dockerand anything in/usr/local/binmay not be found. Use absolute paths in the command, or setPATH=at the top of the crontab. - `%` means newline. In a crontab command, an unescaped
%is turned into a line break and everything after the first one is fed to the job on standard input.date +%Ybecomesdate +plus a stray line. Escape every one as\%. - Output is mailed, not logged. If there is no mail system, output goes nowhere. Redirect it yourself with
>> /var/log/job.log 2>&1, and setMAILTO=""at the top of the crontab if you want silence. - System crontabs take a user field. Files in
/etc/cron.dand/etc/crontabhave six columns, with the user between the day-of-week field and the command. A five-column line in those files fails.
For anything with a real dependency chain, systemd timers are better than cron: they log to the journal, they can depend on other units, and systemctl list-timers tells you when the next run is - which cron never will. For work triggered by an application rather than the clock, you want a queue instead: background jobs on a small server.
Mistakes that cost people a weekend#
***/7 * * * * is not every seven minutes.** Steps restart at the top of each hour, so it fires at minute 0, 7, 14, 21, 28, 35, 42, 49, 56, and then 0 again four minutes later. Any step that does not divide 60 has a short gap every hour. Use 5, 10, 15, 20 or 30.
**0 0 * * * on a shared machine.** Midnight is the busiest minute of the day on any node. Move it.
Restarting more often than you need to. A restart every six hours on a server that is fine for a week is four interruptions a day bought for nothing. Restart on evidence, not on superstition - why your game server keeps restarting covers telling a leak from normal growth.
A backup schedule nobody has restored from. A backup you have never restored is a hypothesis. Pick a quiet week and test a restore before you need it.
Forgetting the schedule exists. Six months later a job is still emptying a directory that now holds something else. Write the intent in the schedule's name, and read the list of schedules once a season.
FAQ#
What does */15 * * * * mean?
Every fifteenth minute of every hour: 00, 15, 30 and 45 past. The */15 is a step in the minute field; the remaining four stars mean it is not limited to any particular hour, date, month or weekday.
Why is my cron job running twice, or at the wrong time?
The two usual causes are the day-of-month and day-of-week rule - if both fields are set, cron fires when either matches - and the timezone, which is the host's or the panel's rather than yours. Check both before assuming the scheduler is broken.
Can cron run something every 30 seconds?
Not on its own; one minute is the finest interval. Run the job every minute and have it sleep 30 seconds and repeat internally, or use a systemd timer with OnUnitActiveSec=30s, or put the loop in the program that needs it.
Should the backup or the restart come first?
Backup first, with a save command before it, then the restart a comfortable margin later. A backup taken during shutdown is a backup of a server that is shutting down, and a backup started sixty seconds before a restart may not have finished.
Do I need to restart anything after editing a crontab?
No. Cron re-reads the file after crontab -e saves it. On a panel, a schedule takes effect as soon as it is saved, and the safest confirmation is to set it a couple of minutes ahead once and watch it fire.
What timezone do panel schedules use?
Whatever the panel is configured for, which is usually the location of the hardware rather than your own. Ours runs in Germany, so local time there moves by an hour between summer and winter. Test with a harmless job before you trust a maintenance window to it.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.