# How to Use Subscription URLs for Proxy Servers in the Fanqiang Project

> Learn how to use subscription URLs to automatically fetch and manage proxy server configurations for your Fanqiang project. Simplify your proxy setup today.

- Repository: [如何翻墙/fanqiang](https://github.com/bannedbook/fanqiang)
- Tags: how-to-guide
- Published: 2026-09-06

---

**Subscription URLs provide a standardized way to distribute proxy node configurations to client applications, allowing automatic fetching, parsing, and storage of proxy servers.**

In the **bannedbook/fanqiang** repository, subscription URLs power both the Android client (Sagernet-based) and the macOS GUI client (V2RayX). This guide explains the complete workflow—from URL format to database storage—with direct references to the source code implementation.

---

## What Is a Subscription URL?

A **subscription URL** is a plain-text HTTP endpoint that returns a list of proxy node configurations. Common formats include **Vmess**, **Shadowsocks**, **Trojan**, and other proxy protocols.

Example URL:

```

https://example.com/subscription

```

The response body contains newline-separated proxy URIs:

```

vmess://eyJ2IjogIjIiLCAicHMiOiAiU2VydmVyIDEiLCAiYWRkIjogIjEuMi4zLjQiLCAicG9ydCI6ICI0NDMiLCAiaWQiOiAiLi4uIn0=
ss://YWVzLTI1Ni1nY206password@server:port

```

---

## Subscription URL Workflow in the Android Client

The Android implementation follows a five-step pipeline defined in `RawUpdater.doUpdate`【https://github.com/bannedbook/fanqiang/blob/master/fqnews2/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt】.

### 1. HTTP Fetch with Custom User-Agent

The client issues an HTTP GET request. The User-Agent can be customized through `DataStore` settings.

```kotlin
// From RawUpdater.kt - simplified fetch logic
val response = HttpURLConnection(url).apply {
    setRequestProperty("User-Agent", userAgent ?: "Sagernet/*")
}.inputStream.use { it.readBytes() }

```

### 2. Protocol-Specific Parsing

The response body passes through format-specific parsers. For **Vmess** and universal formats, `UniversalFmt` handles the conversion【https://github.com/bannedbook/fanqiang/blob/master/fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/UniversalFmt.kt】.

### 3. Database Storage

Parsed proxies are stored in `SubscriptionBean`【https://github.com/bannedbook/fanqiang/blob/master/fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java】 and linked to a `ProxyGroup`.

```kotlin
// SubscriptionBean.java core fields
@Entity(tableName = "subscription_bean")
public class SubscriptionBean {
    public long id;
    public String name;
    public String url;              // the subscription URL
    public String subscriptionUserinfo; // traffic quota data
    public long lastUpdated;
}

```

### 4. Optional Cleanup Steps

- **Force resolve**: Converts hostnames to IP addresses
- **Deduplication**: Removes duplicate server entries before storage

### 5. Routing Engine Integration

The proxy list becomes available to the **routing engine** and updates the UI's selectable servers list.

---

## Configuring Subscription URLs Programmatically

### Manual Subscription Update

Trigger an immediate update for a specific group:

```kotlin
// Assume proxyGroup already has a SubscriptionBean attached
val subscription = proxyGroup.subscription!!
RawUpdater.doUpdate(proxyGroup, subscription, null, byUser = true)

```

### Persistent Subscription Settings

Store the subscription URL and auto-update preferences in `DataStore`【https://github.com/bannedbook/fanqiang/blob/master/fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt】:

```kotlin
val ds = DataStore(context)
ds.subscriptionLink = "https://example.com/subscription"
ds.subscriptionAutoUpdate = true        // enable background updates
ds.subscriptionAutoUpdateDelay = 360    // check every 360 seconds

```

The `subscriptionAutoUpdate` flag controls whether the app periodically refreshes the subscription.

---

## Subscription URL Handling in macOS (V2RayX)

The macOS client exposes subscription URLs through a graphical interface. According to [`macos/V2rayX.md`](https://github.com/bannedbook/fanqiang/blob/main/macos/V2rayX.md)【https://github.com/bannedbook/fanqiang/blob/master/macos/V2rayX.md】:

1. Open **V2RayX** → click the menu icon → **Configure…** → **Advanced**
2. Switch to the **Subscription** tab, click the **+** button
3. Double-click **"enter your subscription link here"**, paste your URL, click outside to confirm
4. Click **Finish** — V2RayX fetches immediately and populates the server table

No code changes required; the GUI handles fetching, parsing, and storage automatically.

---

## Testing Subscription URLs Manually

Verify a subscription endpoint with curl:

```bash
curl -A "FanQiang/Android" https://example.com/subscription

```

Expected output: newline-separated proxy URIs. Check for:
- Valid base64 encoding (vmess://, vless:// prefixes)
- Complete server address, port, and authentication credentials

---

## Subscription-Userinfo Header Support

If the HTTP response includes a `Subscription-Userinfo` header, the Android client saves it to `SubscriptionBean.subscriptionUserinfo`. This typically contains traffic quota information:

```

Subscription-Userinfo: upload=1234567; download=7654321; total=1073741824; expire=1893456000

```

The macOS client displays comparable data in its subscription panel when available.

---

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`fqnews2/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt) | HTTP fetch orchestration and update workflow |
| [`fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java) | Persistent storage model for subscription data |
| [`fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt) | Global settings: URL, auto-update flags, delays |
| [`fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/UniversalFmt.kt`](https://github.com/bannedbook/fanqiang/blob/main/fqnews2/app/src/main/java/io/nekohasekai/sagernet/fmt/UniversalFmt.kt) | Protocol parser for vmess and universal formats |
| [`macos/V2rayX.md`](https://github.com/bannedbook/fanqiang/blob/main/macos/V2rayX.md) | End-user documentation for macOS subscription setup |

---

## Summary

- **Subscription URLs** are HTTP endpoints returning proxy node lists in vmess, Shadowsocks, or similar formats
- The Android client implements a complete pipeline: fetch in `RawUpdater.doUpdate`, parse in `UniversalFmt`, store in `SubscriptionBean`
- **Auto-update** behavior is controlled by `DataStore.subscriptionAutoUpdate` and `subscriptionAutoUpdateDelay`
- The **macOS V2RayX client** provides equivalent functionality through a GUI subscription panel
- Traffic quota data from `Subscription-Userinfo` headers persists for user visibility

---

## Frequently Asked Questions

### How do I add a subscription URL in the Android fanqiang app?

Set `DataStore.subscriptionLink` to your URL and enable `subscriptionAutoUpdate`. Trigger manual updates by calling `RawUpdater.doUpdate(proxyGroup, subscription, null, byUser = true)` with your target group.

### What format should my subscription URL return?

Plain text with newline-separated proxy URIs. Supported protocols include vmess://, vless://, ss://, ssr://, and trojan://. The `UniversalFmt` parser in [`UniversalFmt.kt`](https://github.com/bannedbook/fanqiang/blob/main/UniversalFmt.kt) handles the conversion.

### How often does the Android client refresh subscriptions?

Controlled by `DataStore.subscriptionAutoUpdateDelay`, measured in seconds. Default behavior checks periodically when `subscriptionAutoUpdate` is true. Manual updates bypass this interval.

### Does the macOS client support the same subscription features?

Yes. V2RayX fetches and parses identically, storing results in its local server list. The interface exposes URL input and immediate refresh through the **Subscription** tab in **Advanced** settings.