Files
OpenFlare/docs/en/reference/configuration.md
T
ryan e7b8fb2f99 docs(i18n): 同步 24 篇旧英文文档与中文最新内容
guide 9 篇(quick-start/first-site/sso/troubleshooting/tunnel-usage/waf-usage/waf-ip-group-expr/credits/index)、deployment 7 篇(deployment/server/agent/relay/openflared/upgrade/index)、reference 3 篇(configuration/cli/index)、design 5 篇(architecture/agent-design/tunnel-design/waf-design/index)全部按中文最新版重写同步;waf-usage/waf-design 按新版 DAG 模型重写;修复 reference 中文锚点链接;vitepress 构建 43 个英文页面全绿
2026-08-16 23:27:18 +08:00

30 KiB
Raw Blame History

Configuration

You will learn: which config sources OpenFlare Server, frontend build, Agent, Relay, and OpenFlared support, what config fields and env vars exist, and their defaults and behavior.

This document summarizes all configuration items supported by the current OpenFlare version.


Config Sources

1. Server Config Sources

  • Config file: reads config.yaml in the same directory at startup by default (overridable via the CONFIG_PATH env var).
  • Env vars: every field in the config file can be overridden by an UPPER_SNAKE_CASE env var (env vars take precedence over config.yaml).
  • System runtime config: stored in the w_system_configs table in the relational DB. These can be hot-updated and take effect dynamically via the admin UI or system API.

2. Agent / Relay / OpenFlared Config Sources

  • CLI args: -config specifies the config file (JSON format).
  • Config file: e.g. agent.json, relay.json, flared.json.
  • Override env vars: specific env vars can override connection addresses and Token credentials in the config file.

Config File Locations

Component Default Location Notes
Server config file ./config.yaml overridable via CONFIG_PATH
Server SQLite DB openflare.db overridable via database.sqlite_path / SQLITE_PATH
Agent config file ./agent.json overridable via -config
One-click install Agent config /opt/openflare-agent/agent.json default path generated by the install script
Agent data dir data next to the config file overridable via data_dir
Relay config file ./relay.json overridable via -config
One-click install Relay config /opt/openflare-relay/relay.json default path generated by the install script
Client config file ./flared.json overridable via -config
One-click install Client config /opt/openflared/flared.json default path generated by the install script

Server CLI Args

# specify a config file when starting the Server
CONFIG_PATH=/path/to/custom-config.yaml ./openflare-server all

Supported sub-service commands (fused/single-process mode):

  • all: starts all services in one process (API + Worker + Scheduler, default).
  • api: starts only the API service for the admin panel and node communication.
  • worker: starts only the background-task Worker service.
  • scheduler: starts only the scheduled-task Scheduler service.

Server Env Vars vs Config File

All Server core base config is defined in config.yaml, and every field supports env-var overrides (env vars take precedence over the YAML file).

1. App Basic Config (app:)

YAML path Override env var Description Default
app.app_name APP_NAME application identifier name openflare
app.env APP_ENV runtime env (development / testing / production) production
app.addr APP_ADDR service listen address and port :3000
app.node_id APP_NODE_ID Snowflake node ID (0-1023); must be unique in multi-instance deploys 1
app.api_prefix APP_API_PREFIX route prefix for admin panel and API /api
app.graceful_shutdown_timeout APP_GRACEFUL_SHUTDOWN_TIMEOUT graceful shutdown wait timeout (seconds) 30
app.session_cookie_name APP_SESSION_COOKIE_NAME session cookie name openflare_session_id
app.session_secret APP_SESSION_SECRET session signature secret; must be a random long string in production none (random)
app.session_domain APP_SESSION_DOMAIN shared-session cookie scope domain empty
app.session_age APP_SESSION_AGE browser session lifetime (seconds) 86400 (24h)
app.session_http_only APP_SESSION_HTTP_ONLY enable the cookie's HttpOnly attribute false
app.session_secure APP_SESSION_SECURE enable the cookie's Secure attribute (HTTPS) false

2. Relational DB Config (database:)

