# Environment variables — full reference qiming-file-server can be configured entirely through environment variables. This document lists every supported variable. ## Precedence From highest to lowest: 1. **CLI arguments** 2. **Process environment variables** 3. **Env files** (`.env.production`, `.env.development`, `.env.test` — loaded according to project conventions; see `src/env.*`) 4. **Built-in defaults** ## Env files Files under `src/` are selected based on `NODE_ENV`: | Mode | File | Purpose | | ---- | ---- | ------- | | development | `env.development` | Local development | | production | `env.production` | Production | | test | `env.test` | Tests | ## Core settings ### Server | Variable | Default | Description | | -------- | ------- | ----------- | | `NODE_ENV` | `development` | `development` / `production` / `test` | | `PORT` | `60000` | HTTP listen port | | `REQUEST_BODY_LIMIT` | `2000mb` | Express body size limit | ### Logging | Variable | Default | Description | | -------- | ------- | ----------- | | `LOG_BASE_DIR` | — | Base directory for log files | | `LOG_LEVEL` | `debug` | `error` / `warn` / `info` / `debug` | | `LOG_CONSOLE_ENABLED` | `true` | Mirror logs to console | | `LOG_PREFIX_API` | `api` | Prefix for API logs | | `LOG_PREFIX_BUILD` | `build` | Prefix for build logs | ### Project paths | Variable | Default | Description | | -------- | ------- | ----------- | | `INIT_PROJECT_NAME_REACT` | `react-vite-template` | Built-in scaffold name for React projects | | `INIT_PROJECT_NAME_VUE3` | `vue3-vite-template` | Built-in scaffold name for Vue3 projects | | `INIT_PROJECT_DIR` | — | Scaffold / init project directory | | `UPLOAD_PROJECT_DIR` | — | Directory for uploaded project archives | | `PROJECT_SOURCE_DIR` | — | Unpacked / working project sources | | `DIST_TARGET_DIR` | — | Build output directory (e.g. served by nginx) | | `COMPUTER_WORKSPACE_DIR` | — | “Computer” feature workspace | | `COMPUTER_LOG_DIR` | — | “Computer” feature logs | ### Build | Variable | Default | Description | | -------- | ------- | ----------- | | `MAX_BUILD_CONCURRENCY` | `20` | Max concurrent builds | | `DEV_SERVER_PORT_TIMEOUT` | `5000` | Dev-server port probe timeout (ms) | | `DEV_SERVER_STOP_TIMEOUT` | `5000` | Dev-server stop timeout (ms) | | `DEV_SERVER_STOP_CHECK_INTERVAL` | `100` | Poll interval while stopping dev server (ms) | | `DEV_SERVER_STOP_MAX_ATTEMPTS` | `50` | Max stop retries | ### Uploads | Variable | Default | Description | | -------- | ------- | ----------- | | `MAX_INLINE_FILE_SIZE_BYTES` | `1048576` | Max size (bytes) to return inline; larger files are not inlined | | `UPLOAD_MAX_FILE_SIZE_BYTES` | `1048576000` | Max archive upload size (bytes) | | `UPLOAD_ALLOWED_EXTENSIONS` | `.zip` | Allowed extensions (comma-separated) | | `UPLOAD_SINGLE_FILE_SIZE_BYTES` | `1048576000` | Max single upload size (bytes) | ### Traversal / filters | Variable | Default | Description | | -------- | ------- | ----------- | | `TRAVERSE_EXCLUDE_DIRS` | `dist,node_modules,.pnpm-store,__MACOSX,.attachments` | Comma-separated dirs to skip when traversing | | `BACKUP_TRAVERSE_EXCLUDE_FILES` | `pnpm-lock.yaml,yarn.lock,package-lock.json` | Comma-separated files to skip in backup traversal | | `CONTENT_TRAVERSE_EXCLUDE_FILES` | `AGENT.md,AGENTS.md,CLAUDE.md,pnpm-lock.yaml,yarn.lock,package-lock.json` | Comma-separated files to skip for content API | | `INLINE_IMAGE_EXTENSIONS` | `.png,.jpg,.jpeg,.gif,.bmp,.svg,.ico,.webp,.avif` | Image extensions eligible for inline serving | | `TOP_LEVEL_NOISE_PATTERNS` | `__MACOSX,Thumbs.db,node_modules,.pnpm-store,.attachments` | Comma-separated noise patterns for top-level flattening after unzip | ### pnpm prune scheduler | Variable | Default | Description | | -------- | ------- | ----------- | | `PNPM_PRUNE_ENABLED` | `true` | Enable scheduled `pnpm store` maintenance | | `PNPM_PRUNE_SCHEDULE` | `0 2 * * *` | Cron expression | | `PNPM_PRUNE_TIMEZONE` | `Asia/Shanghai` | Time zone for the schedule | | `PNPM_PRUNE_RUN_ON_START` | `false` | Run once immediately on startup | **Example cron expressions:** | Expression | Meaning | | ---------- | ------- | | `0 2 * * 0` | Every Sunday 02:00 | | `0 3 * * *` | Every day 03:00 | | `0 2 1 * *` | 1st of month 02:00 | | `0 */6 * * *` | Every 6 hours | ### Log cache | Variable | Default | Description | | -------- | ------- | ----------- | | `LOG_CACHE_ENABLED` | `true` | Enable in-memory log cache | | `LOG_CACHE_DURATION` | `180000` | TTL (ms); default 3 minutes | | `LOG_CACHE_MAX_ENTRIES` | `100` | Max cached entries | | `LOG_CACHE_MAX_FILE_SIZE` | `2097152` | Max cached file size (bytes); default 2 MB | ### CLI-only | Variable | Default | Description | | -------- | ------- | ----------- | | `CLI_PID_DIR` | system temp | Directory for PID file | | `CLI_PID_FILE` | `server.pid` | PID filename | | `CLI_STOP_TIMEOUT` | `30000` | Graceful stop timeout (ms) | | `CLI_CHECK_INTERVAL` | `500` | Poll interval when stopping (ms) | | `CLI_LOG_DIR` | system temp | CLI log directory | ## Extra CLI environment | Variable | Description | | -------- | ----------- | | `CONFIG_FILE` | Optional path to an extra env file (CLI) | ## Examples ### Use production defaults but override paths In real deployments you often keep `env.production` as the base and only override paths: #### Example A: production + custom paths ```bash qiming-file-server start \ --env production \ --port 60000 \ PROJECT_SOURCE_DIR=/data/my-projects \ DIST_TARGET_DIR=/var/www/my-app \ UPLOAD_PROJECT_DIR=/data/uploads \ LOG_BASE_DIR=/var/log/qiming ``` #### Example B: multiple instances on one host ```bash # Instance 1 — main qiming-file-server start \ --env production \ --port 60001 \ PROJECT_SOURCE_DIR=/data/main-site \ DIST_TARGET_DIR=/var/www/main-site # Instance 2 — staging qiming-file-server start \ --env production \ --port 60002 \ PROJECT_SOURCE_DIR=/data/test-site \ DIST_TARGET_DIR=/var/www/test-site # Instance 3 — internal qiming-file-server start \ --env production \ --port 60003 \ PROJECT_SOURCE_DIR=/data/internal \ DIST_TARGET_DIR=/var/www/internal ``` > Only pass `--port` and the paths you need; everything else comes from `env.production`. #### Example C: override file ```bash cat > env.override << 'EOF' # Path overrides for production PROJECT_SOURCE_DIR=/data/override-projects DIST_TARGET_DIR=/var/www/override-nginx UPLOAD_PROJECT_DIR=/data/override-uploads LOG_BASE_DIR=/var/log/override EOF qiming-file-server start --env production --env-file ./env.override ``` #### Example D: Kubernetes ConfigMap ```bash kubectl create configmap qiming-overrides \ --from-literal=PROJECT_SOURCE_DIR=/data/k8s-projects \ --from-literal=DIST_TARGET_DIR=/usr/share/nginx/apps \ --from-literal=UPLOAD_PROJECT_DIR=/data/k8s-uploads \ --from-literal=LOG_BASE_DIR=/var/log/qiming ``` Reference it in the Deployment: ```yaml envFrom: - configMapRef: name: qiming-overrides ``` #### Example E: full path set (illustrative) Below lists path-related variables you might set. Trim to what you actually need: ```bash # Production with defaults from env.production, paths overridden qiming-file-server start \ --env production \ --port 60000 # Or set paths explicitly qiming-file-server start \ --env production \ --port 60000 \ INIT_PROJECT_NAME_REACT=react-vite-template \ INIT_PROJECT_NAME_VUE3=vue3-vite-template \ INIT_PROJECT_DIR=/app/project_init \ UPLOAD_PROJECT_DIR=/app/project_zips \ PROJECT_SOURCE_DIR=/app/project_workspace \ DIST_TARGET_DIR=/app/project_nginx \ LOG_BASE_DIR=/app/logs/project_logs \ COMPUTER_WORKSPACE_DIR=/app/computer-project-workspace \ COMPUTER_LOG_DIR=/app/logs/computer_logs ``` #### Path variables as documented for `env.production` | Variable | Example default | Description | | -------- | --------------- | ----------- | | `INIT_PROJECT_NAME_REACT` | `react-vite-template` | Built-in scaffold name for React projects | | `INIT_PROJECT_NAME_VUE3` | `vue3-vite-template` | Built-in scaffold name for Vue3 projects | | `INIT_PROJECT_DIR` | `/app/project_init` | Init project directory | | `UPLOAD_PROJECT_DIR` | `/app/project_zips` | Uploaded zips | | `PROJECT_SOURCE_DIR` | `/app/project_workspace` | Project workspace | | `DIST_TARGET_DIR` | `/app/project_nginx` | Build output (nginx root) | | `LOG_BASE_DIR` | `/app/logs/project_logs` | Log root | | `COMPUTER_WORKSPACE_DIR` | `/app/computer-project-workspace` | Computer workspace | | `COMPUTER_LOG_DIR` | `/app/logs/computer_logs` | Computer logs | #### Path-only snippets ```bash # 1) Only change project sources qiming-file-server start \ --env production \ --port 60000 \ PROJECT_SOURCE_DIR=/data/my-projects # 2) Several paths qiming-file-server start \ --env production \ --port 60000 \ PROJECT_SOURCE_DIR=/data/projects \ DIST_TARGET_DIR=/var/www/html \ UPLOAD_PROJECT_DIR=/data/uploads # 3) Full path set qiming-file-server start \ --env production \ --port 60000 \ INIT_PROJECT_NAME_REACT=my-react-template \ INIT_PROJECT_NAME_VUE3=my-vue3-template \ INIT_PROJECT_DIR=/data/init \ UPLOAD_PROJECT_DIR=/data/zips \ PROJECT_SOURCE_DIR=/data/workspace \ DIST_TARGET_DIR=/var/www/nginx \ LOG_BASE_DIR=/var/logs/project_logs \ COMPUTER_WORKSPACE_DIR=/data/computer \ COMPUTER_LOG_DIR=/var/logs/computer ``` > `--port` selects the HTTP port; unset path keys keep their values from `env.production`. #### Verify overrides ```bash qiming-file-server status curl http://localhost:60000/health | jq # Check startup logs for loaded env (messages are in English, e.g. "Loaded environment files: ...") grep -E "Loaded environment|Environment configuration file" /var/log/qiming/server.log ``` ### CLI overrides precedence CLI wins over env files and plain env: ```bash qiming-file-server start --port 8080 qiming-file-server start --env production qiming-file-server start --env production --port 8080 ``` ### Shell environment #### Linux / macOS ```bash export PORT=8080 export NODE_ENV=production export LOG_LEVEL=info # Persist in ~/.bashrc or ~/.zshrc echo 'export PORT=8080' >> ~/.bashrc source ~/.bashrc ``` #### Windows ```cmd set PORT=8080 set NODE_ENV=production setx PORT 8080 setx NODE_ENV production ``` ### Docker / Compose #### docker-compose.yml ```yaml version: '3.8' services: qiming-file-server: image: qiming-file-server:latest container_name: qiming-file-server restart: unless-stopped environment: - NODE_ENV=production - PORT=60000 - LOG_BASE_DIR=/app/logs - LOG_LEVEL=info - LOG_CONSOLE_ENABLED=false - PROJECT_SOURCE_DIR=/app/projects - DIST_TARGET_DIR=/app/nginx - UPLOAD_PROJECT_DIR=/app/uploads - INIT_PROJECT_DIR=/app/init - COMPUTER_WORKSPACE_DIR=/app/computer - COMPUTER_LOG_DIR=/app/computer-logs - MAX_BUILD_CONCURRENCY=20 - PNPM_PRUNE_ENABLED=true - PNPM_PRUNE_SCHEDULE=0 3 * * * - PNPM_PRUNE_TIMEZONE=Asia/Shanghai - LOG_CACHE_ENABLED=true - LOG_CACHE_DURATION=180000 - LOG_CACHE_MAX_ENTRIES=100 - LOG_CACHE_MAX_FILE_SIZE=2097152 volumes: - ./projects:/app/projects - ./logs:/app/logs - ./nginx:/app/nginx - ./uploads:/app/uploads - ./init:/app/init - ./computer:/app/computer ports: - "60000:60000" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:60000/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s ``` #### Dockerfile ```dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm install -g pnpm && pnpm install --frozen-lockfile COPY . . RUN mkdir -p /app/logs /app/projects /app/nginx /app/uploads /app/init /app/computer EXPOSE 60000 CMD ["node", "scripts/start-cli.js"] ``` ### Sample env files #### .env.production ```bash # ==================== Server ==================== NODE_ENV=production PORT=60000 REQUEST_BODY_LIMIT=2000mb # ==================== Logging ==================== LOG_BASE_DIR=/app/logs LOG_LEVEL=info LOG_CONSOLE_ENABLED=false LOG_PREFIX_API=api LOG_PREFIX_BUILD=build # ==================== Paths ==================== INIT_PROJECT_NAME_REACT=react-vite-template INIT_PROJECT_NAME_VUE3=vue3-vite-template INIT_PROJECT_DIR=/app/project_init UPLOAD_PROJECT_DIR=/app/project_zips PROJECT_SOURCE_DIR=/app/project_workspace DIST_TARGET_DIR=/app/project_nginx COMPUTER_WORKSPACE_DIR=/app/computer-project-workspace COMPUTER_LOG_DIR=/app/logs/computer_logs # ==================== Build ==================== MAX_BUILD_CONCURRENCY=20 DEV_SERVER_PORT_TIMEOUT=5000 DEV_SERVER_STOP_TIMEOUT=5000 DEV_SERVER_STOP_CHECK_INTERVAL=100 DEV_SERVER_STOP_MAX_ATTEMPTS=50 # ==================== Uploads ==================== MAX_INLINE_FILE_SIZE_BYTES=1048576 UPLOAD_MAX_FILE_SIZE_BYTES=1048576000 UPLOAD_ALLOWED_EXTENSIONS=.zip UPLOAD_SINGLE_FILE_SIZE_BYTES=1048576000 # ==================== Traversal / filters ==================== TRAVERSE_EXCLUDE_DIRS=dist,node_modules,.pnpm-store,__MACOSX,.attachments BACKUP_TRAVERSE_EXCLUDE_FILES=pnpm-lock.yaml,yarn.lock,package-lock.json CONTENT_TRAVERSE_EXCLUDE_FILES=AGENT.md,AGENTS.md,CLAUDE.md,pnpm-lock.yaml,yarn.lock,package-lock.json INLINE_IMAGE_EXTENSIONS=.png,.jpg,.jpeg,.gif,.bmp,.svg,.ico,.webp,.avif TOP_LEVEL_NOISE_PATTERNS=__MACOSX,Thumbs.db,node_modules,.pnpm-store,.attachments # ==================== pnpm prune ==================== PNPM_PRUNE_ENABLED=true PNPM_PRUNE_SCHEDULE=0 2 * * * PNPM_PRUNE_TIMEZONE=Asia/Shanghai PNPM_PRUNE_RUN_ON_START=false # ==================== Log cache ==================== LOG_CACHE_ENABLED=true LOG_CACHE_DURATION=180000 LOG_CACHE_MAX_ENTRIES=100 LOG_CACHE_MAX_FILE_SIZE=2097152 # ==================== CLI ==================== CLI_PID_DIR=/tmp/qiming-file-server CLI_STOP_TIMEOUT=30000 CLI_CHECK_INTERVAL=500 CLI_LOG_DIR=/tmp/qiming-file-server/logs ``` #### .env.development ```bash # ==================== Server ==================== NODE_ENV=development PORT=60000 REQUEST_BODY_LIMIT=2000mb # ==================== Logging ==================== LOG_BASE_DIR=./logs LOG_LEVEL=debug LOG_CONSOLE_ENABLED=true LOG_PREFIX_API=api LOG_PREFIX_BUILD=build # ==================== Paths ==================== INIT_PROJECT_NAME_REACT=react-vite-template INIT_PROJECT_NAME_VUE3=vue3-vite-template INIT_PROJECT_DIR=./project_init UPLOAD_PROJECT_DIR=./project_zips PROJECT_SOURCE_DIR=./project_workspace DIST_TARGET_DIR=./project_nginx COMPUTER_WORKSPACE_DIR=./computer-project-workspace COMPUTER_LOG_DIR=./computer_logs # ==================== Build ==================== MAX_BUILD_CONCURRENCY=20 DEV_SERVER_PORT_TIMEOUT=5000 DEV_SERVER_STOP_TIMEOUT=5000 DEV_SERVER_STOP_CHECK_INTERVAL=100 DEV_SERVER_STOP_MAX_ATTEMPTS=50 # ==================== Uploads ==================== MAX_INLINE_FILE_SIZE_BYTES=1048576 UPLOAD_MAX_FILE_SIZE_BYTES=1048576000 UPLOAD_ALLOWED_EXTENSIONS=.zip UPLOAD_SINGLE_FILE_SIZE_BYTES=1048576000 # ==================== Traversal / filters ==================== TRAVERSE_EXCLUDE_DIRS=dist,node_modules,.pnpm-store,__MACOSX,.attachments BACKUP_TRAVERSE_EXCLUDE_FILES=pnpm-lock.yaml,yarn.lock,package-lock.json CONTENT_TRAVERSE_EXCLUDE_FILES=AGENT.md,AGENTS.md,CLAUDE.md,pnpm-lock.yaml,yarn.lock,package-lock.json INLINE_IMAGE_EXTENSIONS=.png,.jpg,.jpeg,.gif,.bmp,.svg,.ico,.webp,.avif TOP_LEVEL_NOISE_PATTERNS=__MACOSX,Thumbs.db,node_modules,.pnpm-store,.attachments # ==================== pnpm prune ==================== PNPM_PRUNE_ENABLED=false PNPM_PRUNE_SCHEDULE=0 2 * * * PNPM_PRUNE_TIMEZONE=Asia/Shanghai PNPM_PRUNE_RUN_ON_START=false # ==================== Log cache ==================== LOG_CACHE_ENABLED=true LOG_CACHE_DURATION=180000 LOG_CACHE_MAX_ENTRIES=100 LOG_CACHE_MAX_FILE_SIZE=2097152 # ==================== CLI ==================== CLI_PID_DIR=./tmp CLI_STOP_TIMEOUT=30000 CLI_CHECK_INTERVAL=500 CLI_LOG_DIR=./tmp/logs ``` ### Kubernetes example ```yaml apiVersion: v1 kind: ConfigMap metadata: name: qiming-file-server-config data: NODE_ENV: "production" PORT: "60000" LOG_BASE_DIR: "/app/logs" LOG_LEVEL: "info" LOG_CONSOLE_ENABLED: "false" PROJECT_SOURCE_DIR: "/app/projects" DIST_TARGET_DIR: "/app/nginx" UPLOAD_PROJECT_DIR: "/app/uploads" INIT_PROJECT_DIR: "/app/init" COMPUTER_WORKSPACE_DIR: "/app/computer" COMPUTER_LOG_DIR: "/app/computer-logs" MAX_BUILD_CONCURRENCY: "20" PNPM_PRUNE_ENABLED: "true" PNPM_PRUNE_SCHEDULE: "0 3 * * *" PNPM_PRUNE_TIMEZONE: "Asia/Shanghai" LOG_CACHE_ENABLED: "true" LOG_CACHE_DURATION: "180000" LOG_CACHE_MAX_ENTRIES: "100" LOG_CACHE_MAX_FILE_SIZE: "2097152" --- apiVersion: apps/v1 kind: Deployment metadata: name: qiming-file-server spec: replicas: 1 selector: matchLabels: app: qiming-file-server template: metadata: labels: app: qiming-file-server spec: containers: - name: qiming-file-server image: qiming-file-server:latest ports: - containerPort: 60000 envFrom: - configMapRef: name: qiming-file-server-config volumeMounts: - name: projects mountPath: /app/projects - name: logs mountPath: /app/logs - name: nginx mountPath: /app/nginx - name: uploads mountPath: /app/uploads - name: init mountPath: /app/init - name: computer mountPath: /app/computer livenessProbe: httpGet: path: /health port: 60000 initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: httpGet: path: /health port: 60000 initialDelaySeconds: 5 periodSeconds: 10 volumes: - name: projects hostPath: path: /data/projects - name: logs hostPath: path: /data/logs - name: nginx hostPath: path: /data/nginx - name: uploads hostPath: path: /data/uploads - name: init hostPath: path: /data/init - name: computer hostPath: path: /data/computer ``` ## Verifying configuration ```bash curl http://localhost:60000/health ``` The JSON body includes the active environment name (e.g. `"env": "production"`). ## Troubleshooting ### Changes not applied 1. Confirm the correct env file path and `NODE_ENV`. 2. Variable names are case-sensitive. 3. Validate YAML/JSON if you embed config in manifests. 4. Read server logs for load errors. ### Port already in use If `PORT` is taken, startup fails. Pick another port or free the listener. ### Permissions Ensure log and data directories are writable: ```bash chmod -R 755 /path/to/logs mkdir -p /path/to/logs /path/to/projects ``` ### Docker env not visible Pass variables with `environment:` or `envFrom:`: ```yaml environment: - NODE_ENV=production - PORT=60000 envFrom: - configMapRef: name: my-config ``` ## Related docs - [README.md](../README.md) — Overview - [PNPM_CHECK.md](./PNPM_CHECK.md) — pnpm disk usage helper