0 */2 * * * looks short. On a five-field crontab it means minute 0 of every second hour. The hour field steps from 0, so the day runs at 00:00, 02:00, 04:00, 06:00, 08:00, 10:00, 12:00, 14:00, 16:00, 18:00, 20:00, and 22:00. The last fire that day is 22:00, not 23:00.
Build the same five fields in the cron expression generator. The page does not install the job. Copy the line into the crontab on the host that will run it.
How the step is counted
A step is a range plus /n. In the hour field, * is the full hour range, so */2 walks that range by two, starting at 0. Pin the minute to 0 and you get the top of those hours only.
That is different from every hour:
0 * * * * # every hour, at minute 0 0 */2 * * * # every second hour, at minute 0 0 * * * * fires 24 times a day. 0 */2 * * * fires 12 times. Neither line has a seconds field. Five-field cron starts the command once when that minute begins.
Mistakes that move the run
Do not add a seconds field on the front. Quartz and Spring use six fields with seconds first. EventBridge uses six fields without seconds and puts ? in one day field. A five-field line from this site matches neither shape.
Copy the fields, not the English next to them. Crontab has no use for the words “every second hour.”
Call the program by its absolute path. Cron’s PATH is often shorter than your login shell.
Try one cycle
0 */2 * * * date >> /tmp/cron-every-2h.log Wait for two lines. The hours should be two apart, and each timestamp should land on minute 0. Then remove the line. Where cron logs the start depends on the distro: some use journalctl -u cron, others still write to syslog.
systemd timers use OnCalendar, which is a different language. Do not paste 0 */2 * * * into a timer unit. Check the expression you want with systemd-analyze calendar on that machine.
The minute steps, the day-of-month step trap, and the rest of the schedule notes are in the guide: https://kepttools.com/guides/cron-every-5-minutes