YAML path Override env var Description Default
database.enabled DB_ENABLED enable PostgreSQL; false falls back to SQLite true
database.sqlite_path SQLITE_PATH SQLite DB file path when PostgreSQL disabled openflare.db
database.host DB_HOST PostgreSQL host 127.0.0.1
database.port DB_PORT PostgreSQL port 5432
database.username DB_USERNAME PostgreSQL username openflare
database.password DB_PASSWORD PostgreSQL password replace-with-strong-password
database.database DB_NAME PostgreSQL database name openflare
database.ssl_mode DB_SSL_MODE PostgreSQL SSL mode disable
database.time_zone DB_TIMEZONE DB session timezone UTC
database.log_level DB_LOG_LEVEL GORM SQL log level (info / warn / error / silent) info
database.max_idle_conn DB_MAX_IDLE_CONN connection pool max idle 16
database.max_open_conn DB_MAX_OPEN_CONN connection pool max open 128

3. Redis Config (redis:)

YAML path Override env var Description Default
redis.enabled REDIS_ENABLED enable Redis. The async queue and sync depend on it; must be on true
redis.addrs REDIS_ADDR Redis single/cluster address array (env var sets a single address) ["127.0.0.1:6379"]
redis.username REDIS_USERNAME Redis username (if any) empty
redis.password REDIS_PASSWORD Redis password empty
redis.db REDIS_DB Redis logical DB number 0
redis.key_prefix REDIS_KEY_PREFIX system key prefix in Redis openflare:
redis.pool_size REDIS_POOL_SIZE Redis connection pool size 100
redis.maint_notifications REDIS_MAINT_NOTIFICATIONS enable Redis maintenance-notifications negotiation at startup; keep off when compatibility is unclear; restart needed after change false

4. ClickHouse Config (clickhouse:)

Note

: these are OpenFlare client connection params. For ClickHouse server small-host tuning: curl performance.xml to ./config/clickhouse/, then mount it as a single file at the container's config.d/performance.xml — see Start the Server.

YAML path Override env var Description Default
clickhouse.enabled CLICKHOUSE_ENABLED enable ClickHouse. Node metrics and access logs are written here at scale. Off by default: missing config or false disables it and the primary DB handles logs/metrics; explicit true or setting CLICKHOUSE_HOST enables it false
clickhouse.hosts CLICKHOUSE_HOST ClickHouse cluster address array (env var sets a single address) ["127.0.0.1:9000"]
clickhouse.username CLICKHOUSE_USERNAME ClickHouse username default
clickhouse.password CLICKHOUSE_PASSWORD ClickHouse password replace-with-clickhouse-password
clickhouse.database CLICKHOUSE_NAME ClickHouse database name openflare
clickhouse.max_idle_conn - client idle connections (low by default for small hosts) 8
clickhouse.max_open_conn - client max open connections 16
clickhouse.conn_max_lifetime - connection max lifetime (seconds) 3600
clickhouse.dial_timeout - dial timeout (seconds) 5
clickhouse.block_buffer_size - native-protocol block buffer rows 32

5. System Log Config (log:)

YAML path Override env var Description Default
log.level LOG_LEVEL global log level (debug / info / warn / error / fatal) info
log.format LOG_FORMAT log format (console readable / json structured) console
log.output LOG_OUTPUT log output (stdout / file) stdout
log.file_path - log file path when output is file ./logs/app.log
log.max_size - max single log file size (MB); auto-rotates beyond 100
log.max_age - max days to keep rotated log files 30

6. Async Task Worker Queue Config (worker:)

YAML path Override env var Description Default
worker.concurrency WORKER_CONCURRENCY max concurrent tasks consumed by the background Worker 20
worker.strict_priority WORKER_STRICT_PRIORITY strictly assign consumer threads by queue priority (else weighted round-robin) false

7. Tracing OpenTelemetry Config (otel:)

YAML path Override env var Description Default
otel.sampling_rate OTEL_SAMPLING_RATE global OTel sampling rate. 0.0 no sampling, 1.0 full tracing 0.0
otel.tracer_name OTEL_TRACER_NAME global OTel tracer instance name github.com/Rain-kl/OpenFlare

Runtime System Config (SystemConfig)

These items are stored in the w_system_configs table. Changes actively notify Redis cache invalidation for dynamic hot-update; admins manage them via the admin UI.

1. Base & Business Runtime Config

