Running Stable Diffusion WebUI in Docker on your homelab means you can generate images without touching the host system, restart it cleanly, and keep everything isolated. I’ve been running this setup for about eight months now on an RTX 4070, and I’ve landed on a configuration that actually stays up and doesn’t require babysitting.
Prerequisites and Hardware
You need a GPU with at least 4GB VRAM. I’m using an Nvidia card, so I’ll be specific about that, but AMD users can adapt the Docker runtime setup. CPU-only mode works but generates at roughly one image per minute, which defeats the point.
On the host, you need the Nvidia Docker runtime installed. On Ubuntu 22.04, that’s nvidia-docker2 and nvidia-container-toolkit. Docker itself should be version 20.10 or newer.
Storage: the base model (sd-v1-5) is about 4GB. A few community models later and you’re at 30-40GB minimum. I run this on a dedicated 500GB NVMe partition to avoid filling my root drive with model weights.
The Docker Compose File, Explained
Here’s what I actually use. Every line has a reason.
version: '3.8'
services:
stable-diffusion:
image: ghcr.io/automatic1111/stable-diffusion-webui:latest
container_name: sd-webui
restart: unless-stopped
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,utility
environment:
- COMMANDLINE_ARGS=--listen 0.0.0.0 --port 7860 --opt-split-attention --enable-insecure-extension-access
- GRADIO_QUEUE_CONCURRENCY_COUNT=1
- SD_WEBUI_RESTART_AFTER_GENERATION=true
ports:
- "7860:7860"
volumes:
- /mnt/models:/home/user/stable-diffusion-webui/models
- /mnt/outputs:/home/user/stable-diffusion-webui/outputs
- sd-cache:/home/user/.cache
networks:
- webui-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7860/info"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"
networks:
webui-net:
driver: bridge
volumes:
sd-cache:
driver: local
Let me break the choices:
Runtime: nvidia โ This tells Docker to use the Nvidia container runtime, which gives the container direct access to your GPU. Without this, you’re doing CPU inference and you’ll regret it.
COMMANDLINE_ARGS โ The important ones here: --listen 0.0.0.0 makes the WebUI accessible from other machines on your network. --opt-split-attention reduces VRAM usage from ~10GB to ~6GB on my 4070. --enable-insecure-extension-access lets you install community extensions; it’s “insecure” in the sense that you’re not validating them, but if you’re self-hosting, you’re already making that call.
GRADIO_QUEUE_CONCURRENCY_COUNT=1 โ This was the surprise. The default is 8, which means WebUI tries to queue 8 generations at once. On a single GPU, this tanks memory and crashes the container. Setting it to 1 means requests wait, but at least they complete instead of dying. If you have multiple GPUs, you can push this higher.
Volumes โ The models directory is mounted from a separate partition because models are large and stateful. Same with outputs; I want to be able to wipe the container without losing generated images. The cache volume is local to Docker because it’s just temporary HF model metadata.
Healthcheck โ This pings /info every 30 seconds. Docker can restart the container if it hangs, which happens occasionally during large batch generations. The 60-second start_period gives WebUI enough time to load the model on startup.
Reverse Proxy Setup
I run Caddy in front of this because I don’t trust port 7860 to the internet directly, and I like having a clean domain name.
image-gen.lab {
reverse_proxy localhost:7860 {
header_uri /api/* Path .*
flush_interval -1
}
}
The flush_interval -1 matters if you’re streaming progress updates. Without it, Caddy buffers the response and you don’t see generation progress in real-time.
If you’re using Nginx instead:
server {
server_name image-gen.lab;
listen 80;
location / {
proxy_pass http://localhost:7860;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_buffering off;
proxy_request_buffering off;
}
}
The proxy_buffering off is the equivalent of Caddy’s flush_interval.
Environment Variables and File Organization
I keep a separate `.env` file for things that change:
CUDA_VISIBLE_DEVICES=0
SD_WEBUI_BATCH_SIZE=1
SD_WEBUI_STEPS=20
SD_WEBUI_SEED=42
Actually, I don’t use most of these at runtime because the WebUI interface is better for tweaking settings. But I do use CUDA_VISIBLE_DEVICES when I want to test on a different GPU, and SD_WEBUI_BATCH_SIZE stays at 1 to avoid OOM errors.
Directory structure on the host:
/mnt/models/
โโโ Stable-diffusion/
โ โโโ sd-v1-5-pruned.safetensors
โ โโโ deliberate-v2.safetensors
โโโ VAE/
โโโ ControlNet/
โโโ extensions/
/mnt/outputs/
โโโ txt2img/
โโโ img2img/
โโโ inpaint/
The models directory gets mounted read-write because you’ll want to add new models from the UI. Outputs is write-only from the container’s perspective, so I use a bind mount instead of a Docker volume.
First Launch and Optimization
When you first run docker-compose up -d, it downloads the image (about 8GB) and starts the container. The first generation takes 2-3 minutes because the model is loading from disk into VRAM. Subsequent generations are faster, usually 20-30 seconds depending on your resolution and step count.
Check the logs with docker-compose logs -f stable-diffusion. You should see Gradio starting on port 7860. If you see CUDA errors, your runtime isn’t wired up correctly.
The first model download happens when you hit “Generate.” It’s large, so don’t panic if nothing seems to happen for 30 seconds. Check the logs to confirm it’s downloading.
One thing I’ve had to do: after running this for a few weeks, the container gets sluggish. The built-in Python environment accumulates cache files. A docker-compose down && docker-compose up -d fixes it. I haven’t figured out how to prevent it cleanly, so I just restart monthly.
Models and Extensions
The default model is included, but you’ll want others. HuggingFace hosts most of them. You can download them manually and drop them in the models directory, or use the WebUI’s model manager.
Extensions are Git repositories that live in the WebUI. The popular ones are:
- ControlNet โ adds spatial control over generation
- Adetailer โ automatically improves faces and hands
- LoRA โ lets you load lightweight fine-tuned adapters
Extensions install via the WebUI directly. Some have dependencies that need to compile inside the container, which can fail if your image is missing dev tools. If that happens, you might need to build a custom Dockerfile, but the stock image covers 90% of use cases.
Common Issues I’ve Hit
Out of Memory errors โ Reduce batch size, lower resolution, or use --opt-split-attention (already in my config). On a 4GB card, you’re limited to 512ร512 resolution unless you sacrifice quality steps.
Container dies after 30 seconds โ Usually means the GPU drivers aren’t visible. Check that nvidia-smi works on the host, then verify the runtime in Docker with docker run --rm --runtime=nvidia nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi.
Models not persisting after container restart โ If you mounted models as a volume but didn’t persist it, they’ll vanish. Use bind mounts for anything you want to keep: - /mnt/models:/path/in/container.
WebUI responds slowly or hangs โ This usually means the GPU ran out of memory and is swapping. Lower your settings or restart the container.
I’ve been running this long enough that I know which settings produce consistent results on my hardware. What surprised me was how much the queue concurrency setting matters โ a single change there cut my crash rate from maybe once a week to almost never. The other lesson: monitoring and logs are worth the effort. The healthcheck saves more restarts than I expected.
FAQ
Can Stable Diffusion WebUI run on a Raspberry Pi?
Not usefully. A Pi has no dedicated GPU, and CPU inference is too slow. You’d wait 5-10 minutes per image. Use this setup on an x86 machine with a real GPU instead.
Do I need a high-end GPU like an RTX 4090?
No. An RTX 4070 or even a 3060 (12GB VRAM) works fine. The tradeoff is speed; a 3060 takes 30-40 seconds per image where a 4090 takes 10. For local experimentation, that’s acceptable.
Is Stable Diffusion WebUI legal to use?
Yes. The model weights are licensed under the OpenRAIL license, which allows personal and commercial use with some restrictions around harm. You’re fine self-hosting for your own use.
How much disk space do I need?
Plan for 50-100GB. The base model is 4GB, but popular community models are 7-10GB each. Generated outputs take a few MB per image. I keep a separate 500GB partition for models and outputs to avoid competing with system storage.
Can I use this with AMD GPUs?
Yes, but the setup changes. You’d use rocm runtime instead of nvidia and adjust the image or build a custom one. The docker-compose structure stays mostly the same, but GPU detection is different.
Explore Stable Diffusion WebUI in our AI Homelab Toolkit.