PasarGuard
Panel

Host Configuration

Proxy host configuration, value overrides, format variables, and filtering

Host Configuration Documentation

This document explains how PasarGuard processes and manages proxy hosts. It's designed to help beginners understand how host configurations work, what values override inbound defaults, and how hosts are displayed to users in subscriptions.

Table of Contents

  1. Overview
  2. Host Configuration Basics
  3. Value Override Priority
  4. Host Fields and Their Behavior
  5. Format Variables for User Display
  6. Transport Settings
  7. Host Status and Filtering
  8. API Limits and Constraints
  9. Common Scenarios

Overview

Hosts in PasarGuard are proxy server configurations that:

  • Override default values from XRay inbound configurations
  • Provide server addresses, ports, and transport settings
  • Display customized names (remarks) to users in subscriptions
  • Filter which users can see which hosts based on status

Subscription Generation Process

When a user requests a subscription, PasarGuard:

  1. Checks user's accessible inbounds - Only hosts whose inbound_tag is accessible to the user (through their groups) are processed
  2. Loads all enabled hosts that match the user's status
  3. Merges host settings with inbound defaults (host values take priority)
  4. Formats host remarks and addresses using user-specific variables
  5. Randomly selects values from lists (SNI, host, address, port) for each request
  6. Generates the subscription configuration

Host Visibility Requirements

A host will only appear in a user's subscription if:

  • The host's inbound_tag is assigned to at least one of the user's groups
  • The user's groups are not disabled
  • The host is not disabled (is_disabled: false)
  • The host's status filter (if set) includes the user's status

Host Configuration Basics

Required Fields

Every host must have:

FieldTypeDescription
remarkstringDisplay name shown to users (supports format variables)
inbound_tagstringMust match a tag from one of your XRay core configurations. Important: This inbound must be assigned to user groups for users to see this host
priorityintegerOrder hosts appear in subscriptions (lower = higher priority)

Optional Fields

Hosts can override inbound defaults for:

  • Network Settings: address, port, sni, host, path
  • Security Settings: security, alpn, fingerprint, allowinsecure
  • Transport Settings: Network-specific configurations (WebSocket, gRPC, etc.)
  • Advanced Features: Mux, fragment, noise settings
  • Display Options: status (which user statuses can see this host)

Value Override Priority

When generating subscriptions, PasarGuard merges values in this order:

Priority Order (Highest to Lowest)

  1. Host Configuration - Values set on the host override everything
  2. Inbound Defaults - Values from the XRay inbound configuration
  3. System Defaults - Built-in fallback values

How Overrides Work

Final Value = Host Value (if set) OR Inbound Value (if exists) OR System Default

Host value overrides inbound:

  • Inbound has sni: ["example.com"]
  • Host has sni: ["host1.com", "host2.com"]
  • Result: sni: ["host1.com", "host2.com"] (host value wins)

Inbound value used when host not set:

  • Inbound has port: 443
  • Host has port: null (not set)
  • Result: port: 443 (inbound value used)

Host Fields and Their Behavior

Basic Network Fields

address (Set of Strings)

  • Purpose: Server IP addresses or domain names
  • Override: Host value replaces inbound value completely
  • Display: Randomly selected per subscription request
  • Format Variables: Supports {SERVER_IP}, {SERVER_IPV6}, {USERNAME}, etc.
  • Limit: Combined string length max 256 characters
  • Wildcards: Supports * which gets replaced with random salt per request

Example:

{
  "address": ["1.2.3.4", "server.example.com", "{SERVER_IP}"]
}

port (Integer)

  • Purpose: Server port number
  • Override: Host port replaces inbound port
  • Special: If not set, uses inbound port (can be single int or comma-separated string like "8080,8443")
  • Display: If inbound has multiple ports, one is randomly selected per request

Example:

{
  "port": 443  // Overrides inbound port
}
// OR
{
  "port": null  // Uses inbound port (could be multiple)
}

sni (Set of Strings)

  • Purpose: Server Name Indication for TLS
  • Override: Host value replaces inbound SNI list
  • Display: Randomly selected per subscription request
  • Limit: Combined string length max 1000 characters
  • Wildcards: Supports * which gets replaced with random salt

Example:

{
  "sni": ["example.com", "*.example.com", "cdn.example.com"]
}