Key Type Description Default
site_name string admin platform display name OpenFlare
server_address string public access address of the admin console, used to assemble OAuth callbacks and download links empty
password_login_enabled bool allow admin login with normal username/password true
registration_enabled bool allow self-service new-user registration (off by default; root invites or distributes) false
password_register_enabled bool allow direct email/password registration on the frontend false
oidc_login_enabled bool enable OIDC (SSO) third-party passwordless login true
max_api_keys_per_user int max API keys (API Tokens) per admin user 5
login_session_ttl_hours int user session lifetime in the browser cookie (hours). 0 = clear on browser close 0
upload_allowed_extensions string allowed upload file extensions (comma-separated; empty = unlimited) jpg,png,webp
file_access_whitelist json file business types allowed for public download/access without login (JSON array) ["avatar"]
disk_cache_max_size_mb int platform local disk cache max storage (MB) 100
disk_cache_ttl_minutes int local disk cache object default TTL (minutes) 60
disk_cache_lru_enabled bool use LRU eviction when local disk cache space is low true
update_upstream_repository string GitHub repo for self-update detection Rain-kl/OpenFlare
storage_config json object-storage structured config (JSON): local disk and AWS S3-compatible storage local-storage mode
relay_frps_web_ui_enabled bool enable the embedded frps traffic-monitoring Web UI on relay nodes false
relay_frps_web_ui_port int host port the relay frps monitoring panel listens on 17500
search_engine_indexing_enabled bool allow search engines to crawl/index the site false
menu_display_config string menu display structured config (JSON string, format {url: enabled}) {}
pages_max_package_size_mb int Pages deployment package upload size cap (MiB, range 1–2048) 100
pages_max_history_count int max historical deployments kept per Pages project (0 = unlimited) 20

2. Human Verification (PoW Captcha)

Key Type Description Default
cap_login_enabled bool require local PoW anti-brute-force human verification on the login page false
cap_auto_solve bool auto-start background PoW computation on page load (no manual click) true
cap_challenge_count int number of PoW challenges required. More = longer compute (recommended 1–5) 1
cap_challenge_difficulty int PoW hash prefix-match difficulty per challenge. Recommended 3-5 4
cap_challenge_size int challenge salt length 32
cap_challenge_ttl_seconds int max valid time to submit the computed challenge (seconds); auto-invalidates on timeout 600
cap_token_ttl_seconds int validity of the login credential after solving (seconds); must log in within the window 1200

3. SMTP Email Config

Key Type Description Default
smtp_host string SMTP server address empty
smtp_port int SMTP port (usually 465 SSL or 587 STARTTLS) 465
smtp_username string SMTP account email empty
smtp_password string SMTP account auth password/cert key (encrypted on save, never echoed) empty
email_login_verification_enabled bool send a one-time 6-digit code for second-factor auth on email login false
email_register_verification_enabled bool force email verification with a registration code for self-service registration false

4. Node & Agent Ops Runtime

Key Type Description Default
agent_discovery_token string global discovery Token for one-click first-time node registration none (auto-generated on first visit)
agent_heartbeat_interval int standard heartbeat interval dispatched to all Agents (ms) 3000 (3s)
agent_websocket_upgrade_enabled bool allow Agents to upgrade to a persistent WebSocket connection after HTTP heartbeat handshake true
node_offline_threshold int no-response threshold (ms) after which a node is marked offline in the admin panel 60000 (60s)
agent_update_repo string Release repo source for Agent self-binary updates Rain-kl/OpenFlare
geoip_provider string GeoIP provider, e.g. maxmind, for WAF geo analysis ipinfo

5. Uptime Kuma Monitoring Sync

Key Type Description Default
uptime_kuma_enabled bool auto-sync generated Uptime Kuma HTTP monitors after config release/activation false
uptime_kuma_url string Uptime Kuma instance access URL (with port and path) empty
uptime_kuma_username string Uptime Kuma admin username for sync API auth empty
uptime_kuma_password string Uptime Kuma login password (encrypted on save, never echoed) empty
uptime_kuma_monitor_scope string route scope for auto-generated monitors (all sites or selected) all
uptime_kuma_selected_sites string selected proxied-site Site Name list to monitor (comma-separated) empty
uptime_kuma_sync_interval int differential scan/calibration sync frequency to the Uptime Kuma instance (minutes) 5
uptime_kuma_interval int HTTP GET probe period of generated monitors (seconds) 60
uptime_kuma_retry int max reconnect retries after probe connection failures 0
uptime_kuma_retry_interval int pause between failed reconnect retries (seconds) 60
uptime_kuma_timeout int timeout for an HTTP GET monitor request (seconds) 48

