For home servers and test environments, resource saving is important: containers can be stopped and system powered off during nights or off-hours. This guide describes a safe method with state preservation and automatic recovery.
π‘ Method suits OrangePI, Raspberry Pi, old PCs, and any systems where power efficiency matters.
π¦ Container shutdown script
Create script
# File: /usr/local/bin/stop_containers_and_shutdown.sh
cat > /usr/local/bin/stop_containers_and_shutdown.sh << 'EOF'
#!/bin/bash
#
# Script saves running container IDs,
# stops them, and initiates system shutdown.
#
CONTAINERS_FILE="/etc/active_containers.txt"
echo "=== $(date '+%Y-%m-%d %H:%M:%S') ==="
echo "Starting container shutdown and system power-off script"
# Get list of running containers (by ID)
RUNNING_CONTAINERS=$(docker ps -q)
if [ -n "${RUNNING_CONTAINERS}" ]; then
echo "Saving running containers to ${CONTAINERS_FILE}"
echo "${RUNNING_CONTAINERS}" > "${CONTAINERS_FILE}"
docker stop ${RUNNING_CONTAINERS}
echo "Containers stopped."
else
echo "No running containers."
[ -f "${CONTAINERS_FILE}" ] && rm -f "${CONTAINERS_FILE}"
fi
sleep 10
echo "Shutting down system."
/sbin/shutdown -h now
EOF
Make executable
chmod +x /usr/local/bin/stop_containers_and_shutdown.sh
How it works
| Step | Description |
|---|---|
docker ps -q | Gets IDs of all running containers |
> /etc/active_containers.txt | Saves list for recovery |
docker stop | Gracefully stops containers (SIGTERM) |
sleep 10 | Allows time for operations to complete |
shutdown -h now | Powers off the system |
Why this way:
- Saving IDs allows restoring the same containers
docker stopgives containers time for graceful shutdownsleep 10ensures all data is written to disk
π Container startup script
Create script
# File: /usr/local/bin/start_containers.sh
cat > /usr/local/bin/start_containers.sh << 'EOF'
#!/bin/bash
#
# Script reads container list from file,
# starts them, then removes the file.
#
CONTAINERS_FILE="/etc/active_containers.txt"
echo "=== $(date '+%Y-%m-%d %H:%M:%S') ==="
echo "Starting container startup script"
if [ ! -f "${CONTAINERS_FILE}" ]; then
echo "File ${CONTAINERS_FILE} not found. No startup needed."
exit 0
fi
CONTAINERS=$(cat "${CONTAINERS_FILE}")
if [ -n "${CONTAINERS}" ]; then
echo "Found container list: ${CONTAINERS}"
for cid in ${CONTAINERS}; do
docker start "${cid}"
if [ $? -eq 0 ]; then
echo "Container ${cid} started."
else
echo "Error starting container ${cid}."
fi
done
else
echo "File empty. No containers to start."
fi
rm -f "${CONTAINERS_FILE}"
echo "File ${CONTAINERS_FILE} removed."
EOF
Make executable
chmod +x /usr/local/bin/start_containers.sh
How it works
| Step | Description |
|---|---|
| File check | If missing - containers weren’t stopped by script |
docker start | Starts containers by saved IDs |
rm -f | Removes file after successful startup |
Why remove file:
- One-time marker - containers won’t restart accidentally
- After reboot without script - system runs in normal mode
β° Schedule setup (cron)
Shutdown (night)
# crontab -e (as root)
# Shutdown at 00:00 daily
0 0 * * * /usr/local/bin/stop_containers_and_shutdown.sh >> /var/log/docker-shutdown.log 2>&1
Startup (morning)
# crontab -e (as root)
# Startup at 08:00 daily
0 8 * * * /usr/local/bin/start_containers.sh >> /var/log/docker-startup.log 2>&1
Important notes
| Parameter | Description |
|---|---|
>> /var/log/... | Logging for debugging |
2>&1 | Redirect errors to same log |
| As root | Required for docker and shutdown |
Verify cron:
# Ensure cron is running
systemctl status cron
# View logs
tail -f /var/log/docker-shutdown.log
tail -f /var/log/docker-startup.log
π§ Alternative: systemd timer (modern method)
Shutdown timer
# /etc/systemd/system/docker-shutdown.timer
[Unit]
Description=Daily Docker shutdown timer
[Timer]
OnCalendar=*-*-* 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Shutdown service
# /etc/systemd/system/docker-shutdown.service
[Unit]
Description=Stop Docker containers and shutdown
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/stop_containers_and_shutdown.sh
Activate
systemctl daemon-reload
systemctl enable docker-shutdown.timer
systemctl start docker-shutdown.timer
# Check status
systemctl list-timers | grep docker-shutdown
systemd timer advantages:
- Precise timing (not affected by cron load)
- Built-in logging via
journalctl Persistent=true- runs missed execution after downtime
π‘ Safety and reliability
Exclude critical containers
If some containers must run continuously:
# Modify shutdown script
RUNNING_CONTAINERS=$(docker ps -q --filter "label=shutdown=false")
# In docker-compose.yml add label
services:
critical-service:
image: ...
labels:
- "shutdown=false"
Pre-shutdown check
# Add to shutdown script
ACTIVE_CONNECTIONS=$(netstat -an | grep ESTABLISHED | wc -l)
if [ "$ACTIVE_CONNECTIONS" -gt 10 ]; then
echo "Active connections detected. Cancelling shutdown."
exit 1
fi
UPS integration
# Integration with NUT (Network UPS Tools)
# /etc/nut/upsmon.conf
MONITOR ups@localhost 1 admin password slave
SHUTDOWNCMD "/usr/local/bin/stop_containers_and_shutdown.sh"
π Monitoring and debugging
Check logs
# Script logs
tail -50 /var/log/docker-shutdown.log
tail -50 /var/log/docker-startup.log
# Systemd logs (if used)
journalctl -u docker-shutdown.service -n 50
journalctl -u docker-startup.service -n 50
Check status
# Which containers are running
docker ps --format "table {{.Names}}\t{{.Status}}"
# Timer status
systemctl list-timers | grep docker
# State file (if exists)
cat /etc/active_containers.txt 2>/dev/null || echo "File not found"
β οΈ Common issues
# Script not running via cron
β Check permissions: ls -la /usr/local/bin/*.sh
β Check cron: grep CRON /var/log/syslog
β Ensure cron is running: systemctl status cron
# Containers not starting
β Check Docker: systemctl status docker
β Check logs: docker logs <container_id>
β Verify file exists: cat /etc/active_containers.txt
# System not shutting down
β Check shutdown available: which shutdown
β Check permissions: script must run as root
β View logs: journalctl -b -1 (previous boot)
# File not removed after startup
β Check file permissions: ls -la /etc/active_containers.txt
β Remove manually: rm -f /etc/active_containers.txt
π Pre-deployment checklist
- Tested scripts manually before cron setup
- Verified logging:
/var/log/docker-*.log - Ensured critical services excluded (if needed)
- Confirmed container data on persistent volumes
- Configured startup/shutdown notifications (optional)
- Created config backup