Init scripts
An init script is a bash script stored with a GPU instance. It runs to completion before the startup command, every time the pod starts.
A template records the image and the command; it cannot record what you did inside the container — and that is where most of the work happens. A pip package the image lacks, a model checkout, a config file: none of it survives the pod. Committing a new image would carry it, but that needs a registry you can push to and a build step. A script needs neither.
Where it runs
sshSetup → sshd → ssh tunnel → INIT SCRIPT → startup command
It runs after sshd is up, on purpose. These scripts install packages and download weights — minutes, not seconds — and being able to SSH in and watch is the difference between "still working" and "stuck".
Writing one
There are two places to write an init script:
- Save as template on a GPU instance's detail page — this is the normal one. By then you have found out the hard way what the image was missing, and you are writing it down. See Compute templates.
- Edit config on a running instance's detail page — adds or changes the script and rebuilds the pod. See Editing a running instance.
The script is then carried by every launch from that template, and by every restart of that instance.
Make it repeatable
The pod re-runs the script every time it starts — after an OOM kill, a node drain, or a redeploy — and the container filesystem is fresh each time, so a marker file written last time is gone too.
The pattern that works is: install into a mounted volume, and guard on the path.
pip install -r /mnt/models/requirements.txt
[ -d /mnt/models/flux ] || huggingface-cli download acme/flux --local-dir /mnt/models/flux
This is also what makes init scripts and persistent storage worth combining: the volume survives the pod, so the expensive half of the script only runs once.
A failing script does not kill the instance
If the script exits non-zero, the instance:
- prints the failure loudly in the pod log,
- skips the startup command, and
- stays up, idle, with SSH still working.
The script's whole job is to run things that break the first few times. A pod that exits goes into CrashLoopBackOff, where it restarts too fast to SSH into — and the one state you cannot debug is the one you cannot get into. Staying up means the instance is still billable, but it is reachable, which is where a broken script needs to be looked at.
The startup command is skipped because running your service without its dependencies produces a second, more confusing failure that buries the first.
To debug: open the terminal or SSH in, read the log above the failure, fix the script with Edit config, and redeploy.
Jupyter images are refused
A Jupyter image keeps its own entrypoint, so an init script attached to one would never run. Rather than store something silently inert, EcoLink refuses it:
HTTP 400 Bad Request
{ "error": "a Jupyter image keeps its own entrypoint, so the init script would never run — put these steps in the startup command instead" }
The console hides the init-script field entirely for images whose name contains jupyter.
What it does not carry
System-level changes: edits under /etc, anything compiled into /usr/local. Those need a custom image — see Container images.
For the common cases — pip packages, model weights, config files — a script is enough.
Limits
| Limit | Detail |
|---|---|
| Size | 64 KB |
| Resource kinds | GPU instances only. Model instances and GPU clusters have no equivalent yet |
| Images | Not available on Jupyter images |
| Runs | Every pod start, not once |
From the API
init_script is an ordinary field on the launch body:
curl https://api.ecohash.com/gpu-instances \
-X POST \
-H "Authorization: Bearer eco_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "flux-dev-box",
"region_id": "<region-id>",
"gpu_type": "<gpu-type-for-region>",
"gpu_count": 1,
"container_image": "nvidia/cuda:12.3.2-cudnn9-devel-ubuntu22.04",
"estimated_duration_hours": 8,
"init_script": "pip install -r /mnt/models/requirements.txt\n[ -d /mnt/models/flux ] || huggingface-cli download acme/flux --local-dir /mnt/models/flux"
}'
It can also be changed on a running instance with PATCH /gpu-instances/{id} — see Editing a running instance.