6. OpenResty Core Main Config & Rendering Options

Key Type Description Default
openresty_default_server_return_status int status code returned for requests hitting no matching route by default 421
openresty_worker_processes string nginx worker_processes; fixed integer or auto auto
openresty_worker_connections int nginx worker_connections per-process max connections 4096
openresty_worker_rlimit_nofile int nginx worker_rlimit_nofile max open file descriptors 65535
openresty_events_use string event polling engine (e.g. epoll preferred on Linux) epoll
openresty_events_multi_accept_enabled bool accept all pending connection handshakes in one batch true
openresty_keepalive_timeout int nginx keepalive_timeout (seconds) 20
openresty_keepalive_requests int max requests per reused TCP connection 1000
openresty_client_header_timeout int read timeout for the client Request Header (seconds) 15
openresty_client_body_timeout int read timeout for the client Request Body (seconds) 15
openresty_client_max_body_size string max client request Body size, with a unit like 10m/50m 64m
openresty_large_client_header_buffers string buffers for oversized request headers (e.g. 4 16k) 4 16k
openresty_send_timeout int max interval for sending Response data to the client (seconds) 30
openresty_resolvers string DNS resolver addresses/params for dynamic name resolution on nodes empty
openresty_proxy_connect_timeout int TCP handshake timeout to the origin (seconds) 3
openresty_proxy_send_timeout int max interval for writing request data to the origin (seconds) 60
openresty_proxy_read_timeout int max wait for origin response data (seconds) 60
openresty_websocket_enabled bool auto-load WebSocket-supporting globals and headers in the HTTP section true
openresty_http3_enabled bool render HTTP/3 QUIC dual-stack listen capability in generated nginx listens true
openresty_proxy_request_buffering_enabled bool fully buffer the client Request Body before forwarding to the origin false
openresty_proxy_buffering_enabled bool buffer large origin Response data before forwarding to the user true
openresty_proxy_buffers string nginx proxy response buffer count/size (e.g. 16 16k) 16 16k
openresty_proxy_buffer_size string buffer for origin Response Header 8k
openresty_proxy_busy_buffers_size string Busy-state buffer cap when response stream is oversized 64k
openresty_gzip_enabled bool enable gzip real-time compression on eligible content true
openresty_gzip_min_length int file size threshold for gzip; below it, skip to save CPU 1024 (1KB)
openresty_gzip_comp_level int gzip level 1-9; higher = more compression, more CPU 5
openresty_cache_enabled bool initialize the proxy cache region (Proxy Cache Path) in global config false
openresty_cache_path string proxy cache temp physical dir on the node __OPENFLARE_PROXY_CACHE_PATH__
openresty_cache_levels string proxy cache directory tree level layout 1:2
openresty_cache_inactive string time after which an unaccessed cache file is invalidated from disk 30m
openresty_cache_max_size string max disk quota for the proxy cache region on a node 1g
openresty_cache_key_template string default proxy cache key template $scheme$host$request_uri
openresty_cache_lock_enabled bool queue/lock origin connections on high-concurrency cache misses for the same expired resource true
openresty_cache_lock_timeout string max queue wait for the proxy cache lock 5s
openresty_cache_use_stale string serve stale cache on specific origin errors (500/502/504 etc.) error timeout updating http_500 http_502 http_503 http_504
openresty_default_limit_conn_per_server int default concurrent-connection cap per server when a site has no config; 0 = off 0
openresty_default_limit_conn_per_ip int default per-IP concurrent cap when a site has no config; 0 = off 0
openresty_default_limit_rate string default per-request bandwidth when a site has no config (e.g. 512k); empty = off empty
openresty_default_limit_req_per_ip string default per-IP request rate limit when a site has no config (e.g. 10r/s, 100r/m); empty = off empty
openresty_main_config_template string fully rewrite the OpenResty nginx.conf skeleton template empty (built-in default skeleton)

7. Origin Error Page

Global origin error page config; written into the config version snapshot and distributed to edge Agents on release/rollback. Only affects reverse proxy routes; Pages static routes are unaffected. Admin entry:「Website Management → Error Page」. Design: Origin Error Page Design.

