Posted on August 06, 2025
Category: Technology
Tags: python, systemd, linux, scheduling
Views: 919
Running a standalone Python script at a specific time is a common requirement for tasks like data processing or API calls. Using systemd with a timer on a Linux server provides precise scheduling, dependency management, and robust logging. This guide shows how to set up a Python script to run in a virtual environment as a systemd service, scheduled to execute at an exact time (e.g., 9:30 AM daily or a one-time run), and addresses common issues like the status=217/USER error.
systemd.sudo apt install python3 python3-pip python3-venv).ubuntu) for security./home/ubuntu/scripts/script.py) and a virtual environment.Create a directory for your script and virtual environment, ensuring the user (e.g., ubuntu) has full access.
sudo mkdir -p /home/ubuntu/scripts
sudo chown ubuntu:ubuntu /home/ubuntu/scripts
Create a sample Python script:
vim /home/ubuntu/scripts/script.py
import datetime
import requests
print(f"Script ran at {datetime.datetime.now()}")
# Example task: Make an API call
response = requests.get("https://dog.ceo/api/breeds/list/all")
print(response.json())
Set up a virtual environment and install dependencies:
python3 -m venv /home/ubuntu/scripts/venv
source /home/ubuntu/scripts/venv/bin/activate
pip install requests
deactivate
Test the script manually as the intended user:
/home/ubuntu/scripts/venv/bin/python3 /home/ubuntu/scripts/script.py
If this fails, check for missing dependencies or permissions.
Create a systemd service file to run the script as a one-time task.
sudo vim /etc/systemd/system/myscript.service
[Unit]
Description=Run standalone Python script in virtual environment
After=network.target
[Service]
Type=oneshot
ExecStart=/home/ubuntu/scripts/venv/bin/python /home/ubuntu/scripts/script.py
User=ubuntu
WorkingDirectory=/home/ubuntu/scripts
Environment="MYENVVAR1=1234"
Environment="MYENVVAR2=5678"
Restart=no
[Install]
WantedBy=multi-user.target
Type=oneshot: Runs the script once and exits.User=ubuntu: Runs as the ubuntu user (replace with your user).ExecStart: Uses the virtual environment’s Python binary.Environment: Defines the environment variables.After=network.target: Ensures network availability for API calls.Create a timer to schedule the service at a specific time (e.g., 9:30 AM on weekdays).
sudo vim /etc/systemd/system/myscript.timer
[Unit]
Description=Run myscript.service at specific time
[Timer]
OnCalendar=Mon..Fri *-*-* 09:30:00
AccuracySec=1min
Persistent=true
Unit=myscript.service
[Install]
WantedBy=timers.target
OnCalendar=Mon..Fri *-*-* 09:30:00: Runs on weekdays at 09:30 AM EDT (adjust for your timezone, e.g., 2025-08-06 15:30:00 for a one-time run).Persistent=true: Runs missed executions upon boot.man systemd.time for calendar syntax (e.g., Mon *-*-* 14:00:00 for weekly runs).Ensure the ubuntu user has access to the virtual environment and script:
sudo chown -R ubuntu:ubuntu /home/ubuntu/scripts
sudo chmod -R u+rx /home/ubuntu/scripts
sudo chmod +x /home/ubuntu/scripts/script.py
Verify permissions:
ls -ld /home/ubuntu/scripts
ls -ld /home/ubuntu/scripts/venv
ls -l /home/ubuntu/scripts/venv/bin/python
ls -l /home/ubuntu/scripts/script.py
Expected output:
drwxr-xr-x 3 ubuntu ubuntu 4096 Aug 5 19:38 /home/ubuntu/scripts
drwxr-xr-x 5 ubuntu ubuntu 4096 Aug 5 19:38 /home/ubuntu/scripts/venv
-rwxr-xr-x 1 ubuntu ubuntu 2320 Aug 5 19:38 /home/ubuntu/scripts/venv/bin/python
-rwxr-xr-x 1 ubuntu ubuntu 123 Aug 5 19:38 /home/ubuntu/scripts/script.py
Activate the timer:
sudo systemctl daemon-reload
sudo systemctl enable myscript.timer
sudo systemctl start myscript.timer
Check the timer status:
sudo systemctl status myscript.timer
systemctl list-timers
View logs after the script runs:
journalctl -u myscript.service -b
status=217/USER ErrorIf you encounter the error Main process exited, code=exited, status=217/USER, it means the User= specified in myscript.service (e.g., ubuntu) is invalid or inaccessible.
Verify User:
id ubuntu
If the user doesn’t exist, create it:
sudo adduser youruser
Or temporarily use User=root in myscript.service, then revert to a non-root user.
Check Paths:
ls -l /home/ubuntu/scripts/venv/bin/python
ls -l /home/ubuntu/scripts/script.py
Fix paths in myscript.service if incorrect.
Test Service:
sudo systemctl start myscript.service
journalctl -u myscript.service -b
Test Script:
su - ubuntu -c "/home/ubuntu/scripts/venv/bin/python /home/ubuntu/scripts/script.py"
SELinux/AppArmor (if applicable):
sudo setenforce 0
sudo systemctl start myscript.service
sudo setenforce 1
Logs:
journalctl -xe
Timezone: Ensure the server’s timezone matches your schedule (e.g., EDT):
timedatectl
sudo timedatectl set-timezone America/New_York
One-Time Run: For a specific date (e.g., August 6, 2025, 3:30 PM), set:
OnCalendar=2025-08-06 15:30:00
Dependencies: Install all required packages in the virtual environment:
/home/ubuntu/scripts/venv/bin/pip install requests
This setup ensures your Python script runs reliably at a specific time, leveraging systemd’s precision and logging, and is isolated in a virtual environment for dependency management. For further customization, share your script’s purpose or specific schedule requirements!
Disclaimer: This blog post was created with assistance from Grok 3, an AI developed by xAI, under my direct supervision and guidance to ensure accuracy and alignment with my vision for the content.