Skip to main content

How to use Render.com Cron Jobs to launch Django management commands

·559 words·3 mins
Author
Alessandro Ferrini

For a recent project I needed a cron job on Render to run some Django management commands. Here’s the approach that worked well.

Why a separate Cron Job service?
#

Render’s Cron Jobs run from their own service/repo (or a prebuilt image) on a schedule you define. My project EchoEV - Sealed TCG EV Tracker uses SQLite with a persistent disk attached to the main service. Because a Cron Job deploys a separate container, it can’t share that disk directly. Instead of duplicating state, I spin up a tiny container that SSHs into the main instance and runs the command there. This requires paid services because free tiers don’t support SSH access.

Overview
#

  1. Generate an SSH key without a passphrase.
  2. Add the public key to your Render account (so Render recognizes it for SSH).
  3. Store the private key as an environment secret for the Cron Job.
  4. Build a minimal image that decodes the key and runs ssh into your main service.
  5. Execute your Django command remotely.

Tip: Cron Jobs can initiate outbound connections but can’t receive inbound traffic; that’s fine here because we initiate SSH from the job to the target service.

1) Create an SSH key (no passphrase)
#

ssh-keygen -t ed25519 -f cronjob_key -C "cronjob-render"

This creates cronjob_key (private) and cronjob_key.pub (public). Never commit the private key.

2) Add the public key to Render
#

Follow Render’s guide to add an SSH public key to your account. This lets the key authenticate against your services via the dashboard’s “Account Settings → SSH Public Keys”. (Adding an SSH public key to your Render account)

3) Store the private key as a secret
#

To avoid multiline formatting issues, store the private key Base64-encoded in an environment variable (e.g., SSH_KEY_B64) for the Cron Job:

# Linux:
base64 -w 0 cronjob_key > cronjob_key.b64
# macOS (no -w): 
base64 < cronjob_key | tr -d '\n' > cronjob_key.b64

Create an env var SSH_KEY_B64 in the Cron Job (or an Environment Group) with the content of cronjob_key.b64.

4) Minimal Docker image for the Cron Job
#

Use a tiny image with the OpenSSH client and a small runner script.

Dockerfile

FROM alpine:3.18
RUN apk add --no-cache openssh-client
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD ["/run.sh"]

run.sh

#!/bin/sh
set -eu

# Recreate the private key from the env var
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "$SSH_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519

# Use the EXACT user@host from your service page: Connect → SSH
RENDER_SSH_HOST="ssh.frankfurt.render.com"   # change based on your region
SERVICE_USER="your-service-slug"             # you can find this on your project 'Shell' page
USER_HOST="${SERVICE_USER}@${RENDER_SSH_HOST}"

# (optional) Pre-populate known_hosts to avoid interactive prompts
ssh-keyscan -H "$RENDER_SSH_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true

# let's call our script
ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no "$USER_HOST" "bash path/of/your_script.sh"

Get the correct SSH username@host from your service’s Connect → SSH tab (it looks like YOUR_SERVICE@ssh.YOUR_REGION.render.com). Don’t hand-type or line-wrap it. (Connecting with SSH)

5) Create the Cron Job
#

  • In the Render dashboard: New → Cron Job.
  • Point it at this repo (Docker), pick a schedule (e.g., 0 * * * *).
  • Add the env var SSH_KEY_B64 (from step 3).
  • Deploy and test with a manual run. Check logs for SSH output.

And that’s it, a lightweight, secure way to run any command on a Render schedule without duplicating state or sharing disks between services.