Key Type Description Default
origin_error_page_enabled bool enable the global origin error page. When on, matching status codes from origin/gateway are replaced by custom/default HTML with the HTTP status kept; when off, no directives are generated and pass-through resumes. Requires a config release to take effect true
origin_error_page_get_only bool only apply to GET requests. When on, only matching GET error statuses return the custom error page; POST/PUT and other methods pass through the origin response (original status and body unchanged) false
origin_error_page_status_codes json status code tag JSON array triggering the error page. Supports single codes (e.g. 522) and closed ranges (e.g. 500-599); single codes and range endpoints must be in 400–599, with lo ≤ hi. The expanded result must not be empty when enabled ["500-599"]
origin_error_page_html string custom error page HTML. Empty uses the built-in OpenFlare default template (minimal white); supports {{status}} (matches the HTTP status) and {{host}} (request Host). Max 256 KiB (bytes). Don't embed untrusted third-party scripts empty

8. Log Database

Runtime config after log-store decoupling: the log primary DB is managed by the「Switch Log Database」task (internal/protected keys, forbidden for manual admin edits); access-log retention days are set per storage DB in business config; performance metrics (CPU/memory/disk/network) decay fast and use a shared short retention independent of the access-log retention config.

Key Type Description Default
log_database string current log primary DB (postgres / sqlite / clickhouse). Internal protected key: only written by the「Switch Log Database」migration task; admins can't create/modify manually follows the primary DB (postgres when PostgreSQL enabled, else sqlite; clickhouse preferred when ClickHouse enabled)
log_db_migration string log migration freeze marker (migrating or empty). Internal protected key: only the migration task writes it; while set, log writes return 503「log DB migrating, not writable」 empty
log_retention_days_postgres int access-log retention days in the PostgreSQL log DB (expired logs deleted by the daily garbage-collection task) 30
log_retention_days_sqlite int access-log retention days in the SQLite log DB 30
log_retention_days_clickhouse int access-log retention days in the ClickHouse log DB 30
metric_retention_days int performance metric (CPU/memory/disk/network) retention days; shared short retention across the three DBs (independent of access-log retention) 3

Frontend Build Env Vars

Env var Purpose Default
WAVELET_BACKEND_URL backend address for server-side rendering and dev proxy http://localhost:3000
NEXT_PUBLIC_WAVELET_BACKEND_URL backend address for browser API requests; empty = same-origin empty
NEXT_PUBLIC_APP_VERSION displayed frontend version dev

Agent Env Vars

Env var Purpose Default
LOG_LEVEL Agent log level info
OPENFLARE_SERVER_URL control-plane address, overrides agent.json empty
OPENFLARE_AGENT_TOKEN node-specific auth Token, overrides agent.json empty
OPENFLARE_DISCOVERY_TOKEN first-time auto-registration Token, overrides agent.json empty
OPENFLARE_NODE_NAME node name, overrides agent.json empty
OPENFLARE_NODE_IP node IP, overrides agent.json empty
OPENFLARE_DATA_DIR Agent data dir, overrides agent.json empty
OPENFLARE_OPENRESTY_PATH OpenResty binary path, overrides agent.json empty
OPENFLARE_PAGES_DIR Pages static deployment dir, overrides agent.json empty
OPENFLARE_HEARTBEAT_INTERVAL heartbeat interval, overrides agent.json empty
OPENFLARE_REQUEST_TIMEOUT request timeout, overrides agent.json empty
OPENFLARE_OPENRESTY_OBSERVABILITY_PORT local observability port, overrides agent.json empty
OPENFLARE_MMDB_PATH WAF GeoIP mmdb path, overrides agent.json empty
OPENFLARE_MMDB_UPDATE_INTERVAL WAF GeoIP mmdb update interval, overrides agent.json empty
OPENFLARE_MMDB_DOWNLOAD_URL WAF GeoIP mmdb download URL, overrides agent.json empty
OPENFLARE_CITY_MMDB_PATH WAF City MMDB path, overrides agent.json empty
OPENFLARE_CITY_MMDB_DOWNLOAD_URL WAF City MMDB download URL, overrides agent.json empty

Agent CLI Args and Config Fields

CLI Args

  • -config: Agent config file path, default ./agent.json.

Config File Fields (agent.json)