host (Set of Strings)

  • Purpose: Host header for HTTP/WebSocket transports
  • Override: Host value replaces inbound host list
  • Display: Randomly selected per subscription request
  • Limit: Combined string length max 1000 characters
  • Wildcards: Supports * which gets replaced with random salt

Example:

{
  "host": ["example.com", "www.example.com"]
}

path (String)

  • Purpose: Path for WebSocket, gRPC, HTTP transports
  • Override: Host path replaces inbound path if set
  • Format Variables: Supports {PROTOCOL}, {TRANSPORT}, {USERNAME}, etc.
  • Default: Uses inbound path if host path is not set

Example:

{
  "path": "/{PROTOCOL}-{TRANSPORT}/path"
}

Security Settings

security (Enum: ProxyHostSecurity)

  • Purpose: TLS/Reality security type
  • Options:
    • inbound_default - Use security from inbound configuration
    • none - No encryption
    • tls - TLS encryption
    • reality - Reality protocol
  • Override: Host security replaces inbound security (unless set to inbound_default)

Example:

{
  "security": "tls"  // Overrides inbound security
}
// OR
{
  "security": "inbound_default"  // Uses inbound security
}

alpn (List of ProxyHostALPN)

  • Purpose: Application-Layer Protocol Negotiation
  • Options: h3, h2, http/1.1
  • Override: Host ALPN list replaces inbound ALPN
  • Special: Automatically sorted by priority (h3 → h2 → http/1.1)
  • Default: Uses inbound ALPN if not set

Example:

{
  "alpn": ["h3", "h2", "http/1.1"]
}

fingerprint (Enum: ProxyHostFingerprint)

  • Purpose: TLS fingerprint type
  • Override: Host fingerprint replaces inbound fingerprint (unless set to none)
  • Default: Uses inbound fingerprint (usually chrome for Reality)

Example:

{
  "fingerprint": "chrome"  // Overrides inbound fingerprint
}
// OR
{
  "fingerprint": "none"  // Uses inbound fingerprint
}

allowinsecure (Boolean)

  • Purpose: Allow insecure TLS connections
  • Override: Host value replaces inbound value if set
  • Default: Uses inbound value (usually false)

Example:

{
  "allowinsecure": false  // Overrides inbound setting
}

ech_config_list (String)

  • Purpose: Encrypted Client Hello (ECH) configuration
  • Override: Host value replaces inbound value if set
  • Default: Uses inbound value if not set

Advanced Features

use_sni_as_host (Boolean)

  • Purpose: Use SNI value as host header
  • Behavior: When true, the selected SNI value replaces the host header
  • Default: false

random_user_agent (Boolean)

  • Purpose: Generate random User-Agent headers
  • Behavior: When true, random User-Agent is added to HTTP headers
  • Default: false

http_headers (Dictionary)

  • Purpose: Custom HTTP headers
  • Format: {"Header-Name": "value"}
  • Override: Host headers are added to transport config

Example:

{
  "http_headers": {
    "X-Forwarded-For": "1.2.3.4",
    "Custom-Header": "value"
  }
}

is_disabled (Boolean)

  • Purpose: Temporarily disable host without deleting
  • Behavior: Disabled hosts are excluded from subscriptions
  • Default: false

status (Set of UserStatus)

  • Purpose: Filter which user statuses can see this host
  • Options: active, expired, limited, disabled, on_hold
  • Behavior: If set, only users with matching status see this host
  • Default: null (all users can see it)

Example:

{
  "status": ["active", "on_hold"]  // Only active and on_hold users see this
}

Format Variables for User Display

Host remark and address fields support format variables that are replaced with user-specific values when generating subscriptions.

Available Format Variables

VariableDescriptionExample
{SERVER_IP}Server's public IPv4 address1.2.3.4
{SERVER_IPV6}Server's public IPv6 address2001:db8::1
{USERNAME}User's usernamejohn_doe
{PROTOCOL}Protocol name (vmess, vless, etc.)vless
{TRANSPORT}Transport type (tcp, ws, grpc, etc.)ws
{DATA_USAGE}User's data usage (formatted)1.5 GB
{DATA_LIMIT}User's data limit (formatted)100 GB or
{DATA_LEFT}Remaining data (formatted)98.5 GB or
{DAYS_LEFT}Days until expiration30 or
{EXPIRE_DATE}Expiration date (Gregorian)2024-12-31
{JALALI_EXPIRE_DATE}Expiration date (Jalali)1403-10-11
{TIME_LEFT}Time until expiration (formatted)30 days or
{STATUS_EMOJI}User status emoji, ⌛️, 🪫, , 🔌
{USAGE_PERCENTAGE}Data usage percentage15.5 or
{ADMIN_USERNAME}Admin who created the useradmin

