# OpenList + Iron Local Deployment SOP This SOP is for a single-machine deployment where: - OpenList runs locally and mounts Aliyun Drive - OpenList exposes WebDAV - Iron runs locally and uses OpenList WebDAV as a remote backend - Iron also keeps its built-in local backend for local reads and recovery The result is: ```text Aliyun Drive -> OpenList mount -> OpenList WebDAV -> Iron WebDAV backend -> Iron file namespace + policies + replicas ``` ## 1. What This SOP Assumes - You want a practical local deployment first, not a public Internet deployment. - OpenList is used as the cloud-drive access layer. - Iron is used as the file namespace, replica policy, and repair layer. - Aliyun Drive data used by Iron should stay inside a dedicated folder, not the cloud-drive root. This SOP uses: - OpenList on `127.0.0.1:5244` - Iron on `127.0.0.1:8000` - Docker for OpenList - local Python + `uv` for Iron Repository deployment assets used in this SOP: - `deploy/openlist/docker-compose.yml` - `deploy/openlist/.env.example` - `deploy/iron/iron.env.example` - `deploy/iron/start_iron.sh` - `deploy/systemd/iron.service.example` OpenList also supports manual installation if you prefer not to use Docker. ## 2. Prerequisites Prepare these first: - Docker - Python 3.11+ - Node.js 20+ - `uv` - a local checkout of this repository Recommended local ports: - `5244` for OpenList - `8000` for Iron ## 3. Recommended Directory Layout Create a deployment working directory outside the Git repo for runtime data: ```bash mkdir -p ~/iron-deploy/openlist mkdir -p ~/iron-deploy/iron-data mkdir -p ~/iron-deploy/iron-temp mkdir -p ~/iron-deploy/iron-cache ``` Recommended meaning: - `~/iron-deploy/openlist`: OpenList runtime data - `~/iron-deploy/iron-data`: Iron local storage root - `~/iron-deploy/iron-temp`: Iron upload temp files - `~/iron-deploy/iron-cache`: Iron remote-read cache ## 4. Install And Start OpenList This SOP uses Docker Compose because it is the shortest path to a repeatable local deployment. Prepare the OpenList env file: ```bash mkdir -p ~/iron-deploy/openlist cp deploy/openlist/.env.example deploy/openlist/.env ``` Edit `deploy/openlist/.env` and set: - `OPENLIST_BIND_HOST=127.0.0.1` - `OPENLIST_PORT=5244` - `OPENLIST_DATA_DIR=$HOME/iron-deploy/openlist` Start OpenList: ```bash docker compose -f deploy/openlist/docker-compose.yml --env-file deploy/openlist/.env up -d ``` Check logs: ```bash docker compose -f deploy/openlist/docker-compose.yml logs -f ``` On first start, OpenList prints the initial admin password in the logs. Open the admin UI: ```text http://127.0.0.1:5244 ``` Log in with the OpenList admin account shown on first boot, then immediately change it to a password you control. ## 5. Create An OpenList User For Iron Do not let Iron use the OpenList admin account. In OpenList: 1. go to `Users` 2. create a dedicated user, for example `iron` 3. give it a strong password 4. enable the permissions needed for WebDAV write access For Iron write access through WebDAV, enable at least: - `Webdav Read` - `Webdav Manage` - `Make dir or upload` - `Delete` - `Rename` - `Move` - `Copy` Without these, Iron health checks may pass partially but upload or directory creation can fail. ## 6. Prepare A Dedicated Aliyun Drive Folder Create a dedicated folder in Aliyun Drive for Iron, for example: ```text IronGateway ``` Do not mount the whole cloud-drive root for Iron unless you explicitly want that. OpenList supports mounting a specific Aliyun folder by `Root Folder ID`. The OpenList Aliyundrive Open docs describe using `root` for the drive root, or a folder `file_id` if you only want a specific folder exposed. Recommended approach: 1. create `IronGateway` in Aliyun Drive 2. open that folder in the Aliyun Drive Web UI 3. copy the folder `file_id` from the URL 4. use that `file_id` as the OpenList `Root Folder ID` That gives you one isolation layer in OpenList. Later, Iron will also use its own `root_path` inside that mount, giving you a second isolation layer. ## 7. Mount Aliyun Drive In OpenList In OpenList: 1. go to `Storage` 2. click `Add Storage` 3. choose driver `AliYun Drive (Oauth2)` / `Aliyundrive Open` 4. set mount path to something stable, for example: ```text /aliyun-iron ``` 5. set `Root Folder ID` to the dedicated Aliyun folder `file_id` 6. fill the refresh token from the OpenList Aliyundrive Open authorization flow 7. save the storage Important notes from the OpenList docs: - normal users can leave `Client ID` and `Secret` blank and use the values provided by OpenList - the refresh token used here must come from the Aliyundrive Open flow intended for OpenList - the docs warn about request rate limiting and advise not to abuse the API Operational note: This means the current local-operator path does not require your own Aliyun developer app. That is based on the latest OpenList docs and may change if OpenList or Aliyun changes upstream behavior. ## 8. Verify OpenList WebDAV Before Touching Iron OpenList exposes WebDAV at: ```text http://127.0.0.1:5244/dav/ ``` Before configuring Iron, verify all three things: 1. the `iron` OpenList user can log in 2. the mounted path `/aliyun-iron` is visible in the OpenList Web UI 3. the `iron` user has WebDAV write permissions The practical target for Iron is: ```text http://127.0.0.1:5244/dav ``` Iron will then use `root_path` to place its own dedicated subtree under the OpenList mount. ## 9. Install Iron From the repository root: ```bash UV_CACHE_DIR=.uv-cache uv venv .venv UV_CACHE_DIR=.uv-cache uv pip install --python .venv/bin/python -e '.[dev]' npm install npm run build ``` Apply database migrations: ```bash ./.venv/bin/alembic upgrade head ``` ## 10. Configure Iron Runtime Environment Iron reads configuration from environment variables. For repeatable deployment, use the provided env template instead of one-off shell exports. Create the runtime directories and env file: ```bash mkdir -p ~/iron-deploy/runtime/temp mkdir -p ~/iron-deploy/runtime/local mkdir -p ~/iron-deploy/runtime/cache cp deploy/iron/iron.env.example deploy/iron/iron.env ``` Edit `deploy/iron/iron.env` and set: ```bash IRON_DATABASE_URL="sqlite+aiosqlite:////Users/your-user/iron-deploy/iron.db" IRON_BOOTSTRAP_USERNAME="admin" IRON_BOOTSTRAP_PASSWORD="replace-this-now" IRON_SECRET_KEY="replace-with-a-long-random-stable-secret" IRON_UPLOAD_TEMP_DIR="/Users/your-user/iron-deploy/runtime/temp" IRON_LOCAL_STORAGE_DIR="/Users/your-user/iron-deploy/runtime/local" IRON_CACHE_DIR="/Users/your-user/iron-deploy/runtime/cache" IRON_JOB_POLL_INTERVAL_SECONDS="2" IRON_JOB_BATCH_SIZE="10" ``` Important: - `IRON_SECRET_KEY` must be stable after deployment begins, or stored backend passwords become unreadable. - the bootstrap user is only auto-created when the database has no users yet - changing `IRON_BOOTSTRAP_PASSWORD` later does not rotate the existing account password ## 11. Start Iron Start the service: ```bash ./deploy/iron/start_iron.sh ``` Open: ```text http://127.0.0.1:8000/app ``` Log in with: - username: `IRON_BOOTSTRAP_USERNAME` - password: `IRON_BOOTSTRAP_PASSWORD` Health endpoints: ```text http://127.0.0.1:8000/api/system/health http://127.0.0.1:8000/api/system/ready ``` For a background service on Linux, adapt `deploy/systemd/iron.service.example` into `/etc/systemd/system/iron.service`. ## 12. Confirm The Built-In Local Backend On first startup, Iron auto-creates the default local backend: - name: `local-default` - type: `Local Directory` - policy class: `Local` Keep this enabled. This is the local durable copy that gives you: - fast reads - local recovery - a safe fallback if OpenList or Aliyun is temporarily unavailable ## 13. Add OpenList As A WebDAV Backend In Iron In Iron: 1. open `Storage` 2. click `Add Backend` 3. choose `OpenList / WebDAV` 4. use a stable backend name, for example `openlist-aliyun` 5. choose policy class `Stable` 6. use read and write priority appropriate for your setup, for example `80` Use config JSON like this: ```json { "endpoint_url": "http://127.0.0.1:5244/dav", "username": "iron", "password": "your-openlist-iron-password", "root_path": "aliyun-iron/iron-data", "verify_ssl": false } ``` Meaning: - `endpoint_url`: OpenList WebDAV root - `username` / `password`: the dedicated OpenList user created for Iron - `root_path`: Iron's dedicated subtree - `verify_ssl`: `false` only because this SOP uses local plain HTTP; use `true` when you switch to HTTPS Recommended path layering: ```text Aliyun folder: IronGateway OpenList mount path: /aliyun-iron Iron root_path: aliyun-iron/iron-data ``` This keeps Iron away from both: - the Aliyun drive root - the rest of the OpenList namespace After saving, click `Run Check`. Expected result: - status becomes `Healthy` - detail points to the configured WebDAV path ## 14. Configure Replica Policies Open `Policies` in Iron and configure at least these defaults: Recommended first production baseline: - `Require local replica = on` - `Stable replicas = 1` - `Opportunistic replicas = 0` Interpretation: - Iron's default target is 2 total replicas - every file keeps one local copy - every file also gets one stable remote copy on OpenList/Aliyun For each file class (`document`, `image`, `video`, `other`): 1. save the policy 2. confirm the OpenList backend is not excluded 3. keep the local backend available Saving a policy automatically enqueues a full reconcile job. ## 15. First End-To-End Acceptance Test Use this exact sequence: 1. in Iron, upload a small text file 2. open the file detail drawer and check the `Storage` tab 3. confirm the desired backend list includes: - local backend - OpenList WebDAV backend 4. wait for the replica to become ready, or go to `Jobs` and run pending jobs 5. in OpenList, browse the mount path and confirm the file exists under: ```text /aliyun-iron/iron-data/... ``` 6. in Aliyun Drive, verify the file appears under the dedicated `IronGateway` folder Expected outcome: - Iron can upload locally - Iron can replicate to OpenList WebDAV - OpenList writes into the dedicated Aliyun subtree After the first manual upload check, run the real acceptance suite: ```bash ./.venv/bin/python scripts/real_openlist_suite.py ``` Useful focused runs: ```bash ./.venv/bin/python scripts/real_openlist_acceptance.py ./.venv/bin/python scripts/real_openlist_chaos_acceptance.py ./.venv/bin/python scripts/real_openlist_multi_backend_acceptance.py ./.venv/bin/python scripts/real_openlist_multi_backend_chaos.py ``` The suite covers: - baseline upload, reconcile, download, and direct WebDAV read - large-file range reads - forced remote recovery after local file deletion - OpenList stop/start recovery - multi-backend placement, avoidance, re-enable, and replica healing - recycle-bin delete and restore with replica validation Current remote object layout note: - Iron stores backend replicas under a structured application object tree such as `objects/file/sha256/73/35/.blob` - this is intentional application storage layout, not an attempt to disguise replicas as user-authored media files - keep Iron inside a dedicated OpenList mount subtree rather than mixing it with personal root folders - because the project is still in active development, this layout is treated as the current source of truth rather than a backward-compatible migration target - reserved subtrees include `objects/preview/...`, `objects/export/metadata/...`, and `objects/manifest/...` for future generated artifacts and control files ## 16. What To Check If It Fails ### OpenList backend check fails in Iron Check: - OpenList is reachable on `127.0.0.1:5244` - WebDAV URL is exactly `/dav` - the OpenList `iron` user password is correct - WebDAV permissions include write-related permissions - `root_path` starts with the OpenList mount path, for example `aliyun-iron/iron-data` ### Iron uploads succeed locally but remote replica never appears Check: - `Jobs` page for failed reconcile or replication jobs - OpenList user permissions - placement policy excludes or preferred backend settings - whether the WebDAV backend is enabled ### Files land in the wrong Aliyun location Check: - OpenList `Root Folder ID` - OpenList mount path - Iron `root_path` Usually this is a path-scoping mistake, not a storage corruption issue. ## 17. Recommended Ongoing Operations For a stable local deployment: 1. keep OpenList and Iron on localhost unless you add a reverse proxy and auth hardening 2. keep `IRON_SECRET_KEY` unchanged 3. back up: - `iron.db` - `~/iron-deploy/openlist` - `~/iron-deploy/runtime/local` - `~/iron-deploy/runtime/cache` 4. run backend health checks from the Iron `Storage` page after OpenList upgrades 5. review the Iron `Jobs` page when replicas lag or a cloud drive is rate-limited ## 18. Source References - OpenList install guide: [docs.openlist.team/guide/install](https://docs.openlist.team/guide/install/) - OpenList manual install guide: [docs.openlist.team/guide/install/manual](https://docs.openlist.team/guide/install/manual) - OpenList WebDAV guide: [docs.openlist.team/guide/webdav](https://docs.openlist.team/guide/webdav) - OpenList Aliyundrive Open guide: [doc.openlist.team/guide/drivers/aliyundrive_open](https://doc.openlist.team/guide/drivers/aliyundrive_open) - Iron quick start and env vars: [README](../README.md) - Iron API backend types and WebDAV notes: [API](api.md) - Iron storage architecture notes: [Architecture](architecture.md)