---
title: Custom Docker Template
sidebar_label: Custom Template
---

> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Docker Template

Use a template when you want pods to start from a specific Docker image with predefined ports, environment variables, volume paths, and a startup command.

This example creates a private template from a known PyTorch image, starts a Python HTTP server from the template's startup command, prints the mapped public URL, checks an environment variable, and stops the pod.

```python
#!/usr/bin/env python3
"""Create a custom template, launch a pod from it, and inspect runtime settings."""

from datetime import datetime, timezone

from lium.sdk import Lium

lium = Lium()
ready_pod = None
created_pod_id = None

template_name = "sdk-custom-template-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")

try:
    template = lium.create_template(
        name=template_name,
        docker_image="daturaai/pytorch",
        docker_image_tag="2.4.0-py3.11-cuda12.4.1-devel-ubuntu22.04",
        ports=[22, 8000],
        start_command="python -m http.server 8000 --bind 0.0.0.0 --directory /workspace",
        environment={
            "LIUM_EXAMPLE_MODE": "custom-template",
        },
        volumes=["/workspace"],
        description="Private SDK example template",
        is_private=True,
    )

    template = lium.wait_template_ready(template.id, timeout=600)
    if template is None:
        raise RuntimeError("Template did not verify before the timeout")

    executors = lium.ls(
        gpu_type="A100",
        gpu_count=1,
        min_cuda_version=12.4,
    )
    if not executors:
        raise RuntimeError("No matching executor is currently available")

    executor = min(executors, key=lambda item: item.price_per_hour)

    pod = lium.up(
        executor_id=executor.id,
        template_id=template.id,
        name="sdk-custom-template-demo",
        ports=2,
    )
    created_pod_id = pod["id"]

    ready_pod = lium.wait_ready(pod, timeout=600)
    if ready_pod is None:
        raise RuntimeError("Pod did not become ready before the timeout")

    details = lium.pod(ready_pod.id)
    ports_mapping = details["ports_mapping"]
    app_port = ports_mapping.get("8000")
    if app_port is None:
        raise RuntimeError(f"Port 8000 was not exposed: {ports_mapping}")

    result = lium.exec(ready_pod, command="printenv LIUM_EXAMPLE_MODE")
    if not result["success"]:
        raise RuntimeError(result["stderr"] or result["stdout"])
    print(result["stdout"].strip())

    print(f"Open http://{ready_pod.host}:{app_port}/")

finally:
    pod_to_stop = ready_pod
    if pod_to_stop is None and created_pod_id:
        pod_to_stop = next((p for p in lium.ps() if p.id == created_pod_id), None)

    if pod_to_stop is not None:
        lium.down(pod_to_stop)
        print(f"Stopped pod {pod_to_stop.name} ({pod_to_stop.huid})")
```

## What Each Field Does

- `docker_image` and `docker_image_tag` choose the container image for the template.
- `ports` declares internal container ports that Lium should expose. Include `22` for SSH access, plus application ports such as `8000` for an API server.
- `start_command` is the command run when the container starts. This example starts Python's built-in HTTP server on `0.0.0.0:8000` so the service can be reached through Lium's public port mapping.
- `environment` sets container environment variables.
- `volumes` declares mount paths inside the container.
- `is_private=True` keeps the template scoped to your account.

When you create a pod, request enough public ports for the SSH port and the application port. Fetch the pod with `lium.pod(...)` and read `ports_mapping` to see the assigned host ports.
