OxidProxy — User Guide
Document version: 1.11
Software version: 2.4.1
Website: https://oxidproxy.com
Support: support@oxidproxy.com · Telegram
Contents
- Product overview
- System requirements
- Installation
- Initial setup
- Configuration (config.yaml)
- 5.1 Licensing
- 5.2 Network settings
- 5.3 OS fingerprinting
- 5.4 IPv6 subnets and rotation
- 5.5 API and user management
- 5.6 DNS resolver
- 5.7 Traffic shaping
- 5.8 Timeouts
- 5.9 Service account
- 5.10 Blacklist
- 5.11 Logging
- 5.12 MITM mode (mitm_listeners)
- 5.13 Dashboard branding - HTTP API
- Web dashboard
- Service management
- Logging and monitoring
- Command line (CLI)
- Troubleshooting
- FAQ
- Changelog
1. Product overview
OxidProxy is a high-performance SOCKS5(h) / HTTP CONNECT IPv6 proxy server written in Rust. It is meant to run on your own dedicated or virtual server and acts as a gateway: it accepts incoming connections over IPv4, authenticates them and routes traffic through the IPv6 subnets you configure.
Key features
| Feature | Description |
|---|---|
| SOCKS5 / SOCKS5h | Full protocol support, including remote DNS, which prevents DNS leaks |
| HTTP CONNECT | HTTP(S) proxy mode via the CONNECT method, for browsers, curl and system proxy settings |
| Hybrid Mode | Automatic protocol detection (SOCKS5 or HTTP) on a single port |
| UDP / QUIC | Full UDP proxying, including QUIC (HTTP/3) |
| Multiple subnets | Attach several IPv6 subnets and balance between them by weight |
| Lazy rotation | The IP changes only on re-authentication; active sessions are never dropped |
| Smart DNS Failover | Built-in resolver with balancing and automatic failover to backup servers |
| OS Fingerprinting (p0f) | TCP/IP fingerprint masking as Linux, Android, Windows, iOS or macOS |
| Traffic Shaping | Total bandwidth limiting with burst support |
| HTTP(S) API | Instant credential generation, statistics and management over a REST API |
| IP Whitelist | Manage allowed addresses and subnets from the dashboard; system entries are protected |
| Web dashboard | Built-in monitoring panel with traffic charts, connection analytics and selectable themes |
| Blacklist | Block domains and IP addresses through blacklist.txt |
| Service account | A restricted account intended for checkers and monitoring |
How it works
Your software OxidProxy Server IPv6 subnets Internet
(SOCKS5h/HTTP) → Auth • DNS • Shaping → Subnet A (w:100) → Target
Subnet B (w:50)
2. System requirements
| Item | Minimum | Recommended |
|---|---|---|
| OS | Debian 12 (Bookworm) x64 | Debian 12 (Bookworm) x64 |
| CPU | 1 core | 2 or more cores |
| RAM | 512 MB | 1 GB or more, depending on max_accounts |
| IPv6 | a /64 subnet | a /48 or /32 subnet |
| Privileges | root, for installation | The service itself runs as the oxidproxy user |
6.1.177-oxidproxy-p0f. Without it every other feature still works normally.3. Installation
3.1. Automatic installation (recommended)
Run as root:
curl -fsSL https://oxidproxy.com/downloads/install.sh | bash
The script will:
1. Download and install the custom Linux kernel with the p0f patch
2. Configure GRUB to boot the new kernel by default
3. Download and install the OxidProxy package
4. Create the oxidproxy system user
5. Set up the systemd service
6. Offer to reboot the server
3.2. Manual installation
- Download the .deb package from the downloads page
- Install the package:
dpkg -i oxidproxy_*.deb
# If dependencies fail:
apt-get install -f -y
- Optionally, install the custom kernel for p0f:
dpkg -i linux-image-6.1.177-oxidproxy-p0f_6.1.177-oxidproxy-p0f-1_amd64.deb
update-grub
6.1.177-oxidproxy-p0f is available on the downloads page. It is needed to build out-of-tree kernel modules.3.3. What the installer creates
| Path | Purpose |
|---|---|
/usr/bin/oxidproxy |
The executable |
/etc/oxidproxy/config.yaml |
Main configuration file |
/etc/oxidproxy/blacklist.txt |
List of blocked domains and addresses |
/etc/oxidproxy/whitelist.txt |
Whitelist of allowed addresses and subnets |
/etc/rc.local |
IPv6 routing rules; created during installation if absent |
/etc/sysctl.d/90-oxidproxy.conf |
Kernel settings (sysctl) |
/usr/lib/systemd/system/oxidproxy.service |
systemd unit file |
/etc/logrotate.d/oxidproxy |
Log rotation configuration |
/var/log/oxidproxy/ |
Log directory |
/var/lib/oxidproxy/ |
Data directory, used for exported accounts |
4. Initial setup
The service does not start automatically after installation. Complete these steps first:
The server checks these values when it starts. If license_key,
master_token or public_ip still hold the values from the
template, the service says which one and does not start, so a half-configured
server never goes live.
Step 1. Edit the configuration
nano /etc/oxidproxy/config.yaml
These must be filled in:
- license_key — your licence key, obtained via Telegram
- public_ip — the external IPv4 address of your server
- ipv6_subnets — your IPv6 subnets
- master_token — the secret API token; replace the default
Step 2. Set up IPv6 routing
Edit /etc/rc.local and uncomment the route line:
nano /etc/rc.local
Replace the placeholder with your real subnet:
ip -6 route add local 2a01:xxxx::/32 dev lo
Step 3. Validate the configuration
oxidproxy -t /etc/oxidproxy/config.yaml
It should print ✅ Syntax OK. followed by a summary of the main settings.
Step 4. Reboot the server
reboot
Required to activate the custom kernel and the routing rules.
Step 5. Start the service
systemctl start oxidproxy
systemctl status oxidproxy
5. Configuration (config.yaml)
Every setting lives in /etc/oxidproxy/config.yaml. Restart the service to apply changes.
oxidproxy -t before restarting.5.1. Licensing
license_key: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# license_servers: optional - see the note below
| Parameter | Description |
|---|---|
license_key |
Required. The licence key you received on purchase |
license_servers |
Optional. The regular endpoints are built into the server, so there is nothing to set here. Fill it in only with an address given to you by support, for instance when the usual endpoints are unreachable from your network. Entries here are tried first. |
About the licence server addresses. They no longer belong in the config: they are built into the server and spread across two independently registered domains, so that one becoming unreachable does not stop licence checks.
The license_servers parameter is needed in one case only: support has given you
a dedicated address. Such addresses are tried before the built-in ones, so a working
endpoint takes effect immediately, without waiting through timeouts on unreachable ones.
license_servers:
- "address.given.by.support:8000"Order of attempts: addresses from the config first, if any, then the built-in ones. A server that answers successfully moves to the front of the list and is used for subsequent checks.
oxidproxy --ping address:port — useful when support has given you a dedicated address and you want to confirm it is reachable from your network. The built-in endpoints need no manual checking; the server walks them itself.5.2. Network settings
listen_ip: "0.0.0.0"
public_ip: "123.45.67.89"
# ext_iface: "eth0" # optional
| Parameter | Description | Default |
|---|---|---|
listen_ip |
Interface to accept incoming connections on | 0.0.0.0 (all interfaces) |
public_ip |
Required. Public IPv4 address of the server, used by the API and in generated links | — |
ext_iface |
External interface used for QoS. Detected automatically when not set | auto |
5.3. OS fingerprinting
The listeners section defines several ports, each with its own TCP/IP fingerprint profile. Anti-fraud systems that inspect traffic with tools such as p0f will see the parameters characteristic of the chosen operating system.
Every listener supports a mode field that selects the protocol:
| Mode | Description |
|---|---|
socks |
SOCKS5 / SOCKS5h (default) |
http |
HTTP CONNECT proxy, using the CONNECT method with Proxy-Authorization: Basic |
hybrid |
Auto-detect: SOCKS5 and HTTP on one port. The protocol is determined from the first byte |
listeners:
- port: 1080
os_preset: "linux"
# mode: "socks" # the default, may be omitted
- port: 1081
os_preset: "android"
mode: "hybrid" # accepts both SOCKS5 and HTTP CONNECT
- port: 1082
os_preset: "windows"
mode: "http"
- port: 1083
os_preset: "ios"
mode: "socks"
- port: 1084
os_preset: "macos"
mode: "http"
hybrid is the recommended mode. One port serves both protocols, so no extra ports need opening, and detection is instant, from the first byte.Available profiles:
| Profile | TTL | TCP MSS | Congestion Control | Description |
|---|---|---|---|---|
linux |
64 | System default | cubic | A standard Linux server |
android |
64 | Common for the platform | bbr | A mobile Android client |
windows |
128 | Common for the platform | cubic | A Windows machine |
ios |
64 | Common for the platform | cubic | iPhone / iPad |
macos |
64 | Common for the platform | cubic | A macOS desktop |
linux profile emulates nothing and keeps the system value.Fine-tuning (for experienced users only):
Each listener accepts manual network parameters:
- port: 1081
os_preset: "android"
tcp_congestion: "bbr" # congestion control algorithm
tcp_window_size: 1048576 # TCP window size, bytes
latency_base_ms: 60 # base latency, ms
jitter_ms: 30 # jitter, ms
tos: 10 # traffic class (QoS marker)
5.4. IPv6 subnets and rotation
ipv6_subnets:
- cidr: "2a01:xxxx::/32"
weight: 427
- cidr: "2a02:yyyy:yyyy:yyyy::/64"
weight: 16
rotation_interval: 10
| Parameter | Description |
|---|---|
cidr |
IPv6 subnet in CIDR notation. Any size is supported: /29, /32, /48, /64 and so on |
weight |
Subnet weight. The higher the value, the more often the subnet is used for outgoing addresses |
rotation_interval |
Rotation interval in minutes. 0 disables rotation, and the IP is kept until restart |
How rotation works:
- The IP address is bound to a login and password pair (a sticky session)
- On every authentication the server checks whether rotation_interval has elapsed
- If it has, a new IPv6 is generated from the subnets, honouring their weights
- Active connections are never dropped — the IP changes only on a new connection
- A session idle for more than 5 minutes is closed; this is tunable via timeouts.idle
5.5. API and user management
api_port: 8080
api_port_https: 8443 # optional - HTTPS API
master_token: "my-secret-token"
max_accounts: 100000
accounts_file: "/var/lib/oxidproxy/accounts_[port]_[os]_[mode].txt"
# account_seed: 123456789
| Parameter | Description | Default |
|---|---|---|
api_port |
HTTP API port | 8080 |
api_port_https |
HTTPS API port (optional) | — |
master_token |
Required. Secret token used to authenticate API requests | — |
max_accounts |
Maximum number of unique accounts generated, each with its own IPv6 | 100000 |
accounts_file |
Path for exported accounts. Supports the [port], [os] and [mode] macros |
accounts.txt |
account_seed |
Generation seed. With the same seed, logins and passwords stay identical across restarts | random |
account_seed when accounts must stay the same across restarts. This helps when integrating with external systems, as credentials never need updating.5.6. DNS resolver
Names are resolved by the server itself. One cache is shared by all
listeners, so a name looked up for one client is already resolved for the
next. Servers carrying a weight share the load between them;
those without one are used only when the weighted ones do not answer. The
resolver keeps track of how each server behaves and stops sending queries to
one that stopped answering, returning to it a little later. When the first
server is slow, the next is queried in parallel and the first answer wins,
so a single slow server does not hold the client up.
timeout is what a single server is given to answer, not what
the client waits: with the parallel query above the client normally gets an
answer sooner. Its job is to decide how quickly a server that went quiet is
taken out of rotation, so it is kept short. Raise it to 2 if healthy servers
are being taken out. What each server is doing right now is visible in
/stats, section 6.2.
dns:
timeout: 1
cache_size: 8000
suppress_aaaa_not_found: true
servers:
# primary servers (balanced)
- address: "[2606:4700:4700::1111]:53"
weight: 53
- address: "1.1.1.1:53"
weight: 7
# failover servers
- address: "[2620:fe::fe]:53"
- address: "9.9.9.9:53"
| Parameter | Description | Default |
|---|---|---|
timeout |
DNS query timeout, in seconds | 2 |
cache_size |
Number of cached DNS records | 1024 |
suppress_aaaa_not_found |
Suppress warnings about domains that have no AAAA record | false |
How it works:
1. The query goes to one of the primary servers, chosen by weight — the higher the weight, the more often that server is used. There may be several primaries.
2. If a primary does not answer, whether by timeout or error, the query falls through to the failover pool. There may be several of those too; they are listed without a weight.
3. A domain that exists but has no AAAA record is not a connection error, so failover is not triggered
/etc/resolv.conf, or can be obtained from the provider's support. Provider resolvers typically answer in 1–2 ms, against 10–50 ms for Google or Cloudflare.5.7. Traffic shaping
shaping:
rate: 12500000 # 100 Mbit/s
burst: 25000000 # 200 Mbit/s burst
| Parameter | Description |
|---|---|
rate |
Maximum rate in bytes per second. 0 means unlimited |
burst |
Burst allowance in bytes, letting transfers briefly exceed rate |
Cheat sheet:
| Speed | rate value |
|---|---|
| 1 Mbit/s | 125 000 |
| 10 Mbit/s | 1 250 000 |
| 100 Mbit/s | 12 500 000 |
| 1 Gbit/s | 125 000 000 |
5.8. Timeouts
timeouts:
shutdown: 10 # how long to wait for sessions to finish on shutdown, sec
idle: 300 # maximum session idle time, sec
| Parameter | Description | Default |
|---|---|---|
shutdown |
How long, in seconds, to wait for active connections to finish when the service stops or restarts | 15 |
idle |
Maximum idle time of a TCP or UDP session before it is closed | 300 (5 min) |
5.9. Service account
service_account:
enabled: true
login: "checker"
password: "strong_password"
allowed_domain: "ifconfig.me"
The service account is meant for monitoring and health checks. Its properties:
- Static login and password: neither generated nor rotated
- Can reach only one domain, set by allowed_domain
- Does not consume rotation limits
- Never changes its IP
allowed_domain: "ifconfig.me" and verify the outgoing IP with curl --proxy socks5://checker:password@IP:PORT ifconfig.me.5.10. Blacklist
blocked_file: "/etc/oxidproxy/blacklist.txt"
The file lists blocked domains and IP addresses, one per line. Comments start with #.
# blocking ad domains
doubleclick.net
ads.google.com
# blocking private IPv6 networks
fc00::/7
fe80::/10
google.com is blocked, then mail.google.com and ads.google.com are unreachable as well.5.11. Logging
log:
dir: "/var/log/oxidproxy"
level: "info"
| Level | Description |
|---|---|
error |
Critical errors only |
warn |
Errors and warnings |
info |
Main events: connections, DNS, rotation — recommended |
debug |
Verbose debugging: every session, every DNS query |
Two log files are produced:
- oxidproxy.log — the full log, at the verbosity set by level
- error.log — errors only, always
Journal-only logging. The dir parameter is optional. Leave it empty,
or drop it altogether, and no files are written to disk: everything goes to the system journal, where
journalctl -u oxidproxy picks it up.
log:
dir: "" # empty = journal only
level: "info"This suits setups where journald already collects everything and a second copy on disk is
unwanted. The log section may be omitted entirely, in which case the level defaults
to info.
To confirm: oxidproxy -t /etc/oxidproxy/config.yaml reports
Log Dir: not set, logging to journal only.
5.12. MITM mode (mitm_listeners)
In MITM mode OxidProxy terminates the client TLS connection with its own certificate authority and rebuilds the request to the target with the network fingerprint of a real browser: JA4 in full, HTTP/2 and Akamai. The profile is chosen automatically from the client User-Agent, so one port serves every OS and browser — Chrome, Firefox and Safari on Windows, macOS, Linux, Android and iOS.
MITM listeners are declared in their own mitm_listeners section and run alongside the regular listeners:
mitm_listeners:
- port: 8443
profiles:
- "windows-chrome"
- "windows-firefox"
- "macos-safari"
- "android-chrome"
- "ios-safari"
default: "windows-chrome" # profile used when the client UA is not recognised
# strict: false # true = refuse instead of falling back to default
# mode: socks # socks / http / hybrid, as for regular listenersProfiles are named <os>-<browser>. The available ones are:
| OS | Profiles |
|---|---|
| Windows | windows-chrome, windows-firefox, windows-edge |
| macOS | macos-chrome, macos-firefox, macos-safari |
| Linux | linux-chrome, linux-firefox |
| Android | android-chrome, android-firefox |
| iOS | ios-safari |
Listener fields:
| Parameter | Description |
|---|---|
port |
Port of the MITM listener |
profiles |
List of allowed <os>-<browser> profiles. The right one is chosen from the client User-Agent |
default |
Profile used when the User-Agent is unrecognised or not in the list |
strict |
When true, refuse the connection on a mismatch instead of falling back to default. Defaults to false |
mode |
Listener protocol: socks (the default), http or hybrid, exactly as for regular listeners. When omitted, the port runs in socks mode. |
/ca endpoint.5.13. Dashboard branding
The web dashboard can carry your own mark instead of ours. This exists for resellers: a customer's panel has no business advertising the vendor behind it.
brand:
name: "Acme"
accent: "Proxy"
url: "https://acme.example"
| Parameter | Description |
|---|---|
name |
First half of the wordmark, shown in the main text colour |
accent |
Second half, painted in the accent colour of whichever theme is selected. Leave empty for a single-colour wordmark |
url |
Where the wordmark links to. An empty value drops the link entirely. Only http:// and https:// are accepted |
The setting reaches further than the header. It also renames the browser tab, the theme label in the selector, and the CA certificate the dashboard offers for download — that file is handed to end users, so a leftover name there would give the game away.
6. HTTP API
The API is reachable at http://YOUR_IP:PORT or https://YOUR_IP:PORT, where PORT comes from api_port and api_port_https in the configuration, 8080 and 8443 by default.
Requests are authenticated with the token parameter, whose value is master_token.
Every endpoint answers with a standard HTTP status: 200 when the request succeeded, 401 when the token is missing or wrong, 400 when the request cannot be satisfied as written — for example a mode the listener does not serve — and 500 when the server cannot answer, such as a configuration with no listeners at all. The explanation is in the body; the status is what a script should branch on.
6.1. New credentials — GET /allocate
Returns a connection string with a fresh login and password. The listener is selected by port — the same URL the dashboard produces (section 7.6):
curl "http://YOUR_IP:8080/allocate?token=YOUR_TOKEN&port=1080&mode=socks5"
Response:
socks5://user_AbCdEfGh:KlMnOpQrSt@YOUR_IP:1080
Query parameters:
| Parameter | Description | Default |
|---|---|---|
token |
Required. The secret master_token | — |
port |
Port of the listener the credentials are for. Identifies the listener unambiguously | — |
mode |
Protocol: socks5 or http |
socks5 |
os |
OS profile: linux, android, windows, ios, macos. Selects the listener by profile; ignored when port is given |
linux |
The port identifies the listener unambiguously. os selects it by profile;
when several listeners share that profile, the first one in the configuration is
returned. A port or profile that is not in the configuration is answered with 400 and
a list of what is configured.
Examples:
# Credentials for the listener on port 1081
curl "http://YOUR_IP:8080/allocate?token=YOUR_TOKEN&port=1081&mode=socks5"
# response: socks5://user_xxx:pass_xxx@YOUR_IP:1081
# Same listener, HTTP proxy (listener in http or hybrid mode)
curl "http://YOUR_IP:8080/allocate?token=YOUR_TOKEN&port=1081&mode=http"
# response: http://user_xxx:pass_xxx@YOUR_IP:1081
# By OS profile
curl "http://YOUR_IP:8080/allocate?token=YOUR_TOKEN&os=android"
Error: no listener on port 1090. Configured ports: 1080, 1081, 1082Error: http mode is not enabled for 'linux' profile (port 1080). Listener mode: sockshybrid mode both mode=socks5 and mode=http work on the same port.6.2. Statistics — GET /stats
Returns full server statistics as JSON.
curl "http://YOUR_IP:8080/stats?token=YOUR_TOKEN"
Example response, abridged: the listeners and mitm_listeners fields are omitted, being an echo of the matching config sections.
{
"version": "2.0.0",
"uptime_seconds": 9980,
"active_connections": { "tcp": 56, "udp": 4 },
"mitm": { "active": 3, "total": 512 },
"traffic": {
"ingress_bytes": 264074969,
"egress_bytes": 35524983
},
"dns": {
"total_queries": 18905,
"cache_hits": 17106,
"cache_stale_served": 12,
"cache_misses": 1799,
"cache_entries": 1420,
"inflight_joined": 63,
"hedge_fired": 208,
"hedge_won_by_backup": 41,
"all_failed": 3,
"bad_names": 0,
"servers": [
{
"address": "[2606:4700:4700::1111]:53",
"weight": 53, "state": "healthy",
"queries": 1502, "failures": 7,
"timeouts": 6, "servfails": 1, "net_errors": 0,
"consecutive_failures": 0,
"last_failure_ago_s": 1840, "last_error": "Timeout"
},
{
"address": "1.1.1.1:53",
"weight": 7, "state": "healthy",
"queries": 261, "failures": 0,
"timeouts": 0, "servfails": 0, "net_errors": 0,
"consecutive_failures": 0,
"last_failure_ago_s": null, "last_error": null
},
{
"address": "[2620:fe::fe]:53",
"weight": null, "state": "healthy",
"queries": 36, "failures": 0,
"timeouts": 0, "servfails": 0, "net_errors": 0,
"consecutive_failures": 0,
"last_failure_ago_s": null, "last_error": null
}
]
},
"events": {
"total_connections": 18963,
"connection_errors": 12,
"access_denied": 0,
"blocked_domains": 0,
"dns_no_ipv6": 4,
"firewall_blocks": 0
},
"license": {
"expires_at_unix": 1770484105,
"days_left": 29,
"is_active": true,
"servers": {
"L1": "online",
"L2": "online"
}
},
"telemetry": {
"cpu_cores": 2,
"total_mem_mb": 2048,
"latest_cpu_usage": 4.8,
"latest_mem_mb": 96
},
"server_ip": "1.2.3.4",
"shaper": {
"enabled": false,
"rate_bytes": 0,
"burst_bytes": 0
}
}
Key fields:
| Field | Description |
|---|---|
mitm |
Active and cumulative connections through MITM ports since startup |
dns |
Cache hit and miss counts, how often the parallel query to a backup was used, and a line per server: its state, weight, how many queries it served and how its failures break down into timeouts, SERVFAILs and network errors. A server that stopped answering shows up here first |
events.dns_no_ipv6 / firewall_blocks |
Domains without an AAAA record, and connections refused by the IP whitelist — the same categories as the dashboard chart in section 7.3 |
license.is_active |
Whether the licence is currently confirmed. When false, the proxy ports stay closed until the next check |
telemetry |
Server CPU and RAM usage — the data behind the hardware panel in section 7.1 |
server_ip |
The public_ip value from the configuration |
shaper |
Current shaping limits and counters, see section 5.7 |
listeners / mitm_listeners |
A verbatim echo of the matching config.yaml sections, handy for scripts that need the list of active ports and profiles |
7. Web dashboard
The built-in dashboard is available at:
http://YOUR_IP:8080/dashboard?token=YOUR_TOKEN
7.1. Live monitoring
The dashboard lives at http://YOUR_IP:PORT/dashboard?token=YOUR_TOKEN, where PORT is the configured api_port. HTTPS is supported too, via api_port_https.
It refreshes every 10 seconds and shows:
- Hardware — CPU load, with the core count, and RAM usage, both with progress bars
- Network traffic — total ingress and egress in readable units, plus total and active TCP/UDP connection counts
- Licence and status — days remaining and the live online/offline state of each licence server
- Version and uptime — in the header
7.2. Traffic charts
Two throughput charts (Rx/Tx in Mbit/s) with average labels:
- Hourly — the last 60 minutes, one point per minute
- Daily — the last 24 hours, one point per hour
7.3. Connection Analytics
The doughnut chart breaks all connections down by category:
| Category | Colour | Description |
|---|---|---|
| Success | green | Successfully proxied connections |
| Auth Denied | yellow | Refused because authentication failed |
| Conn Errors | purple | Network errors while establishing the connection |
| Blocked (DPI) | grey | Blocked by the domain blacklist |
| No IPv6 | blue | Domains with no AAAA record, that is, no IPv6 |
| Firewall Blocks | red | Refused by the IP whitelist |
7.4. IP whitelist management
The IP Whitelist panel manages allowed addresses and subnets straight from the browser, without restarting the service:
- View — lists every entry, with a lock icon marking system entries that cannot be removed
- Add — the input accepts a single address or a CIDR subnet such as 192.168.1.0/24. Press + Add Entry or Enter
- Remove — the button next to each entry. Removing 0.0.0.0/0 asks for confirmation, to avoid locking yourself out
- Import — the Import button loads a .txt file of addresses or CIDRs, one per line, with # comments supported
The list refreshes every 10 seconds, so changes made from another device or by another administrator appear without reloading the page.
0.0.0.0/0 entry allows connections from every address. Remove it and only the addresses explicitly listed will reach the proxy — make sure your own is among them first.7.5. Recent Blocks
The Recent Blocks panel shows the last blocked connections, up to ten, with the address and the time. The Total counter gives the number of blocks since the service last started.
7.6. AUTO-ROTATION API LINKS
At the top of the dashboard, quick-copy buttons are generated per OS profile: Linux, Android, Windows, iOS and macOS. The SOCKS5 and HTTP buttons are disabled when that protocol is not enabled for the profile.
Clicking a button copies the credential-request URL (GET /allocate?port=...&mode=...) to the clipboard and shows a toast in the corner.
Below them, the TXT SOCKS5 and TXT HTTP buttons download the account file for that profile and mode directly. A button is disabled when the mode is not enabled for the profile, or the account file does not exist yet.
MITM listeners get their own card, holding the connection link and a Download CA certificate button. The client installs that CA once, after which all HTTPS traffic goes out under the selected browser profile.
7.8. Downloading account files
The Downloads section offers the account files for download, grouped by OS profile and proxy mode:
| File | Contents |
|---|---|
accounts_1080_linux_socks5.txt |
SOCKS5 accounts for the Linux profile, port 1080 |
accounts_1081_android_socks5.txt |
SOCKS5 accounts for the Android profile |
accounts_1081_android_http.txt |
HTTP accounts for the Android profile in hybrid mode |
accounts_1082_windows_http.txt |
HTTP accounts for the Windows profile |
Each file holds lines of the form protocol://login:password@IP:PORT, ready to import anywhere.
listeners and accounts_file settings. Hybrid listeners produce two files, SOCKS5 and HTTP.7.7. Themes
The dashboard offers eight themes, switchable without reloading. The choice is remembered in the browser:
| Theme | Description |
|---|---|
| OxidProxy Dark | The brand dark theme, used by default |
| Light Classic | Classic light |
| Dracula | Dark, purple and pink |
| Deep Ocean | Deep navy |
| Teal Lagoon | Dark teal |
| Gruvbox Retro | Warm retro palette |
| Baroque Bling 💰 | Baroque, with gold accents |
| Hacker | Monochrome green on black |
8. Service management
OxidProxy installs as a systemd service and runs as the oxidproxy user.
# start
systemctl start oxidproxy
# stop, gracefully - waits for active sessions to finish
systemctl stop oxidproxy
# restart
systemctl restart oxidproxy
# status
systemctl status oxidproxy
# enable at boot
systemctl enable oxidproxy
# follow the logs
journalctl -u oxidproxy -f
systemctl start oxidproxy: systemd switches to the oxidproxy user declared in the unit file.9. Logging and monitoring
Log files
| File | Description |
|---|---|
/var/log/oxidproxy/oxidproxy.log |
Main log, at the verbosity set in the config |
/var/log/oxidproxy/error.log |
Errors only |
Log rotation
Logs are rotated automatically by logrotate:
- Daily, or once a file reaches 100 MB
- The last 10 generations are kept
- Compressed with gzip
System telemetry
Every 10 seconds a [SYS_STATS] line is written to the log:
[SYS_STATS] System Mem: 524/2048 MB | App Mem: 85 MB | CPU: 12.3% | Conns: 42 / 4096
10. Command line (CLI)
oxidproxy [OPTIONS]
Options:
-c, --config <PATH> Path to the configuration file (default: config.yaml)
-t, --test [<PATH>] Validate the configuration syntax
-g, --generate Write a sample config.yaml.example
-b, --blacklist Write a sample blacklist.txt.example
-H, --hwid Show the server HWID
-p, --ping <HOST:PORT> Check that a licence server is reachable
-V, --version Show the version
-h, --help Show this help
Examples:
# run with the default config
oxidproxy
# run with a specific config
oxidproxy -c /etc/oxidproxy/config.yaml
# validate the config before deploying
oxidproxy -t /etc/oxidproxy/config.yaml
# generate a sample configuration
oxidproxy -g
# check that a licence server is reachable
oxidproxy --ping address.given.by.support:8000
# show the HWID
oxidproxy -H
11. Troubleshooting
The service will not start
-
Validate the configuration:
oxidproxy -t /etc/oxidproxy/config.yaml -
Check the logs:
journalctl -u oxidproxy --no-pager -n 50 -
Check the licence server:
oxidproxy --ping <HOST:PORT>
Use an address given to you by support. The regular endpoints are built into the server and need no manual checking.
No connection through the proxy
- Make sure the client speaks a supported protocol: SOCKS5, SOCKS5h or HTTP CONNECT. SOCKS5h is recommended for maximum anonymity, as DNS is then resolved on the server.
- Check IPv6 routing — inspect
/etc/rc.localand the output of:
ip -6 route show - Confirm the port is reachable from outside:
ss -tlnp | grep oxidproxy - Check the firewall (iptables or nftables)
Some sites do not open
OxidProxy works over IPv6 only. A target site without an AAAA record simply cannot be reached.
To check for an AAAA record:
dig AAAA example.com
The IP does not change
OxidProxy uses sticky sessions: the IP is bound to a login and password pair. To change it:
- Request new credentials via GET /allocate
- Or wait for rotation_interval to elapse and reconnect
12. FAQ
Q: What is SOCKS5h, and how does it differ from SOCKS5?
A: With SOCKS5h, DNS queries are resolved on the proxy server. Plain SOCKS5 resolves them on the client, which can leak DNS traffic and expose the real address. Always prefer SOCKS5h.
Q: Why are new logins and passwords generated on every restart?
A: By default accounts derive from a random seed. Uncomment and set account_seed in the config and the credentials will stay the same across restarts.
Q: Can I use several IPv6 subnets?
A: Yes. Add them to ipv6_subnets with different weights, and traffic is distributed in proportion.
Q: How do I find my server HWID?
A: Run oxidproxy -H. The HWID binds the licence to the machine.
Q: How much does OxidProxy consume?
A: With 100,000 accounts and around 50 active connections, roughly 80–120 MB of RAM and about 5% of one CPU core. Being written in Rust gives it high throughput and predictable memory use.
Q: Is the API secure?
A: With api_port_https enabled the API is served over HTTPS. Access is protected by master_token. Statistics at /stats are reachable without a token only from localhost.
Q: What is HTTP CONNECT mode?
A: HTTP CONNECT is the standard way to proxy HTTPS. The client sends CONNECT host:443 HTTP/1.1 with a Proxy-Authorization: Basic header, and an encrypted tunnel is established. Every browser supports it, as do curl, system proxy settings and most software.
Example with curl:
curl -x http://user_xxx:pass_xxx@YOUR_IP:1081 https://ifconfig.me
Q: How does hybrid differ from separate socks and http ports?
A: In hybrid mode one port accepts both. The protocol is detected from the first byte of the connection (0x05 means SOCKS5, anything else HTTP). It saves opening extra ports, and every feature — p0f, shaping, DNS, limits — behaves identically for both.
Q: What does the [mode] macro do in accounts_file?
A: On export, [mode] is replaced by the protocol, either socks5 or http. Hybrid listeners produce two files: one with socks5:// links and one with http://. For example accounts_1081_android_socks5.txt and accounts_1081_android_http.txt.
Q: The browser reports a certificate error on a MITM port.
A: A MITM port terminates TLS with its own certificate authority, so the client device must add the server CA to its trust store once; otherwise the browser treats the connection as insecure. The certificate is available from the /ca endpoint, or via the download button on the MITM card in the dashboard, described in section 7.6.
Q: What happens if the client User-Agent matches none of the mitm_listeners profiles?
A: By default the server falls back to the profile named in default. Set strict: true and it will refuse the connection instead.
13. Changelog
v2.4.1 — September 2026
- Config check without a path —
oxidproxy -tchecks the installed configuration at/etc/oxidproxy/config.yaml; no path required.
v2.4.0 — September 2026
- Network profiles improved — connection characteristics are closer to real networks and profile behaviour is more natural.
v2.3.7 — September 2026
- Listener selected by port in
/allocate— theportparameter names the listener exactly, which matters when several listeners share one profile and differ in their settings. Theosparameter keeps working. - Parameter checking in
/allocate— a port or profile that is not in the configuration is answered with 400 and a list of what is configured.
v2.3.6 — September 2026
- New DNS resolver — a shared cache across all listeners, per-server availability tracking and a parallel query to a backup. Resolution is faster and steadier, and the range of supported names is wider.
- Detailed DNS statistics in
/stats— each server reports its state, weight and the kind of failures it returns, which makes diagnosis straightforward. - UDP mode optimised — session reliability and network compatibility improved.
- SOCKS5: precise reply codes — the client is told the actual reason a connection did not happen.
- HTTP mode optimised — better resilience under load and wider client compatibility.
- iOS profiles brought in line with real devices.
- Browser mode improved — higher accuracy and better site compatibility; large uploads use less memory.
- Configuration is checked at startup — the service points at unfilled mandatory fields at once and will not start while
license_key,master_tokenorpublic_ipstill hold template values. - Standard API status codes —
/allocate,/statsand/dashboardreturn 401 for a wrong token and 400 for an invalid request. - Dashboard: dark theme readability improved.
v2.2.0 — September 2026
- Lower latency on the profiles — mobile profiles (
android,ios) add 30 ms, desktop ones (windows,macos) 10 ms, andlinuxadds nothing. The previous values were set too high and cost tens of milliseconds on every request. A value set explicitly inconfig.yamltakes precedence: the defaults apply only where the key is absent. jitter_msis no longer applied — the key is still accepted and configurations carrying it keep working, but the service notes it in the log at startup.- Throughput ceiling removed — it showed up under heavy load.
v2.1.2 — August 2026
- The MITM port refuses non-browser clients — curl, scripts and anything else that sends no browser
User-Agentget a short page explaining why, instead of going out under a profile they do not match. Addallow_unknown_ua: trueto the listener to restore the previous behaviour. Browsers are unaffected. - Login banner over SSH — optional, offered during installation. It shows whether the service is running, which kernel is booted, which subnets are configured and where the dashboard lives, and warns when
master_tokenis still the template value. The token itself is deliberately left out; thedashboard-urlcommand prints the full link on request. - Browser version matches the handshake — for traffic with no browser
User-Agent, the server now claims the version whose TLS handshake the emulation actually reproduces.
v2.1.0 — August 2026
- Updated custom kernel —
6.1.177-oxidproxy-p0freplaces 6.1.170, with the matchinglinux-headerspackage published beside it on the downloads page. - Licence endpoints are built in —
license_serversis no longer a required key. The field is now Additional license servers and is normally left out of the configuration entirely; fill it in only when support gives you an address. - Journal-only logging — leave
log.dirempty and the server writes to the systemd journal instead of files, which suits hosts where logs are collected centrally. - More varied TCP fingerprint — the MSS is no longer a single fixed value shared by every connection. It is drawn from a realistic distribution and stays stable for a given outgoing address, so a profile no longer stands out by repeating the same value everywhere.
- Readable log-directory errors — an unwritable directory is reported at startup instead of crashing the service.
- Honest p0f status — when the kernel cannot supply the fingerprint, the server says so plainly rather than falling back quietly.
v2.0.0 — June 2026
- MITM mode — a new mode of operation: the server terminates TLS with its own CA and rebuilds traffic to the target with the network fingerprint of a real browser (Chrome, Firefox, Safari) across every layer — JA4 in full, HTTP/2 and Akamai. The profile is chosen automatically from the client
User-Agent, so one port serves every OS. - The
mitm_listenerssection — dedicated MITM ports alongside the regularlisteners, with a list of allowed<os>-<browser>profiles and a default one. - MITM card in the dashboard — the connection link and a button to download the CA certificate for the client trust store.
v1.8.1 — May 2026
- RFC-conformant QUIC — a substantial rework of the UDP/QUIC implementation: deviations from the specification removed, client compatibility improved, packet loss under high load reduced.
- New custom kernel 6.1.170-oxidproxy-p0f — greatly improved hardware compatibility. It now boots on any hypervisor and hardware configuration as reliably as the stock Debian 12 kernel; the previous build failed to boot on some setups.
- Account file downloads from the dashboard — the AUTO-ROTATION API LINKS block gained TXT SOCKS5 and TXT HTTP buttons that download the account lists directly, grouped by OS profile and mode.
v1.7.1 — April 2026
- Dashboard: IP whitelist — full whitelist management from the browser: add, remove, import from a file. Changes take effect immediately, without restarting the service.
- Dashboard auto-refresh — IP whitelist and Recent Blocks now update every 10 seconds along with the rest of the statistics.
- Connection analytics — a new doughnut chart breaking connections down by category: successful, blocked, errored, IPv4-only domains.
- Recent Blocks — a panel listing the latest blocked connections with timestamps and a running total.
- Themes — five dashboard themes added, with the choice remembered in the browser.
- HTTP CONNECT support — a full HTTP proxy mode with
Proxy-Authorization: Basicand correct handling of every header variant. - Improved robustness — a busy dashboard API port no longer causes a silent crash; the error is now reported explicitly in the log.
- Dashboard layout fix — widget column edges no longer misalign at different screen resolutions.
v1.7.0 — March 2026
- Hybrid mode — automatic protocol detection (SOCKS5 or HTTP CONNECT) on a single port, from the first byte of the connection.
- HTTP proxy — the
httpmode added to thelistenerssection. - The
[mode]macro inaccounts_file— hybrid listeners export two account files, one with SOCKS5 links and one with HTTP.
v1.6.0 — January 2026
- HTTPS API — an optional
api_port_httpsport. - Smart DNS failover — a backup pool of resolvers with automatic switching when a primary is unreachable.
- Service account — a static account restricted to a single domain, for checkers and monitoring.