Format Variable Examples

Remark Examples:

{
  "remark": "{PROTOCOL}-{TRANSPORT} Server {STATUS_EMOJI}"
}
// Results in: "vless-ws Server ✅" (for active user)
{
  "remark": "{USERNAME} - {DATA_LEFT} left"
}
// Results in: "john_doe - 98.5 GB left"
{
  "remark": "Server {SERVER_IP} - Expires {EXPIRE_DATE}"
}
// Results in: "Server 1.2.3.4 - Expires 2024-12-31"

Address Examples:

{
  "address": ["{SERVER_IP}", "cdn-{USERNAME}.example.com"]
}
// Results in random selection: "1.2.3.4" or "cdn-john_doe.example.com"

Missing Variables:

If a format variable is not available (e.g., user has no expiration), it will be replaced with:

  • for date/time/limit fields
  • - for dates when user is on hold
  • <missing> for other missing variables

Transport Settings

Hosts can configure network-specific transport settings that override inbound defaults.

WebSocket Settings

{
  "transport_settings": {
    "websocket_settings": {
      "heartbeatPeriod": 30  // Heartbeat interval in seconds
    }
  }
}

gRPC Settings

{
  "transport_settings": {
    "grpc_settings": {
      "multi_mode": true,  // Enable multi-mode
      "idle_timeout": 60,  // Idle timeout in seconds
      "health_check_timeout": 20,  // Health check timeout
      "permit_without_stream": false,  // Require stream
      "initial_windows_size": 1048576  // Initial window size
    }
  }
}

KCP Settings

{
  "transport_settings": {
    "kcp_settings": {
      "header": "wechat-video",  // Header type
      "mtu": 1350,  // Maximum Transmission Unit
      "tti": 20,  // Transmission Time Interval
      "uplink_capacity": 5,  // Uplink capacity
      "downlink_capacity": 20,  // Downlink capacity
      "congestion": false,  // Congestion control
      "read_buffer_size": 2,  // Read buffer size
      "write_buffer_size": 2  // Write buffer size
    }
  }
}

TCP Settings

{
  "transport_settings": {
    "tcp_settings": {
      "header": "http",  // Header type: "none" or "http"
      "request": {
        "method": "GET",
        "version": "1.1",
        "headers": {
          "Host": ["example.com"]
        }
      },
      "response": {
        "status": "200",
        "reason": "OK",
        "version": "1.1"
      }
    }
  }
}

XHTTP/SplitHTTP Settings

{
  "transport_settings": {
    "xhttp_settings": {
      "mode": "auto",  // auto, packet-up, stream-up, stream-one
      "no_grpc_header": false,  // Disable gRPC header
      "x_padding_bytes": "1-100",  // Padding bytes range
      "sc_max_each_post_bytes": 1048576,  // Max post bytes
      "sc_min_posts_interval_ms": 100,  // Min interval between posts
      "xmux": {
        "maxConcurrency": 8,
        "maxConnections": 8,
        "cMaxReuseTimes": 1,
        "hMaxReusableSecs": 300,
        "hMaxRequestTimes": 8,
        "hKeepAlivePeriod": 15
      },
      "download_settings": 2  // ID of another host for download
    }
  }
}

Download Settings

download_settings references another host ID for XHTTP download functionality. The referenced host cannot have its own download host (no nesting).

Mux Settings

{
  "mux_settings": {
    "xray": {
      "enabled": true,
      "concurrency": 8,
      "xudpConcurrency": 8,
      "xudpProxyUDP443": "reject"  // reject, allow, skip
    },
    "sing_box": {
      "enable": true,
      "protocol": "smux",  // smux, yamux, h2mux
      "max_connections": 8,
      "max_streams": 8,
      "min_streams": 1,
      "padding": false,
      "brutal": {
        "enable": true,
        "up_mbps": 100,
        "down_mbps": 100
      }
    },
    "clash": {
      // Same as sing_box plus:
      "statistic": false,
      "only_tcp": false
    }
  }
}

