Profile Configuration
For script authoring, see the JavaScript API guide, including an importable demo, request/response fields, completion rules, and runtime limits.
Updated for MintFlow 2.0.0. Profile text is the source of truth: the app compiles it into a runtime database when starting VPN. Save changes, inspect compilation diagnostics, and restart VPN to apply a new configuration. Syntax/range errors and entitlement restrictions are distinct: a valid Pro configuration may be excluded from the compiled result when Pro is unavailable.
New sections include [simple-mode], [flowlog], [dns-hosts], and [http-body-rewrite]. Tailscale is an experimental [l3vpns] type. HTTP Engine now supports broader capture scope and jq/JavaScript body rules. Local scripts are separate resources; sharing profile text alone does not package them. Use an MFHRB bundle to share a rule and its source together.
The text-based profile is a cornerstone of MintFlow, designed to provide power users with a highly flexible and shareable way to control the app's advanced networking capabilities.
Why Use Profiles?
- Complex Setups: Easily configure sophisticated routing rules, split DNS, and combinations of proxies and VPNs.
- Manage Multiple Configurations: Create and switch between different profiles for various scenarios (e.g., a "Work" profile with a corporate VPN and a "Home" profile for personal use).
- Share and Collaborate: Profiles are plain text, making them easy to share with other MintFlow users, version control with Git, or collaborate on.
- Import and Export: Seamlessly import profiles from URLs or files, and export your configurations to back them up or share them.
MintFlow uses a powerful and flexible text-based profile format to configure all aspects of the VPN and proxy behavior. This document details the syntax and all available configuration options.
Syntax Overview
The profile uses an INI-style format with sections enclosed in [].
# Comments start with # or //
[section-name]
key=value
# Lists are comma-separated
key=value1,value2,value3
# Structured values use subkey:subvalue pairs
key=subkey1:value1,subkey2:value2
Sections
[misc]
This section contains miscellaneous system-level settings.
| Key | Type | Description | Default |
|---|---|---|---|
tun-mtu | Integer | The MTU for the TUN interface. | |
exclude-lan-networks | Boolean | If true, local area networks will be excluded from the VPN. | false |
log-level | String | Runtime logging level; use the app's supported choices. |
Example:
[misc]
tun-mtu=1420
exclude-lan-networks=true
[dns]
This section configures the DNS settings.
| Key | Type | Description |
|---|---|---|
system-dns | List of IPs | Deprecated legacy override, used only when both custom App Routing and Simple Mode are disabled. Prefer direct-dns for new profiles. |
app-routing-enabled | Boolean | Enables domain-based routing and split DNS. Set true for new profiles; the legacy false path is deprecated. |
direct-dns | List of DNS upstreams | DNS servers for direct connections when app-routing-enabled is true. Supports plain IP DNS, DoT, and DoH. |
vpn-dns | List of DNS upstreams | DNS servers for VPN/proxy connections when app-routing-enabled is true. Supports plain IP DNS, DoT, and DoH. |
bootstrap-dns | List of IPs | (New in 1.9.0) bootstrap resolvers used when encrypted VPN DNS upstreams are configured with domains. Defaults are provided by the app. |
direct-dns-follow-vpn | Boolean | (New in 1.8.0) whether DNS servers for direct connections should follow the split routing rule. |
optimistic-dns-caching | Boolean | (New in 1.9.0) enables optimistic DNS cache refresh. Default is true. |
l4proxy-synthetic-ip | Boolean | Enables synthetic-IP handling for L4 proxy domain routing. Default false. |
DNS upstream formats:
- Plain IP DNS:
1.1.1.1,8.8.8.8 - DNS over TLS:
tls://cloudflare-dns.comortls://1.1.1.1 - DNS over HTTPS:
https://dns.google/dns-query
When vpn-dns contains an encrypted DNS server with a domain name, such as tls://p2.freedns.controld.com, add a VPN-DNS-SERVER-DOMAINS routing rule so MintFlow can resolve that DNS server domain through a selected VPN/proxy path instead of leaking bootstrap traffic to the direct network.
Example:
[dns]
app-routing-enabled=true
direct-dns=223.5.5.5,114.114.114.114
vpn-dns=tls://p2.freedns.controld.com,https://dns.google/dns-query
bootstrap-dns=1.1.1.1,8.8.8.8
optimistic-dns-caching=true
[l3vpns]
This section defines Layer 3 VPN interfaces. The key for each entry is a user-defined name for the interface.
Common Fields
| Key | Type | Description | Required |
|---|---|---|---|
type | String | Active types include wireguard, amneziawg, and experimental tailscale. openvpn is accepted by the schema but should not be treated as an implemented OpenVPN client. | Yes |
nickname | String | A user-friendly name for the interface. | No |
enabled | Boolean | Whether the interface is enabled. Defaults to true. | No |
WireGuard Specific Fields (When type=wireguard)
| Key | Type | Description | Required |
|---|---|---|---|
private-key | String | The private key for the interface. | Yes |
address | CIDR | The internal IP address and subnet for the interface. | Yes |
Tailscale fields (type:tailscale, experimental, Pro)
| Key | Meaning |
|---|---|
login-server | HTTPS control server URL, normally https://controlplane.tailscale.com; no embedded credentials, query, or fragment. |
auth-key | Optional bootstrap enrollment key. Prefer browser login or a one-time key submission to avoid saving secrets in the profile. |
drive-dns | Default false. Derive peer IPv4 DNS records through MintFlow DNS; this does not enable the Tailscale OS MagicDNS resolver. Requires Pro and the MintFlow DNS path. |
enabled | Default true. Only one active Tailscale interface per profile. |
[l3vpns]
tailnet=type:tailscale,login-server:https://controlplane.tailscale.com,enabled:true
[routing]
CIDR,100.64.0.0/10,L3VPN,tailnet
DEFAULT,DIRECT
DNS-FALLBACK,DIRECT
Use with [dns] app-routing-enabled=true and suitable direct-dns upstreams. See the complete login and routing guide. Machine identity, Accept Routes, and exit-node selection are device-local state, not portable profile settings. Losing Pro access excludes the interface during compilation and changes routes targeting it to REJECT.
AmneziaWG Specific Fields (When type=amneziawg)
MintFlow 1.9.0 supports AmneziaWG 1.5 and 2.0 interface parameters. Peer fields are configured separately in [amneziawg-peers].
| Key | Type | Description | Required |
|---|---|---|---|
private-key | String | The private key for the interface. | Yes |
address | CIDR | The internal IP address and subnet for the interface. | Yes |
jc | Integer | Junk packet count parameter. | No |
jmin | Integer | Minimum junk packet size. | No |
jmax | Integer | Maximum junk packet size. | No |
s1 | Integer | AmneziaWG S1 parameter. | No |
s2 | Integer | AmneziaWG S2 parameter. | No |
s3 | Integer | AmneziaWG S3 parameter. | No |
s4 | Integer | AmneziaWG S4 parameter. | No |
h1 | Integer or range | H1 packet header value, for example 1 or 843739526-1233562642. | No |
h2 | Integer or range | H2 packet header value, for example 2 or 1383464517-1389039856. | No |
h3 | Integer or range | H3 packet header value, for example 3 or 1558777559-1611162592. | No |
h4 | Integer or range | H4 packet header value, for example 4 or 1797613837-1977519157. | No |
i1 ... i5 | String | AmneziaWG 2.0 CPS instruction strings. Each field is limited to 255 UTF-8 bytes. Supported tags are <b>, <r>, <rd>, <rc>, and <t>. | No |
Example:
[l3vpns]
my-wireguard=type:wireguard,nickname:My WG,private-key:...,address:10.0.0.1/32
my-awg=type:amneziawg,nickname:My AWG,private-key:...,address:10.8.9.2/32,jc:4,jmin:40,jmax:70,s1:0,s2:0,s3:0,s4:0,h1:1,h2:2,h3:3,h4:4,i1:<r 33>
[wireguard-peers]
This section defines peers for WireGuard interfaces. The key for each entry is a user-defined name for the peer.
| Key | Type | Description | Required |
|---|---|---|---|
interface | String | The name of the l3vpns interface this peer belongs to. | Yes |
public-key | String | The public key of the peer. | Yes |
preshared-key | String | An optional pre-shared key. | No |
endpoint | String | The public endpoint of the peer (e.g., 1.2.3.4:51820). | Yes |
allowed-ips | List of CIDRs | A list of IP addresses/ranges to be routed through this peer. | Yes |
Example:
[wireguard-peers]
my-peer=interface:my-wireguard,public-key:...,endpoint:1.2.3.4:51820,allowed-ips:0.0.0.0/0
[amneziawg-peers]
This section defines peers for AmneziaWG interfaces. The key for each entry is a user-defined peer name. The fields match WireGuard peers, but interface must reference an [l3vpns] entry whose type is amneziawg.
| Key | Type | Description | Required |
|---|---|---|---|
interface | String | The name of the amneziawg interface this peer belongs to. | Yes |
public-key | String | The public key of the peer. | Yes |
preshared-key | String | An optional pre-shared key. | No |
endpoint | String | The public endpoint of the peer, for example 1.2.3.4:51820. | Yes |
allowed-ips | List of CIDRs | A list of IP addresses/ranges to be routed through this peer. | Yes |
Example:
[amneziawg-peers]
my-awg-peer=interface:my-awg,public-key:...,endpoint:1.2.3.4:51820,allowed-ips:0.0.0.0/0,::/0
[l4proxies]
This section defines Layer 4 proxies, like Shadowsocks and VMess. The key for each entry is a user-defined name for the proxy.
Common Fields
| Key | Type | Description | Required |
|---|---|---|---|
type | String | The proxy type. Supported: shadowsocks, vmess, anytls, http, socks5. | Yes |
nickname | String | A user-friendly name. | No |
server | String | The server address. | Yes |
port | Integer | The server port. | Yes |
enabled | Boolean | Whether the proxy is enabled. Defaults to true. | No |
route-via-vpn | Boolean | (New in 1.8.0) Whether the proxy need to route over the VPN, thus you can chain it traffic to another VPN/Proxy server. Default to false, server IP must be in IPv4 address. | No |
Shadowsocks Fields
| Key | Type | Description | Required |
|---|---|---|---|
password | String | The password. | Yes |
method | String | The encryption method. Supported AEAD methods: aes-128-gcm, aes-256-gcm, chacha20-ietf-poly1305. Supported Shadowsocks 2022 methods: 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, 2022-blake3-chacha20-poly1305. | Yes |
obfs-type | String | Obfuscation type (tls or http). | No |
obfs-host | String | Obfuscation host (required for obfs-type). | No |
obfs-path | String | Obfuscation path (required for obfs-type=http). | No |
udp-forward | Boolean | Whether to forward UDP traffic. Defaults to false. | No |
For Shadowsocks 2022 methods, password must be a base64-encoded pre-shared key. The decoded key must be 16 bytes for 2022-blake3-aes-128-gcm, and 32 bytes for 2022-blake3-aes-256-gcm or 2022-blake3-chacha20-poly1305.
VMess Fields
| Key | Type | Description | Required |
|---|---|---|---|
user-id | UUID | The user ID. | Yes |
alter-id | Integer | The alter ID. | Yes |
security | String | Security type. E.g., auto. | Yes |
transport-type | String | Transport type (tcp or ws). | Yes |
ws-path | String | The WebSocket path (required for transport-type=ws). | No |
sni | String | Server Name Indication for TLS. | No |
skip-cert-check | Boolean | If true, skip certificate validation. Defaults to false. | No |
alpn | String | Application-Layer Protocol Negotiation. Defaults to h2,http/1.1. | No |
AnyTLS Fields
AnyTLS is configured as an L4 proxy with type=anytls. The fields below are based on the shared profile schema used by the mintflow-app branch currently used for vpprs integration; these AnyTLS profile fields are stable there and safe to use.
| Key | Type | Description | Required |
|---|---|---|---|
password | String | AnyTLS password. | Yes |
sni | String | TLS Server Name Indication. Defaults to the server value when omitted. | No |
skip-cert-check | Boolean | If true, skip upstream certificate validation. Defaults to false. | No |
session-reuse | Boolean | Enables AnyTLS idle session reuse. Defaults to true. | No |
idle-session-check-interval | Integer | Interval in seconds for checking idle AnyTLS sessions. Valid range: 1 to 3600. Defaults to 30. | No |
idle-session-timeout | Integer | Idle session timeout in seconds. Valid range: 1 to 3600. Defaults to 60. | No |
min-idle-sessions | Integer | Minimum idle sessions to keep. Valid range: 0 to 64. Defaults to 1. | No |
max-idle-sessions | Integer | Maximum idle sessions to keep. Valid range: 0 to 64. Defaults to 4. | No |
Example:
[l4proxies]
any=type:anytls,nickname:AnyTLS,server:any.example.com,port:443,password:secret,sni:cdn.example.com,skip-cert-check:false,session-reuse:true,idle-session-check-interval:30,idle-session-timeout:60,min-idle-sessions:1,max-idle-sessions:4,enabled:true
HTTP&Socks5 Fields
| Key | Type | Description | Required |
|---|---|---|---|
username | String | Proxy username for upstream authentication. | No |
password | String | Proxy password for upstream authentication. | No |
udp-forward | Boolean | SOCKS5 UDP forwarding flag. Currently kept for profile compatibility; UDP forwarding depends on runtime support. | No |
Example:
[l4proxies]
tshttp=type:http,nickname:tshttp,server:3.3.3.3,port:1055,enabled:true
tssocks=type:socks5,nickname:tssocks,server:10.1.1.1,port:1055,username:user,password:pass,enabled:true,udp-forward:false,route-via-vpn:true
ss2022=type:shadowsocks,nickname:SS2022,server:ss.example.com,port:8388,password:base64-psk,method:2022-blake3-aes-256-gcm,udp-forward:true,enabled:true
any=type:anytls,nickname:AnyTLS,server:any.example.com,port:443,password:secret,sni:cdn.example.com,skip-cert-check:false,session-reuse:true
[domain-sets]
Domain sets select an output through [routing]; they are separate from HTTP capture domains and exact DNS host records.
This section defines named sets of domains for use in routing rules. The key is the set name.
Example:
[domain-sets]
social-media=twitter.com,facebook.com,instagram.com
[cidr-sets]
This section defines named sets of IP ranges (CIDRs) for use in routing rules. The key is the set name.
Example:
[cidr-sets]
private-ips=10.0.0.0/8,192.168.0.0/16
[routing]
This section defines the routing rules, which are processed from top to bottom. It does not use key-value pairs.
Rule Format: TYPE,VALUE,ACTION,TARGET for match rules, or TYPE,ACTION,TARGET for reserved/default rules such as DNS-FALLBACK, VPN-DNS-SERVER-DOMAINS, and DEFAULT.
| Type | Value | Action | Target | Description |
|---|---|---|---|---|
DOMAIN-SET | Name of a domain set | L3VPN, L4PROXY, DIRECT, DROP, REJECT | Name of an l3vpn/l4proxy | Route based on a domain set. |
CIDR-SET | Name of a CIDR set | L3VPN, L4PROXY, DIRECT, DROP, REJECT | Name of an l3vpn/l4proxy | Route based on a CIDR set. |
CIDR | A single CIDR | L3VPN, L4PROXY, DIRECT, DROP, REJECT | Name of an l3vpn/l4proxy | Route based on a single IP range. |
DNS-FALLBACK | (Not used) | DIRECT, L3VPN, L4PROXY, etc. | Name of an l3vpn/l4proxy | Default DNS behavior for domains not in any set. |
VPN-DNS-SERVER-DOMAINS | (Not used) | L3VPN, L4PROXY | Name of an l3vpn/l4proxy | (New in 1.9.0) route encrypted VPN DNS server domain bootstrap traffic through a selected VPN/proxy. Required when vpn-dns uses DoT/DoH upstreams with domain names. |
DEFAULT | (Not used) | DIRECT, L3VPN, L4PROXY, etc. | Name of an l3vpn/l4proxy | The final catch-all rule for all traffic. |
Example:
[routing]
DOMAIN-SET,social-media,L4PROXY,my-shadowsocks
CIDR-SET,private-ips,DIRECT
VPN-DNS-SERVER-DOMAINS,L4PROXY,my-shadowsocks
DEFAULT,L3VPN,my-wireguard
[http-engine]
This section configures the internal HTTP engine.
| Key | Type | Description |
|---|---|---|
enabled | Boolean | Enables the HTTP engine. Default false. |
capture-all | Boolean | Process every IPv4 destination on configured TCP ports; default false. Saved domain/CIDR lists remain intact. |
cidr-list | List of IPv4 CIDRs | Additional destination-IP capture scope. |
port-list | List of integers | TCP ports from 1–65535; default 80,443. |
http3-policy | allow or block | Default allow. Blocking HTTP/3 can encourage compatible clients to retry over TCP; it is not HTTP/3 decryption. |
mitm-bypass-apple-services | Boolean | Default true; avoid decrypting known Apple service domains. |
mitm-bypass-domain-list | List of domain suffixes | Additional domains that must not be decrypted. |
upstream-tcp-receive-window | Integer | Advanced upstream receive-window size in bytes: 4096–1048576, default 262144. |
domain-list | List of domain suffixes | Domains to apply HTTP processing on; supports * for all domains. |
ca-p12 | String | A base64 encoded PKCS#12 certificate authority. Note: Only RSA keys are currently supported. |
ca-passphrase | String | The passphrase for the ca-p12 certificate. |
Example:
[http-engine]
enabled=true
domain-list=example.com
ca-p12=...
ca-passphrase=...
[http-url-rewrite]
This section defines URL rewrite rules for the HTTP engine. The key is a user-defined name for the rule.
| Key | Type | Description | Required |
|---|---|---|---|
match | Regexp | A regular expression to match the URL. | Yes |
action | String | The action to take. Supported: reject, redirect-302. | Yes |
target | String | The target URL for redirection. | No |
enabled | Boolean | Default true. | No |
Example:
[http-url-rewrite]
block-ads=match:^https?://ads\..*,action:reject
redirect-google=match:^https?://google\.com,action:redirect-302,target:https://duckduckgo.com
[simple-mode]
Select one typed output for ordinary client traffic. Saved advanced routing rules remain available when returning to Rules Mode; Simple Mode does not erase them.
[simple-mode]
enabled=true
output=type:DIRECT
For a configured VPN use output=type:L3VPN,target:my-wireguard; for a proxy use output=type:L4PROXY,target:my-proxy. The target must exist and be usable under the current entitlement. Do not use an unauthenticated Tailscale output as the browser's Internet path during initial login.
[dns-hosts] (Pro)
Exact hostnames mapped to IPv4 addresses, served by MintFlow DNS. These are DNS answers, not routing rules or wildcard domain suffixes. Configure routing separately and enable App Routing for this example:
[dns]
app-routing-enabled=true
direct-dns=1.1.1.1,8.8.8.8
[dns-hosts]
nas.example.com=192.168.40.10
At most 256 hostnames and 1–16 IPv4 addresses per hostname are supported. Static host records and derived Tailscale records are subject to entitlement and effective DNS configuration checks; inspect the compilation report.
[flowlog]
Local Flow Capture is available free. It records flow diagnostics; it is not an IPFIX remote exporter or an HTTP body recording.
| Key | Default | Range |
|---|---|---|
enabled | false | Boolean |
sampling-interval | 1 | 1–1000000 |
active-timeout-seconds | 5 | 1–3600 |
tcp-idle-timeout-seconds | 120 | 2–86400 |
udp-idle-timeout-seconds | 30 | 2–3600 |
fin-grace-seconds | 5 | 1–300 |
max-flows-per-worker | 4096 | 1–16384 |
capture-duration-seconds | 0 | 0–86400; 0 means no duration limit |
retention-hours | 24 | 1–720 |
max-database-rows | 100000 | 1000–1000000 |
[flowlog]
enabled=true
sampling-interval=1
retention-hours=24
[http-body-rewrite]
Named request or response body rules reference managed local scripts. The app's editor and MFHRB importer manage the script resource and its profile reference. Do not paste a remote script URL here and expect automatic fetching or updates.
| Field | Meaning |
|---|---|
match | Required regex over the normalized full URL; at most 4096 UTF-8 bytes. |
direction | request or response; default response. |
type | Required: jq or javascript. |
body-mode | json or text; jq requires JSON (default json for jq, text for JavaScript). |
script | Required managed local resource reference, produced by the editor/importer. |
priority | 0–1000000; default 100. Lower values run first; ties sort by rule name. |
enabled | Default true in profile syntax. MFHRB imports always save it disabled. |
api-version | 1. |
timeout-ms | JavaScript only: 50–2000 ms, default 500. |
The portable JSON bundle uses camel-case keys such as bodyMode and timeoutMS; profile text uses body-mode and timeout-ms. They are different formats. Use the MFHRB guide for a complete shareable example, API contract, and review workflow.
For example, if the managed resource ./feed-cleanup/remove-banner.jq already exists in this profile's script storage:
[http-body-rewrite]
remove-banner=match:^https://api\.example\.com/feed$,direction:response,type:jq,body-mode:json,priority:100,enabled:false,api-version:1,script:./feed-cleanup/remove-banner.jq
The referenced jq source could be .items |= map(select(.kind != "banner")) for a JSON object with an items array. The profile line does not create that file. Import an MFHRB bundle or use the app's script editor to manage the resource, and review it before enabling the rule.