This guide is for operators, system administrators, and developers who deploy, harden, extend, or audit Fooocus. It documents the architecture, the complete configuration surface, the security model, operational procedures, and the internal code structure in enough depth to operate Fooocus confidently or rebuild an understanding of it from scratch.
For end-user, task-oriented documentation (installation, generation modes, prompts), see the User Guide.
Note
Fooocus is in limited long-term support (LTS) — bug fixes only, built entirely on Stable Diffusion XL. There are no current plans to migrate to newer architectures. Operationally, this means the codebase is stable and the dependency pins are fixed; the main maintenance burden is keeping the runtime (PyTorch, drivers, NumPy) compatible with newer hardware. This guide flags those points explicitly.
Table of Contents
- Executive Summary
- Architecture
- The Vendored
ldm_patchedBackend and Monkey-Patching - Requirements and Dependencies
- Startup and the Generation Pipeline
- Configuration Mastery
- Presets
- Command-Line Reference
- Model Management and Auto-Download
- Security Analysis
- Deployment
- Operations
- Repository Structure
- Module Reference
- Code Quality and Patterns
- Potential Improvements
- Quick Reference
1. Executive Summary
Fooocus (version 2.5.5 at the documented commit) is a single-process Python application that wraps a Stable Diffusion XL diffusion pipeline behind a Gradio web UI. Its defining characteristic is opinionated automation: a large body of sampling, prompt-expansion, and scheduling logic is applied automatically so that users do not configure the model.
Key architectural facts an operator must know:
- Single process, single GPU. Fooocus runs one Gradio server and one background worker thread. There is no horizontal scaling primitive; multi-GPU means multiple independent instances.
- No bundled models. All weights are downloaded on demand from Hugging Face on first run and on preset switches. This is the single largest operational and supply-chain consideration.
- A vendored, monkey-patched diffusion backend. The
ldm_patched/package is a renamed fork of the ComfyUI backend, and Fooocus patches it at import time (modules/patch*.py,modules/sample_hijack.py). Upgrading the vendored backend can silently break those patches. - Auto-update on launch. The recommended entry point (
entry_with_update.py) performs agit fetch+ hard reset tooriginbefore every run. - Minimal but real attack surface. Optional network exposure (
--listen,--share), a simple SHA-256 auth file, globally disabled TLS verification, and known community-reported issues (arbitrary code execution viaeval(), a path-traversal report) make hardening important when Fooocus is exposed beyondlocalhost.
┌──────────────────────────────────────────────┐
Browser ───────▶│ Gradio server (Blocks, port 7865) │
│ webui.py — UI definition + event wiring │
└───────────────┬──────────────────────────────┘
│ AsyncTask queued
▼
┌──────────────────────────────────────────────┐
│ Background worker thread (async_worker.py) │
│ process_prompt → diffusion → save_and_log │
└───────────────┬──────────────────────────────┘
│ calls
▼
┌──────────────────────────────────────────────┐
│ default_pipeline.py (Fooocus orchestration) │
│ patched via modules/patch*.py at import │
└───────────────┬──────────────────────────────┘
│ wraps
▼
┌──────────────────────────────────────────────┐
│ ldm_patched/ (vendored ComfyUI backend) │
│ model_management · samplers · sd · cldm │
└──────────────────────────────────────────────┘
2. Architecture
Fooocus is structured in three layers:
-
UI layer (
webui.py,shared.py,modules/gradio_hijack.py,modules/ui_gradio_extensions.py,javascript/,css/). Defines a singlegr.Blocksinterface and wires every control to a callback. The interface is queued (.queue()), so generation requests are serialized. -
Orchestration layer (
modules/). The Fooocus-specific logic: the async task model, prompt processing, style application, the diffusion pipeline orchestration, inpaint/upscale/enhance workflows, LoRA handling, metadata, and the extensive runtime patches applied to the backend. -
Backend layer (
ldm_patched/). A vendored fork of the ComfyUI diffusion engine providing model loading, memory management, samplers, schedulers, VAE, ControlNet (cldm), and the latent-diffusion model code.
Request lifecycle
- The user clicks Generate.
webui.py:get_task()packs every UI control value (in a fixed positional order) into aworker.AsyncTask. - The task is appended to
async_worker.async_tasks. A single background worker thread (started at import) picks it up. AsyncTask.__init__unpacks the positional args into named attributes (this fixed ordering is the contract betweenwebui.pyandasync_worker.py— see Code Quality).- The worker runs the pipeline and yields progress events (
preview,results,finish) back to the UI throughtask.yields, whichgenerate_clicked()consumes in a polling loop.
Concurrency model
There is exactly one worker thread and the Gradio queue serializes requests. Generation is therefore effectively single-task. The --multi-user flag (inherited from the backend) affects storage scoping only, not parallel execution. Interruption (Stop/Skip) is implemented via a backend interrupt_processing mutex.
Important
Because generation is single-threaded and single-GPU per process, a busy instance blocks all users. To serve multiple concurrent users, run multiple instances (each pinned to a GPU with
--gpu-device-id) behind a load balancer with sticky sessions.
3. The Vendored ldm_patched Backend and Monkey-Patching
This is the most important architectural fact for anyone maintaining or forking Fooocus.
ldm_patched/ is a vendored, renamed fork of the ComfyUI backend (comfy/). It includes model_management, samplers, sd, controlnet/cldm, k_diffusion, unipc, the latent-diffusion model code (ldm/), and the engine's own argument parser (ldm_patched/modules/args_parser.py).
Fooocus does not modify the backend in place at the call site. Instead, at the moment modules/async_worker.py is imported, it calls patch_all() from modules/patch.py, which monkey-patches functions and methods inside ldm_patched (and a few other libraries) at runtime. The patch modules are:
| Module | What it patches |
|---|---|
modules/patch.py |
Core diffusion patches: weight calculation, UNet forward, ADM guidance, sharpness, CFG mimicking, sampler hooks. Defines PatchSettings (sharpness, ADM scales, controlnet softness, adaptive CFG). |
modules/patch_clip.py |
Patches CLIP text-encoder behavior. |
modules/patch_precision.py |
Patches numeric precision handling. |
modules/sample_hijack.py |
Replaces/extends the sampling loop (scheduler selection, etc.). |
modules/anisotropic.py |
Anisotropic filtering used by the sharpness patch. |
Warning
Upgrading the vendored backend can silently break the patches. Because the patches target specific functions/methods in
ldm_patchedby name and signature, replacingldm_patched/with a newer ComfyUI snapshot — without re-validating every patch — can cause subtle, non-crashing quality regressions (wrong guidance, missing sharpness) rather than loud errors. Treatldm_patched/as a pinned, co-versioned component. Re-test image output against known seeds after any backend change.
Note
This is the same hazard class as AUTOMATIC1111's
sd_hijackpatches over k-diffusion/CLIP. If you maintain a fork, keep a fixed-seed regression suite that compares output images before and after touching the backend or the patch modules.
A practical consequence: the CLI flag surface is split across two parsers. Fooocus's UX flags are defined in args_manager.py; the diffusion-engine flags (VRAM mode, precision, attention implementation, networking) are defined in ldm_patched/modules/args_parser.py. args_manager.py imports the backend parser and adds its own arguments to it, so a single --help shows both. See Command-Line Reference.
4. Requirements and Dependencies
Runtime requirements
| Resource | Minimum | Notes |
|---|---|---|
| GPU | 4 GB VRAM (NVIDIA) | AMD beta (ROCm/DirectML); Intel/Apple via fallbacks |
| RAM | 8 GB + swap | 16 GB+ recommended; ≥40 GB free disk per drive if CPUAllocator errors appear |
| Python | 3.10 | environment.yaml pins python=3.10 |
| Disk | ~10–20 GB for default models, more per preset | No models are bundled |
Pinned dependencies (requirements_versions.txt)
torchsde==0.2.6 einops==0.8.0
transformers==4.42.4 safetensors==0.4.3
accelerate==0.32.1 pyyaml==6.0.1
pillow==10.4.0 scipy==1.14.0
tqdm==4.66.4 psutil==6.0.0
pytorch_lightning==2.3.3 omegaconf==2.3.0
gradio==3.41.2 pygit2==1.15.1
opencv-contrib-python-headless==4.10.0.84
httpx==0.27.0 onnxruntime==1.18.1
timm==1.0.7 numpy==1.26.4
tokenizers==0.19.1 packaging==24.1
rembg==2.0.57 groundingdino-py==0.4.0
segment_anything==1.0
PyTorch itself is installed separately by launch.py:prepare_environment(), which defaults to:
pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url https://download.pytorch.org/whl/cu121
Caution
The PyTorch 2.1.0 / CUDA 12.1 pin is the #1 source of "won't run on new hardware" reports. Newer GPUs (e.g. RTX 50-series, compute capability
sm_120) are not supported by this build, producingCUDA error: no kernel image is available. Override with theTORCH_COMMAND/TORCH_INDEX_URLenvironment variables (below) or pre-install a compatible PyTorch before launch.
Note
numpy==1.26.4is pinned deliberately. Allowing NumPy 2.x into the environment causesnumpy.core.multiarray failed to import. Do not blanket-upgrade the environment.
Environment variables that influence installation
| Variable | Default | Effect |
|---|---|---|
TORCH_INDEX_URL |
https://download.pytorch.org/whl/cu121 |
PyTorch wheel index. |
TORCH_COMMAND |
pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url $TORCH_INDEX_URL |
Full torch install command. Override to change torch version. |
REQS_FILE |
requirements_versions.txt |
Requirements file to install. |
XFORMERS_PACKAGE |
xformers==0.0.23 |
xformers build (only if xformers install is enabled). |
INDEX_URL |
(empty) | Extra pip index URL (modules/launch_util.py). |
HF_MIRROR |
https://huggingface.co |
Hugging Face mirror for model downloads (also --hf-mirror). |
LAUNCH_LIVE_OUTPUT |
(empty) | Stream subprocess output during install. |
5. Startup and the Generation Pipeline
Entry chain
entry_with_update.py → git fetch + (fast-forward) hard reset to origin, then `from launch import *`
└─ launch.py → prepare_environment() [pip installs], build_launcher() [writes run*.bat on Windows],
parse args, download_models(), then `from webui import *`
└─ webui.py → build gr.Blocks UI, start the worker thread, launch the Gradio server (port 7865)
entry_with_update.pyusespygit2to fetchoriginand fast-forward the working tree. If you modified files, it printsUpdate failed - Did you modify any file?and continues with your local code.launch.pysetsGRADIO_SERVER_PORT=7865(if unset), enables the MPS fallback for Apple Silicon, and — notably — setsssl._create_default_https_context = ssl._create_unverified_context(see Security).build_launcher.pywritesrun.bat,run_anime.bat, andrun_realistic.baton Windows standalone builds.
The generation pipeline (async_worker.py → default_pipeline.py)
Each AsyncTask is processed roughly as follows:
apply_patch_settings— installs per-processPatchSettings(sharpness, ADM, adaptive CFG) keyed by PID.- Performance overrides — for Extreme Speed / Lightning / Hyper-SD, the worker downloads the acceleration LoRA and forces sampler, scheduler, CFG, sharpness, ADM, and refiner-switch values (
set_lcm_defaults,set_lightning_defaults,set_hyper_sd_defaults). apply_image_input— inspects the active tab and appends "goals" (vary,upscale,inpaint,cn,enhance). Downloads ControlNet / IP-Adapter / inpaint / upscale models as needed.process_prompt— splits multi-line prompts, applies wildcards (__file__) and arrays ([[a,b,c]]), applies styles, runs Fooocus V2 prompt expansion, encodes positive/negative conditioning via CLIP, and refreshes models/LoRAs.- Diffusion —
pipeline.process_diffusion(...)runs the sampler with the chosen steps, switch point (refiner), and resolution. - Post-process — inpaint post-processing, optional NSFW censor (
extras/censor.py), thensave_and_logwrites the image plus a metadata dictionary (prompt, model, seed, sampler, LoRAs, ADM guidance, version, …) tooutputs/viaprivate_logger.
The worker yields preview/results/finish events to the UI throughout.
Note
"Goals" are additive. The Image Prompt tab can mix with Upscale/Variation or Inpaint via the
mixing_image_prompt_and_*flags, which is whyapply_image_inputcan append bothcnandinpaint.
6. Configuration Mastery
Fooocus configuration is layered. Understanding the precedence is the single most useful operator skill.
Precedence (highest wins)
1. Environment variable matching the config key (e.g. set `default_cfg_scale` in the env)
2. CLI argument (for the subset exposed as flags, e.g. --output-path)
3. User config file: config.txt (JSON; created on first launch)
4. The active preset: presets/<name>.json
5. presets/default.json (loaded first as the base)
6. Hard-coded defaults in modules/config.py
modules/config.py loads presets/default.json, then merges config.txt, then merges the active preset, then resolves every key through get_config_item_or_set_default() (which also checks for an environment-variable override and validates the value/type).
config.txt
A JSON file at the repo root (path overridable with the config_path env var). It is created on first launch with the currently-resolved values, and thereafter you edit it to change defaults. Fooocus also always writes config_modification_tutorial.txt — a non-effective tutorial/example file listing every key with its current value and formatting rules.
Tip
Edit
config.txt, neverconfig_modification_tutorial.txt. On Windows paths, escape backslashes (\\) and ensure there is no trailing comma before the closing}.
Path configuration
| Key | Default (relative to repo) | Purpose |
|---|---|---|
path_checkpoints |
../models/checkpoints/ |
Base models (list-valued; multiple folders allowed). |
path_loras |
../models/loras/ |
LoRA files (list-valued). |
path_embeddings |
../models/embeddings/ |
Textual-inversion embeddings. |
path_vae |
../models/vae/ |
Standalone VAEs. |
path_vae_approx |
../models/vae_approx/ |
Preview approximation VAEs. |
path_upscale_models |
../models/upscale_models/ |
Upscaler. |
path_inpaint |
../models/inpaint/ |
Inpaint head + patch models. |
path_controlnet |
../models/controlnet/ |
ControlNet / IP-Adapter. |
path_clip_vision |
../models/clip_vision/ |
CLIP-Vision for image prompt. |
path_fooocus_expansion |
../models/prompt_expansion/fooocus_expansion |
GPT-2 expansion model. |
path_wildcards |
../wildcards/ |
Wildcard text files. |
path_safety_checker |
../models/safety_checker/ |
NSFW safety checker. |
path_sam |
../models/sam/ |
Segment Anything models. |
path_outputs |
../outputs/ |
Generated images + HTML logs (override with --output-path). |
Note
A deprecated
user_path_config.txtformat is auto-migrated to the newpath_*keys at startup (try_load_deprecated_user_path_config), backing up the old file. This is transparent but worth knowing if you inherit an old install.
Generation defaults (selected — full set in modules/config.py)
| Key | Default | Validated range / values |
|---|---|---|
default_model |
model.safetensors (preset overrides) |
string |
default_refiner |
None |
string |
default_refiner_switch |
0.8 |
0–1 |
default_cfg_scale |
7.0 (presets lower it) |
number |
default_sample_sharpness |
2.0 |
number |
default_sampler |
dpmpp_2m_sde_gpu |
must be in sampler_list |
default_scheduler |
karras |
must be in scheduler_list |
default_vae |
Default (model) |
string |
default_styles |
["Fooocus V2","Fooocus Enhance","Fooocus Sharp"] |
all in legal style names |
default_performance |
Speed |
one of Performance values |
default_max_lora_number |
5 |
≥1 |
default_loras_min_weight / max_weight |
-2 / 2 |
-10–10 |
default_aspect_ratio |
1152*896 |
in available_aspect_ratios |
default_max_image_number |
32 |
≥1 |
default_image_number |
2 |
1–max |
default_output_format |
png |
png/jpeg/webp |
default_clip_skip |
2 |
1–12 |
default_cfg_tsnr |
7.0 |
number |
default_inpaint_engine_version |
v2.6 |
None/v1/v2.5/v2.6 |
default_black_out_nsfw |
False |
bool — forces NSFW censoring |
default_save_metadata_to_images |
False |
bool |
default_metadata_scheme |
fooocus |
fooocus/a1111 |
temp_path |
system temp /fooocus |
string |
temp_path_cleanup_on_launch |
True |
bool |
Important
Set
default_black_out_nsfw: trueinconfig.txtto force the safety checker on for every generation regardless of the per-task checkbox. This downloads and runsstable-diffusion-safety-checker.binand is the recommended setting for any shared/public deployment.
7. Presets
A preset is a JSON file in presets/ that overrides config keys. The mapping from config key → metadata parameter lives in possible_preset_keys in modules/config.py. Shipped presets:
| Preset | Base model | Refiner | CFG | Default styles | Extra |
|---|---|---|---|---|---|
default |
juggernautXL_v8Rundiffusion | None | 4.0 | V2 + Enhance + Sharp | + SDXL offset LoRA @0.1 |
anime |
animaPencilXL_v500 | None | 6.0 | V2 + Semi Realistic + Masterpiece | — |
realistic |
realisticStockPhoto_v20 | None | 3.0 | V2 + Photograph + Negative | + film LoRA @0.25, strong negative prompt |
lcm |
juggernautXL_v8 | None | 4.0 | V2 + Enhance + Sharp | Extreme Speed |
lightning |
juggernautXL_v8 | None | 4.0 | V2 + Enhance + Sharp | Lightning |
playground_v2.5 |
playground-v2.5-1024px | None | 2.0 | V2 | edm_playground_v2.5 scheduler |
pony_v6 |
ponyDiffusionV6XL | None | 7.0 | Fooocus Pony | + dedicated VAE |
sai |
sd_xl_base_1.0 | sd_xl_refiner_1.0 @0.75 | 7.0 | V2 + Cinematic | + SDXL offset LoRA @0.5 |
Each preset declares checkpoint_downloads, lora_downloads, vae_downloads, embeddings_downloads (the Hugging Face URLs to fetch) and previous_default_models (fallbacks so a preset switch reuses a model you already have instead of downloading the newest).
Tip
To create a custom edition, copy a preset JSON, point it at your models with their download URLs, and launch with
--preset yourname. SettingREWRITE_PRESET = Trueinconfig.py(developer-only) makes Fooocus dump the resolved config back to the preset file and exit.
8. Command-Line Reference
Flags come from two parsers. Fooocus-specific flags (args_manager.py):
| Flag | Type | Default | Purpose |
|---|---|---|---|
--share |
bool | off | Public Gradio share link. |
--preset |
str | None | Apply a preset. |
--disable-preset-selection |
bool | off | Hide in-browser preset dropdown. |
--language |
str | default |
Use language/<x>.json for UI translation. |
--disable-offload-from-vram |
bool | off | Keep models in VRAM (some Macs need this). |
--theme |
str | None | light or dark. |
--disable-image-log |
bool | off | Don't write images/logs to outputs/. |
--disable-analytics |
bool | off | Disable Gradio analytics. |
--disable-metadata |
bool | off | Don't embed metadata in images. |
--disable-preset-download |
bool | off | Skip preset model downloads. |
--disable-enhance-output-sorting |
bool | off | Don't reorder enhance gallery. |
--enable-auto-describe-image |
bool | off | Auto-describe when prompt is empty. |
--always-download-new-model |
bool | off | Download newest preset models (no fallback). |
--rebuild-hash-cache |
int | — | Regenerate model/LoRA hashes (optional thread count). |
Backend/engine flags (ldm_patched/modules/args_parser.py) — selected:
| Flag | Default | Purpose |
|---|---|---|
--listen |
127.0.0.1 |
Bind address (set to 0.0.0.0 to expose). |
--port |
8188* |
Server port (*Fooocus sets the Gradio port to 7865 separately). |
--web-upload-size |
100 |
Max upload size (MB). |
--disable-header-check |
None | Disable host-header check. |
--hf-mirror |
None | Hugging Face mirror. |
--external-working-path / --output-path / --temp-path / --cache-path |
None | Path overrides. |
--in-browser / --disable-in-browser |
— | Auto-open browser. |
--gpu-device-id |
None | Select GPU (sets CUDA_VISIBLE_DEVICES). |
--all-in-fp32 / --all-in-fp16 |
— | Global precision. |
--unet-in-bf16 / --unet-in-fp16 / --unet-in-fp8-e4m3fn / --unet-in-fp8-e5m2 |
— | UNet precision. |
--vae-in-fp16 / --vae-in-fp32 / --vae-in-bf16 / --vae-in-cpu |
— | VAE precision/placement. |
--clip-in-fp8-e4m3fn / --clip-in-fp8-e5m2 / --clip-in-fp16 / --clip-in-fp32 |
— | Text-encoder precision. |
--attention-split / --attention-quad / --attention-pytorch |
— | Attention implementation. |
--disable-xformers |
— | Disable xformers. |
--always-gpu / --always-high-vram / --always-normal-vram / --always-low-vram / --always-no-vram / --always-cpu |
— | VRAM strategy. |
--always-offload-from-vram |
— | Force offload (Fooocus enables this by default unless --disable-offload-from-vram). |
--directml |
— | Use DirectML (Windows AMD/Intel). |
--disable-ipex-hijack |
— | Disable Intel IPEX hijack. |
--pytorch-deterministic |
— | Deterministic mode. |
--multi-user |
— | Storage scoping only (not parallel execution). |
--debug-mode / --disable-server-log / --disable-server-info |
— | Logging/diagnostics. |
Note
Fooocus sets
disable_cuda_malloc=True,in_browser=True, andport=Noneas defaults (inargs_manager.py), and computesalways_offload_from_vram = not --disable-offload-from-vram. The Gradio server port is7865(envGRADIO_SERVER_PORT), distinct from the backend's--portdefault of8188.
9. Model Management and Auto-Download
Fooocus downloads models lazily via modules/model_loader.py:load_file_from_url. Triggers and sources:
| Trigger | Function | Source (Hugging Face) |
|---|---|---|
| First run / preset model | download_models (launch.py) |
per-preset checkpoint_downloads (e.g. lllyasviel/fav_models, mashb1t/fav_models, stabilityai) |
| Prompt expansion | download_models |
lllyasviel/misc (fooocus_expansion.bin) |
| VAE approx (preview) | download_models |
lllyasviel/misc, mashb1t/misc |
| Inpaint | downloading_inpaint_models(v) |
lllyasviel/fooocus_inpaint (head + inpaint_v{1,25,26}.fooocus.patch) |
| ControlNet (Canny/CPDS) | downloading_controlnet_* |
lllyasviel/misc |
| Image Prompt / FaceSwap | downloading_ip_adapters(v) |
lllyasviel/misc (clip_vision, ip-adapter-plus) |
| Upscaler | downloading_upscale_model |
lllyasviel/misc |
| Safety checker | downloading_safety_checker_model |
mashb1t/misc |
| SAM masking | download_sam_model |
mashb1t/misc (vit_b/l/h) |
| Performance LoRAs | downloading_sdxl_{lcm,lightning,hyper_sd}_lora |
lllyasviel/misc, mashb1t/misc |
Caution
No checksum verification.
load_file_from_urldownloads by URL into the model folder; there is no signature or hash check on the downloaded weights. Combined with the globally-disabled TLS verification (see Security), this means model integrity depends entirely on the Hugging Face source and transport. For air-gapped or high-assurance deployments, pre-stage all models manually, verify hashes out of band, and run with--disable-preset-download.
Model file extensions recognized: .pth, .ckpt, .bin, .safetensors, .fooocus.patch. A hash cache (modules/hash_cache.py) indexes models/LoRAs; rebuild it with --rebuild-hash-cache.
10. Security Analysis
Fooocus is designed as a local, single-user, offline tool. Its defaults are appropriate for localhost use. Exposing it to a network or the internet substantially changes the risk picture. The items below are factual, source-derived, and (where noted) reference public community reports.
Network exposure
- By default the backend binds
127.0.0.1.--listen(with0.0.0.0) and--share(a public Gradio tunnel) expose the app. - There is no host-header check unless you consider
--disable-header-check; Gradio's own protections apply.
Authentication
modules/auth.pyimplements a minimal scheme: anauth.jsonfile (a list of{user, pass}or{user, hash}entries). Passwords are hashed with SHA-256 (no salt, no key-stretching).- Auth is only active if
auth.jsonexists; it gates the Gradio app when sharing. - The shipped
auth-example.jsoncontains the usersitting-duck-1/ passwordvery-bad-publicly-known-password-change-it— a deliberate placeholder.
Warning
If you expose Fooocus with
--shareor--listen, create a realauth.jsonwith strong credentials. SHA-256 without salting is weak against offline cracking if the file leaks — keepauth.jsonoff any world-readable path and never commit it.
TLS verification disabled globally
launch.py sets:
ssl._create_default_https_context = ssl._create_unverified_context
This disables certificate verification for all HTTPS in the process (model downloads, any outbound call). It exists to avoid corporate-proxy/cert headaches but means downloads are not protected against TLS man-in-the-middle.
Caution
For any hardened deployment, patch this out and verify model integrity by hash. Combined with the no-checksum model download, the unverified TLS context is the most significant supply-chain weakness in the default configuration.
Auto-update trust
entry_with_update.py fetches and hard-resets to origin on every launch. This means each run pulls and executes the latest upstream code. In a controlled environment, launch launch.py directly (not entry_with_update.py) to pin code to a reviewed commit, or run with the network restricted.
Known community-reported issues
| Report | Summary | Operator action |
|---|---|---|
| #4185 | Arbitrary code execution via eval(). |
Audit any eval/exec paths before exposing; restrict the OS account Fooocus runs under. |
| #4156 | Path traversal in get_annotated_filepath allowing arbitrary file reads. |
Do not expose an un-patched instance; run under a low-privilege account with a confined working directory. |
Important
These are publicly filed issues against a popular open-source project, not signs of malicious code. The mitigation is standard defense-in-depth: run Fooocus as an unprivileged user, in a container or jailed directory, never as root/Administrator, and never expose an instance directly to the internet without a reverse proxy, authentication, and the hardening above.
Content safety
- An optional NSFW safety checker (
extras/censor.py+stable-diffusion-safety-checker.bin) blacks out flagged images. Enable globally withdefault_black_out_nsfw: trueor per task.
Input handling
- The Image Prompt, Inpaint, Describe, and Metadata tabs all accept user-uploaded images and (for Metadata) parse embedded parameter strings. Treat uploads as untrusted;
--web-upload-sizecaps upload size.
11. Deployment
Single-instance (typical)
python launch.py --listen --port 7865 --always-normal-vram
Put it behind a reverse proxy (nginx/Traefik/Caddy) terminating TLS, and add authentication (auth.json plus, ideally, proxy-level auth).
Tip
Prefer
launch.pyoverentry_with_update.pyin production so the code does not auto-update from upstream on every restart. Pin your checkout to a reviewed commit.
Reverse proxy sketch (nginx)
location / {
proxy_pass http://127.0.0.1:7865;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade; # Gradio uses websockets
proxy_set_header Connection "upgrade";
proxy_read_timeout 600s; # long generations
}
Containerized / Colab
- The repo includes
entrypoint.sh(used by container/Colab templates) that symlinksmodelsandoutputsto a persistentDATADIRso weights survive container restarts, then runslaunch.py. environment.yamldefines a conda env (python=3.10) for reproducible builds.
Multi-GPU / multi-user
Run N instances, one per GPU:
python launch.py --gpu-device-id 0 --listen --port 7865 &
python launch.py --gpu-device-id 1 --listen --port 7866 &
Front them with a load balancer using sticky sessions (a generation streams progress over a persistent connection, so a user must stay pinned to one instance).
Deployment checklist
- [ ] Run as an unprivileged user, not root/Administrator.
- [ ] Confine the working directory; mount models read-only where possible.
- [ ] Create a strong
auth.json; never commit it. - [ ] Terminate TLS at a reverse proxy; do not rely on
--sharefor anything permanent. - [ ] Pre-stage and hash-verify models; consider
--disable-preset-download. - [ ] Launch
launch.py(pinned commit), notentry_with_update.py. - [ ] Set
default_black_out_nsfw: truefor shared instances. - [ ] Ensure adequate swap and ≥40 GB free disk per drive.
- [ ] Confirm PyTorch matches your GPU's compute capability.
12. Operations
Start / stop
- Start:
run.bat(Windows) orpython entry_with_update.py/python launch.py. - Stop: Ctrl-C the process. The single worker thread and Gradio server terminate with it.
Logs and outputs
- Generated images and an HTML session log are written under
outputs/(date-stamped). The History Log link in the UI opens it. - Console output is the primary diagnostic channel: it prints the resolved args (
[System ARGV]), version, model download progress, per-step progress ([Fooocus] ...), and total generation time. --debug-mode,--disable-server-log,--disable-server-infotune verbosity.
Temp management
temp_pathdefaults to the system temp/fooocus. Withtemp_path_cleanup_on_launch: true(default), Fooocus deletes its temp contents on each launch.
Backup
Back up these, none of which are auto-synced anywhere:
config.txtand any custompresets/*.jsonauth.jsonmodels/(large — or just record the source URLs)outputs/(your generated work + logs)wildcards/andsdxl_styles/if customized
Updating
- Default:
entry_with_update.pypulls on launch. - Manual:
git pull(or pin to a tag). After updating, re-test output on fixed seeds because of the backend-patch coupling described in §3.
Health check
A simple liveness check is an HTTP GET to the Gradio root on the configured port; a 200 means the server is up. There is no dedicated /health endpoint (Fooocus exposes no REST API — interaction is via Gradio's event protocol).
13. Repository Structure
Fooocus/
├── entry_with_update.py # Auto-update launcher (git fetch + reset → launch)
├── launch.py # Environment prep, model download, → webui
├── webui.py # Gradio Blocks UI + event wiring (~1500 lines)
├── args_manager.py # Fooocus CLI flags (extends backend parser)
├── shared.py # Global gradio_root handle
├── build_launcher.py # Writes run*.bat on Windows
├── fooocus_version.py # version = '2.5.5'
├── requirements_versions.txt
├── environment.yaml # conda env (python=3.10)
├── entrypoint.sh # container/Colab persistence + launch
├── config.txt # (generated) user config
├── modules/ # Fooocus orchestration layer (~29 files)
│ ├── async_worker.py # AsyncTask + the worker pipeline
│ ├── default_pipeline.py # diffusion orchestration
│ ├── config.py # the entire config system
│ ├── flags.py # enums: Performance, samplers, schedulers, ratios
│ ├── patch.py # core backend monkey-patches
│ ├── patch_clip.py # CLIP patches
│ ├── patch_precision.py # precision patches
│ ├── sample_hijack.py # sampling-loop hijack
│ ├── sdxl_styles.py # style loading + application
│ ├── inpaint_worker.py # inpaint/outpaint engine
│ ├── upscaler.py # upscaling
│ ├── meta_parser.py # metadata read/write (fooocus + a1111)
│ ├── private_logger.py # image saving + HTML log
│ ├── auth.py # SHA-256 auth file
│ ├── model_loader.py # load_file_from_url (downloads)
│ ├── lora.py, core.py, util.py, html.py, localization.py, ...
├── ldm_patched/ # Vendored ComfyUI backend (monkey-patched)
│ ├── modules/ # model_management, samplers, sd, args_parser, ...
│ ├── ldm/ # latent diffusion model
│ ├── k_diffusion/, unipc/, controlnet/, t2ia/, taesd/, pfn/, utils/
├── extras/ # Auxiliary ML: BLIP, GroundingDINO, SAM, facexlib,
│ # censor, expansion, interrogate, ip_adapter, preprocessors
├── presets/ # default/anime/realistic/lcm/lightning/pony_v6/sai/...
├── sdxl_styles/ # JSON style packs (fooocus, sai, mre, twri, diva, ...)
├── wildcards/ # Wildcard text files
├── language/ # UI translation JSON
├── models/ # (populated at runtime; mostly empty placeholders)
├── javascript/ css/ # Frontend assets injected into Gradio
└── fooocus_colab.ipynb # Colab notebook
14. Module Reference
Orchestration (modules/)
| Module | Responsibility |
|---|---|
async_worker.py |
Defines AsyncTask (unpacks ~80 positional UI args into named fields) and the background worker() that runs the full pipeline: prompt processing, goals (vary/upscale/inpaint/cn/enhance), diffusion, censor, save/log. Calls patch_all() at import. |
default_pipeline.py |
Loads/refreshes base+refiner+LoRA+VAE, CLIP encoding, process_diffusion, candidate-VAE selection, expansion. The Fooocus "brain" over the backend. |
config.py |
The complete config system: defaults, validators, env/CLI/file/preset precedence, path resolution, and all downloading_* model fetchers. |
flags.py |
Enums and lists: Performance (+ Steps, StepsUOV, PerformanceLoRA), sampler/scheduler names, aspect ratios, ControlNet types, inpaint options/engines, mask models, metadata schemes, output formats. |
patch.py / patch_clip.py / patch_precision.py / sample_hijack.py |
Runtime monkey-patches over ldm_patched and libraries. PatchSettings holds per-PID sharpness/ADM/CFG. |
sdxl_styles.py |
Loads style JSON packs, normalizes names, applies styles ({prompt} placeholder), wildcard arrays ([[...]]). |
inpaint_worker.py |
The Fooocus-specific inpaint/outpaint algorithm and latent patching. |
upscaler.py |
perform_upscale (ESRGAN-style upscaler). |
meta_parser.py |
Reads/writes generation metadata in fooocus (JSON) and a1111 (plain-text) schemes. |
private_logger.py |
Saves images, embeds metadata, maintains the HTML history log. |
auth.py |
auth.json loading + SHA-256 password check. |
model_loader.py |
load_file_from_url — the download primitive (no checksum). |
launch_util.py |
pip/install helpers, requirements_met, subprocess run. |
hash_cache.py |
Model/LoRA hash index. |
localization.py |
language/*.json UI translation. |
gradio_hijack.py / ui_gradio_extensions.py |
Custom gr.Image component and JS/CSS injection. |
Backend (ldm_patched/)
A vendored ComfyUI fork. Key subpackages: modules/ (model_management, samplers, sd, model_patcher, args_parser, ops, sd1_clip), ldm/ (latent diffusion + attention + diffusion modules), k_diffusion/ (sampling), unipc/ (UniPC sampler), controlnet/cldm (ControlNet), t2ia/ (T2I-Adapter), taesd/ (tiny autoencoder previews), pfn/ (upscaler architectures). See §3 for the patching relationship.
Extras (extras/)
Auxiliary ML used by specific features: BLIP + wd14tagger/interrogate (Describe), GroundingDINO + sam + inpaint_mask (text-prompted masking), facexlib + face_crop (FaceSwap), ip_adapter (Image Prompt), preprocessors (Canny/CPDS), censor (NSFW), expansion (Fooocus V2 GPT-2 prompt expansion).
15. Code Quality and Patterns
Strengths
- Clear three-layer separation (UI / orchestration / backend) keeps Fooocus logic out of the vendored engine.
- Centralized, validated configuration. Every config key passes through a validator with a typed default, and the precedence chain is consistent. The auto-generated
config_modification_tutorial.txtis good operator UX. - Opinionated defaults encode substantial domain knowledge (per-preset CFG, styles, ADM guidance) so users get good results without tuning.
- Pinned dependencies make environments reproducible.
Patterns and risks
- Positional arg coupling (high-risk).
webui.pypacks ~80 UI control values into a list in a fixed order, andAsyncTask.__init__pops them in exactly that order. There is no named-key contract. Any insertion/removal in either file that isn't mirrored in the other silently misaligns every downstream parameter. This is the most fragile seam in the codebase. - Monkey-patch coupling to the vendored backend (high-risk). See §3. Quality regressions can be silent.
- Module-import side effects. Importing
async_workertriggerspatch_all(); importingconfigwrites files and can prompt interactively (deprecated-config migration). Import order matters. - Disabled TLS verification and unchecked downloads (see §10).
- Large monolith files.
webui.pyandasync_worker.pyare each ~1500 lines with deeply nested closures; readable but hard to unit-test in isolation.
Note
The
extras/ML helpers (BLIP, GroundingDINO, facexlib) are themselves vendored third-party code with their own licenses (the repo bundles manyLICENSEfiles, mostly Apache-2.0). Track these for license compliance if you redistribute.
16. Potential Improvements
These are observations for maintainers/forkers, derived from the source:
- Replace positional
AsyncTaskpacking with a dataclass / named dict. Eliminates the §15 misalignment hazard and makes the parameter contract explicit and testable. - Add checksum/signature verification to
load_file_from_url. Pair each download URL with an expected SHA-256 in the preset JSON and verify after download. - Remove the global
ssl._create_unverified_contextoverride or scope it narrowly; rely on proper CA handling with an opt-in escape hatch. - Decouple from PyTorch 2.1.0. Detect GPU compute capability at install time and select a compatible torch build automatically, reducing the dominant class of "won't start on new GPUs" issues.
- Provide a pinned-commit production launcher as a first-class, documented path (today operators must know to avoid
entry_with_update.py). - A backend-patch regression harness (fixed-seed image diffs) shipped in
tests/would make backend upgrades safe. - Salt the auth hashes and document a secure credential workflow for exposed deployments.
17. Quick Reference
Entry points
| File | Use |
|---|---|
entry_with_update.py |
Default launcher; auto-updates from origin. |
launch.py |
Direct launcher; no auto-update (prefer in production). |
run.bat / run_anime.bat / run_realistic.bat |
Windows package launchers (preset editions). |
Key paths
| Path | Contents |
|---|---|
config.txt |
User config (JSON). |
presets/*.json |
Editions. |
auth.json |
Credentials (SHA-256). |
models/<type>/ |
Weights (downloaded). |
outputs/ |
Images + HTML logs. |
sdxl_styles/*.json |
Style packs. |
wildcards/*.txt |
Wildcards. |
language/*.json |
UI translations. |
Critical environment variables
TORCH_COMMAND, TORCH_INDEX_URL (override torch), HF_MIRROR (model mirror), GRADIO_SERVER_PORT (default 7865), config_path (config location).
Performance ↔ steps ↔ LoRA
| Performance | Steps | UOV steps | LoRA |
|---|---|---|---|
| Quality | 60 | 36 | — |
| Speed | 30 | 18 | — |
| Extreme Speed | 8 | 8 | LCM |
| Lightning | 4 | 4 | SDXL-Lightning |
| Hyper-SD | 4 | 4 | Hyper-SD |
Default ports
| Service | Port |
|---|---|
| Gradio UI | 7865 (GRADIO_SERVER_PORT) |
Backend --port default |
8188 |
Hardening one-liner (exposed instance)
# unprivileged user, pinned code, real auth, NSFW filter on, no preset auto-download
python launch.py --listen --port 7865 --disable-preset-download
# + config.txt: "default_black_out_nsfw": true
# + auth.json with strong credentials, behind a TLS reverse proxy