Fragment Settings

{
  "fragment_settings": {
    "xray": {
      "packets": "tlshello",  // or range like "1-10"
      "length": "100-200",  // Fragment length range
      "interval": "10-20"  // Interval range
    },
    "sing_box": {
      "fragment": true,
      "fragment_fallback_delay": "100ms",
      "record_fragment": false
    }
  }
}

Noise Settings

{
  "noise_settings": {
    "xray": [
      {
        "type": "rand",  // rand, str, base64, hex
        "packet": "base64-encoded-data",
        "delay": "10-20",  // Delay range
        "apply_to": "ip"  // ip, ipv4, ipv6
      }
    ]
  }
}

Host Status and Filtering

How Host Filtering Works

When generating a subscription, hosts are filtered in this order:

  1. Inbound Access Check: Host's inbound_tag must be accessible to the user through their groups

    • Users belong to groups
    • Groups have inbound tags assigned to them
    • Only hosts whose inbound_tag is in the user's accessible inbounds (from all their groups) are processed
    • Disabled groups are excluded from this check
    • This is the first and most important filter - if a user doesn't have access to the inbound through their groups, the host will never appear in their subscription
  2. Disabled Check: Hosts with is_disabled: true are excluded

  3. Status Check: If host has status set, user's status must match one of the values in the set

  4. Priority Sort: Remaining hosts are sorted by priority (ascending)

Understanding Inbound Access Through Groups

How it works:

  • Users are assigned to groups
  • Groups have inbound tags assigned to them (many-to-many relationship)
  • When generating a subscription, PasarGuard collects all inbound tags from all of the user's groups (excluding disabled groups)
  • Only hosts whose inbound_tag matches one of these accessible inbounds will be included

Example:

User "john" belongs to:
  - Group "Premium" (inbound_tags: ["vless-443", "trojan-8443"])
  - Group "Standard" (inbound_tags: ["vmess-8080"])

Hosts:
  - Host A (inbound_tag: "vless-443") ✅ Will appear (in Premium group)
  - Host B (inbound_tag: "trojan-8443") ✅ Will appear (in Premium group)
  - Host C (inbound_tag: "vmess-8080") ✅ Will appear (in Standard group)
  - Host D (inbound_tag: "shadowsocks-9090") ❌ Will NOT appear (not in any group)

No Groups = No Hosts

If a user has no groups, or all their groups are disabled, they will see no hosts in their subscription.

Status Filtering Examples

Host visible to all users:

{
  "status": null  // or empty set
}

Host visible only to active users:

{
  "status": ["active"]
}

Host visible to active and on_hold users:

{
  "status": ["active", "on_hold"]
}

Priority Ordering

Hosts are sorted by priority field (lower number = higher priority):

{
  "priority": 1  // Appears first in subscription
}
{
  "priority": 100  // Appears later in subscription
}

API Limits and Constraints

Field Limits

FieldLimitDescription
remarkMust be valid format stringSupports format variables
addressCombined string length max 256 charsSet of address strings
sniCombined string length max 1000 charsSet of SNI strings
hostCombined string length max 1000 charsSet of host strings
inbound_tagMust exist in core configsValidated against XRay configs

Validation Rules

  1. Inbound Tag Validation

    • inbound_tag must exist in at least one XRay core configuration
    • Validated when creating or modifying hosts
  2. Download Settings Validation

    • If xhttp_settings.download_settings is set, it must reference a valid host ID
    • Referenced host cannot be the same as the current host
    • Referenced host cannot have its own download host (no nesting)
  3. Format Variable Validation

    • remark must be a valid format string
    • Invalid format variables will cause errors
  4. ALPN Validation

    • ALPN list is automatically deduplicated
    • ALPN list is automatically sorted by priority (h3 → h2 → http/1.1)

API Endpoints

  • GET /api/host/{host_id} - Get host by ID
  • GET /api/hosts - List all hosts (with pagination)
  • POST /api/host/ - Create new host
  • PUT /api/host/{host_id} - Modify existing host
  • DELETE /api/host/{host_id} - Delete host
  • PUT /api/hosts - Bulk modify hosts

