# Configuration
Configuration can come from a JSON config file, CLI flags, or both. **CLI
flags take precedence over JSON file values.** Defaults are applied for
anything not supplied.
Both binaries accept `-c, --config <PATH>` to point at a JSON file.
## Core fields
| `server` | `--listen` / `--server` | server: UDP bind address; client: remote `host:port` | yes | — |
| `password` | `-k, --password` | pre-shared password; master key derived from it | yes | — |
| `cipher` | `-m, --cipher` | AEAD cipher name | no | `chacha20-poly1305` |
| `tun_name` | `--tun-name` | explicit TUN interface name (e.g. `utun7`, `tun0`) | no | OS picks |
| `tun_ip` | `--tun-ip` | local IPv4 address on the TUN interface | yes | — |
| `tun_netmask` | `--tun-netmask` | IPv4 netmask for the TUN interface | no | `255.255.255.0` |
| `peer_ip` | `--peer-ip` | point-to-point peer IPv4 (server: client IP; client: server IP) | yes | — |
| `mtu` | `--mtu` | TUN interface MTU | no | `1400` |
| `obfs` | *(config only)* | carrier obfuscation: `none` \| `quic` \| `base64` (both ends must match) | no | `none` |
On the **server** the `server` field is the UDP bind/listen address; on the
**client** it is the remote server address to connect to.
There are more client-only fields for policy routing — see
[Policy routing](./policy-routing) and the full
[configuration reference](/reference/configuration).
## Example: server config
```json [server.json]
{
"server": "0.0.0.0:8388",
"password": "correct horse battery staple",
"cipher": "chacha20-poly1305",
"tun_name": "utun7",
"tun_ip": "10.9.0.1",
"tun_netmask": "255.255.255.0",
"peer_ip": "10.9.0.2",
"mtu": 1400
}
```
## Example: client config
```json [client.json]
{
"server": "vpn.example.com:8388",
"password": "correct horse battery staple",
"cipher": "chacha20-poly1305",
"tun_name": "utun7",
"tun_ip": "10.9.0.2",
"tun_netmask": "255.255.255.0",
"peer_ip": "10.9.0.1",
"mtu": 1400
}
```
::: tip Mirror images
`tun_ip` and `peer_ip` swap between the two ends: the server's local tunnel IP
is the client's peer, and vice versa.
:::
## Choosing a cipher
All ciphers are AEAD, from the RustCrypto project:
| `aes-128-gcm` | 16 bytes |
| `aes-256-gcm` | 32 bytes |
| `chacha20-poly1305` | 32 bytes |
The alias `chacha20-ietf-poly1305` is accepted and treated as
`chacha20-poly1305`. The default (when none is specified) is
`chacha20-poly1305` — a good choice everywhere, and the best choice on ARM
hardware without a crypto-enabled build. See the
[ciphers reference](/reference/ciphers).
## Carrier obfuscation
The optional `obfs` field shapes the UDP payload so it doesn't read as an
opaque random blob — `quic` wraps each datagram as a QUIC 1-RTT short-header
packet, `base64` encodes it as printable ASCII. **Both ends must agree**, and
it has no CLI flag:
```json
{
"server": "vpn.example.com:8388",
"password": "correct horse battery staple",
"obfs": "quic"
}
```
This is cosmetic framing only — it adds no security. Details, trade-offs, and
wire formats: [carrier obfuscation](/reference/obfuscation).
## Sharing configs between devices
- Export/import a client config as a single `shadowvpn://` URI or QR code —
see [Config URIs & QR codes](./uri-qr).
- Run many clients off one identical config with the server's
[NAT mode](./multi-client).