Field Purpose Required Default/Behavior
server_url control-plane address yes none
agent_token node-specific auth Token one of two with discovery_token empty
discovery_token global Token for first-time auto-registration one of two with agent_token empty
node_name node name no hostname automatically
node_ip node IP no auto-detected, prefers the public egress IP; falls back to local NIC detection on failure
openresty_path OpenResty binary path no openresty
openresty_observability_port local observability & OpenResty health-check port no 18081
data_dir Agent data dir no data next to the config file
main_config_path OpenResty main config write path no data_dir/etc/nginx/nginx.conf
route_config_path route config write path no data_dir/etc/nginx/conf.d/openflare_routes.conf
access_log_path OpenResty access log path no data_dir/var/log/openflare/access.log
cert_dir certificate write dir no data_dir/etc/nginx/certs
openresty_cert_dir certificate dir read by the OpenResty config no same as cert_dir
lua_dir Lua scripts & static assets write dir no data_dir/etc/nginx/lua
openresty_lua_dir Lua dir read by the OpenResty config no same as lua_dir
runtime_config_dir Agent runtime config write dir, e.g. pow_config.json no data_dir/etc/openflare
pages_dir Pages deployment package extraction & current deploy dir no data_dir/var/lib/openflare/pages
mmdb_path WAF GeoIP mmdb file path no data_dir/etc/openflare/GeoLite2-Country.mmdb
city_mmdb_path WAF City MMDB file path no data_dir/etc/openflare/GeoLite2-City.mmdb
mmdb_update_interval WAF GeoIP mmdb update interval no 86400000 ms (24h)
mmdb_download_url WAF GeoIP mmdb periodic update URL no GeoLite2 Country update URL; first download when the disk file is missing (Docker images COPY default-path files)
city_mmdb_download_url WAF City MMDB periodic update URL no GeoLite2 City update URL; first download when the disk file is missing (Docker images COPY default-path files)
observability_buffer_path observability backfill buffer file path no data_dir/var/lib/openflare/observability-buffer.json
observability_replay_minutes auto-backfill recent observability window (minutes) no 60
state_path Agent local state file path no data_dir/var/lib/openflare/agent-state.json
heartbeat_interval heartbeat interval no 3000 ms
request_timeout HTTP request timeout no 10000 ms

Relay Env Vars and Config Fields

Env Vars

  • LOG_LEVEL: Relay log level, default info.
  • Supports OPENFLARE_SERVER_URL, OPENFLARE_AGENT_TOKEN, OPENFLARE_DISCOVERY_TOKEN, OPENFLARE_NODE_NAME, OPENFLARE_NODE_IP, OPENFLARE_DATA_DIR, OPENFLARE_FRPS_PATH overrides.

CLI Args

  • -config: Relay config file path, default ./relay.json.

Config File Fields (relay.json)

Field Purpose Required Default/Behavior
server_url control-plane address yes none
agent_token relay node-specific auth Token one of two with discovery_token empty
discovery_token global Token for first-time auto-registration one of two with agent_token empty
node_name node name no hostname automatically
node_ip relay node IP for receiving tunnel traffic no auto-detected, prefers the public egress IP; falls back to NIC detection on failure
frps_path frps binary path no frps (found on system PATH)
data_dir Relay runtime data dir no data next to the config file
state_path Relay local state file path no data_dir/relay-state.json
heartbeat_interval heartbeat interval no 10000 ms
request_timeout HTTP request timeout no 10000 ms

OpenFlared (Client) Env Vars and Config Fields

Env Vars

  • LOG_LEVEL: Client log level, default info.
  • Supports OPENFLARE_SERVER_URL, OPENFLARE_TUNNEL_TOKEN, OPENFLARE_DATA_DIR, OPENFLARE_FRPC_PATH overrides.

CLI Args

  • -config: Client config file path, default ./flared.json.

Config File Fields (flared.json)

Field Purpose Required Default/Behavior
server_url control-plane address yes none
tunnel_token tunnel-specific auth Token yes none
frpc_path frpc binary path no frpc (found on system PATH)
data_dir Client runtime data dir no data next to the config file
state_path Client local state file path no data_dir/flared-state.json
heartbeat_interval heartbeat interval no 10000 ms
sync_interval config pull/sync interval no 30000 ms
request_timeout HTTP request timeout no 10000 ms