Authentication

All endpoints require sudo admin privileges.


Common Scenarios

Scenario 1: Override Inbound Port

Problem: Inbound uses port 443, but you want this host to use port 8443.

Solution:

{
  "inbound_tag": "my-inbound",
  "port": 8443,  // Overrides inbound port
  "remark": "Custom Port Server"
}

Scenario 2: Multiple SNI Values

Problem: You want to randomly select from multiple SNI values per request.

Solution:

{
  "sni": ["example.com", "cdn.example.com", "www.example.com"]
}
// Each subscription request randomly picks one

Scenario 3: User-Specific Server Names

Problem: You want each user to see their username in the server address.

Solution:

{
  "address": ["{USERNAME}.example.com", "{SERVER_IP}"],
  "remark": "Server for {USERNAME}"
}

Scenario 4: Status-Based Host Visibility

Problem: You want a premium server only visible to active users.

Solution:

{
  "remark": "Premium Server",
  "status": ["active"],  // Only active users see this
  "priority": 1  // High priority
}

Group Access Required

The host's inbound_tag must also be assigned to the user's groups. The status filter only works on hosts that are already accessible through groups.

Scenario 4b: Group-Based Host Access

Problem: You want a host to be visible only to users in specific groups.

Solution:

  1. Create a group (e.g., "VIP Group")
  2. Assign the host's inbound_tag to that group
  3. Only assign users to that group who should see the host
// Host configuration
{
  "inbound_tag": "vless-premium-443",
  "remark": "VIP Server"
}

// Group configuration (via API)
{
  "name": "VIP Group",
  "inbound_tags": ["vless-premium-443"]  // Must match host's inbound_tag
}

Users in "VIP Group" will see this host. Users not in this group will not see it, regardless of other settings.

Scenario 5: Override Security Type

Problem: Inbound uses TLS, but you want this host to use Reality.

Solution:

{
  "security": "reality",  // Overrides inbound security
  "sni": ["reality.example.com"]
}

Scenario 6: Custom Path with Variables

Problem: You want path to include protocol and transport type.

Solution:

{
  "path": "/{PROTOCOL}/{TRANSPORT}/path"
}
// Results in: "/vless/ws/path"

Scenario 7: Multiple Ports from Inbound

Problem: Inbound has ports "8080,8443,9090" and you want to use all of them.

Solution:

{
  "port": null  // Don't set port, uses inbound's multiple ports
}
// Each subscription request randomly picks one port

Scenario 8: XHTTP with Download Host

Problem: You want to configure XHTTP with a download host.

Solution:

{
  "transport_settings": {
    "xhttp_settings": {
      "mode": "auto",
      "download_settings": 5  // Reference to host ID 5
    }
  }
}

Scenario 9: Wildcard SNI with Random Salt

Problem: You want SNI to have random subdomain per request.

Solution:

{
  "sni": ["*.example.com"]
}
// Each request: "a1b2c3d4.example.com" (random salt replaces *)

Scenario 10: Priority Ordering

Problem: You want certain hosts to appear first in subscriptions.

Solution:

// High priority host
{
  "remark": "Primary Server",
  "priority": 1
}

// Lower priority host
{
  "remark": "Backup Server",
  "priority": 100
}

Summary

Best Practices

  • Host values override inbound defaults - Host settings take priority over inbound defaults
  • Inbound access through groups is required - Hosts only appear if their inbound_tag is assigned to the user's groups
  • Use format variables in remark and address for user-specific display
  • Multiple values are randomly selected - SNI, host, address, and port values are randomly chosen per subscription request
  • Wildcards (*) in SNI/host/address are replaced with random salt
  • Host status filters which users can see the host (but only if inbound is accessible through groups)
  • Host priority determines order in subscriptions
  • inbound_tag must exist in your XRay core configurations AND be assigned to user groups
  • Transport settings override inbound defaults for specific networks
  • Disabled hosts (is_disabled: true) are excluded from subscriptions
  • Format variables are replaced with user-specific values when generating subscriptions
  • Group-based access control - Users only see hosts whose inbounds are in their assigned groups

For more information about XRay configuration, see Core Configuration.