Logo

Deploying Sub-Store on VPS (Docker Compose + Caddy)

Published on
...
Authors

Sub-Store is an advanced subscription management tool suitable for Loon, Surge, Quantumult X, Shadowrocket, Clash, and other clients. This tutorial will guide you on how to deploy both Caddy and Sub-Store services simultaneously using Docker Compose.

1. Create Complete Docker Compose File

Create a Docker Compose file that includes both Caddy and Sub-Store:

nano docker-compose.yml

Paste the following content:

version: '3.8'

services:
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - app_network
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  sub-store:
    image: xream/sub-store:latest
    container_name: sub-store
    restart: always
    volumes:
      - sub_store_data:/opt/app/data
    environment:
      - SUB_STORE_BACKEND_API_PORT=3001
      - SUB_STORE_BACKEND_PREFIX=true
      - SUB_STORE_FRONTEND_BACKEND_PATH=/sEcUrEpaThExaMpLe98765
    expose:
      - "3001"
    networks:
      - app_network
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

networks:
  app_network:
    driver: bridge

volumes:
  caddy_data:
  caddy_config:
  sub_store_data:

Note:

  1. SUB_STORE_FRONTEND_BACKEND_PATH should be replaced with a random string for API access security
  2. The above configuration uses a bridge network named app_network, no external network needed
  3. Caddy container maps ports 80 and 443 to the host, ensure these ports are not occupied

2. Optional Environment Variable Configuration

You can add the following optional environment variables as needed:

environment:
  - SUB_STORE_FRONTEND_HOST=0.0.0.0       # Frontend listening address
  - SUB_STORE_FRONTEND_PORT=3001          # Frontend listening port

  - SUB_STORE_BACKEND_SYNC_CRON=0 0 * * * # Auto-sync subscriptions at 0:00 daily
  - SUB_STORE_BACKEND_UPLOAD_CRON=0 1 * * * # Auto-backup config at 1:00 daily
  - SUB_STORE_BACKEND_DOWNLOAD_CRON=30 2 * * 0 # Restore config every Sunday at 2:30

  - GITHUB_USERNAME=your_github_username_here
  - GITHUB_TOKEN=your_github_token_here

  # Push service configuration (optional)
  - SUB_STORE_PUSH_SERVICE=https://api.day.app/XXX/[Push Title]/[Push Content]?sound=shake

3. Create Caddyfile Configuration

Create the Caddyfile configuration file:

nano Caddyfile

Add the following configuration:

# Sub-Store configuration
sub.yourdomain.com {
    reverse_proxy sub-store:3001
    encode gzip
    header {
        # Security headers
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-XSS-Protection "1; mode=block"
        X-Content-Type-Options "nosniff"
        -Server
    }
}

# If you have other services, add them here
# For example:
# n8n.yourdomain.com {
#     reverse_proxy n8n:5678
#     encode gzip
# }

Please replace sub.yourdomain.com with your actual domain name.

4. Start All Services

Use Docker Compose to start all services:

docker compose up -d

5. Verify Service Running Status

Check if containers are running normally:

docker ps

View service logs:

# View Sub-Store logs
docker logs sub-store

# View Caddy logs
docker logs caddy

6. Reload Caddy Configuration (If Modifying Configuration)

If you need to modify the Caddyfile later, you can reload the configuration after editing:

docker exec -w /etc/caddy caddy caddy reload

7. Access Sub-Store

Access in browser: https://sub.yourdomain.com

Sub-Store API address is: https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765

The format for using subscriptions is:

https://sub.yourdomain.com/subs?api=https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765

If using default port and API path, the complete access address is:

https://sub.yourdomain.com/?api=https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765

9. Update Services

When you need to update services, you can use the following commands:

# Pull latest images
docker compose pull

# Update all services
docker compose up -d

# Update only Sub-Store
docker compose up -d --no-deps --build sub-store

# Clean unused images (optional)
docker system prune -f

Security Recommendations

  1. Ensure your VPS firewall has ports 80 and 443 open
  2. The value of SUB_STORE_FRONTEND_BACKEND_PATH should be randomly generated, don't use simple or default values
  3. Recommend configuring Caddy's HTTPS to ensure secure data transmission
  4. Security HTTP headers configured enhance access security
  5. Consider adding access authentication for Sub-Store to prevent unauthorized access

Common Troubleshooting

If you encounter problems, you can check container logs:

docker logs sub-store

Check Caddy logs:

docker logs caddy

If you cannot access, check the following:

  • Confirm containers are running normally: docker ps
  • Confirm network configuration is correct: docker network inspect app_network
  • Confirm firewall has necessary ports open
  • Confirm domain DNS is correctly configured to point to your server IP

Comparison with Other Deployment Methods

This tutorial uses Docker Compose to deploy both Caddy and Sub-Store simultaneously, which has the following advantages compared to other methods:

  1. Integrated Configuration: Manage all related services with one Docker Compose file
  2. Docker Isolation: Deploying with Docker containers is more secure, avoiding dependency conflicts
  3. Caddy Auto HTTPS: Caddy automatically applies and renews SSL certificates, no manual configuration needed
  4. Easy Maintenance: Using Compose files to manage services makes updates and backups simpler
  5. High Reliability: Container auto-restart policy ensures continuous service operation
  6. Flexibility: Can easily add more services to the same environment

Advanced Configuration

Add HTTP Basic Authentication for Sub-Store Frontend

If you need to add basic authentication, modify the Caddyfile:

sub.yourdomain.com {
    reverse_proxy sub-store:3001
    encode gzip

    # Basic authentication configuration
    basicauth {
        username encrypted_password
    }

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-XSS-Protection "1; mode=block"
        X-Content-Type-Options "nosniff"
        -Server
    }
}

To generate encrypted password, you can use:

docker exec -it caddy caddy hash-password

Add Multiple Services

If you want to add more services (like RSSHub, N8N, etc.) to the same environment, simply add new service definitions in docker-compose.yml and configure corresponding reverse proxy rules in Caddyfile.

IP Access Restriction

If you need to restrict access to specific IPs only, modify the Caddyfile:

sub.yourdomain.com {
    @allowed_ips {
        remote_ip 192.168.1.0/24 10.0.0.0/8
    }
    handle @allowed_ips {
        reverse_proxy sub-store:3001
    }
    handle {
        respond "Access denied" 403
    }

    encode gzip
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-XSS-Protection "1; mode=block"
        X-Content-Type-Options "nosniff"
        -Server
    }
}

Through these steps, you have successfully deployed your own Sub-Store service on VPS and can start enjoying convenient subscription management!

Sub-Store Web Usage Guide

Basic Settings

1. Access Sub-Store Web

Use browser to access your deployed Sub-Store address:

https://sub.yourdomain.com

If using default port and API path, the complete access address is:

https://sub.yourdomain.com/?api=https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765

2. Configure Backend

When first entering the Sub-Store web interface, you need to configure the backend address:

  1. Click the settings icon in the upper right corner
  2. Fill in your API address in "Backend Settings": https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765
  3. Click "Save"

Add Subscriptions

Sub-Store can manage three types of subscriptions:

1. Add Airport Subscription

  1. Click "Subscriptions" in the left navigation bar
  2. Click the "+" button in the lower right corner
  3. Select "Add Subscription"
  4. Fill in the form:
    • Name: Give the subscription an easily recognizable name
    • URL: Paste your airport subscription link
    • Type: Select "Subscription"
  5. Click "Save"

2. Add Personal Node

  1. After clicking the "+" button, select "Add Node"
  2. Fill in node information:
    • Name: Name the node
    • Type: Select protocol type (such as Shadowsocks, VMess, Trojan, etc.)
    • Fill in corresponding server information, port, password, etc.
  3. Click "Save"

3. Create Combined Subscription

  1. After clicking the "+" button, select "Add Collection"
  2. Fill in collection information:
    • Name: Name the combined subscription
    • Select subscriptions or nodes to include
  3. Click "Save"

Node Management

1. Node Editing and Operations

Select an added subscription and enter the subscription editing page where you can perform the following operations:

Basic Operations

  • Filter: Check to enable node filtering
  • Sort: Sort nodes by keywords
  • Add Flag: Automatically add country/region flags before node names
  • UDP Relay: Enable UDP traffic forwarding
  • TCP Fast Open: Enable TFO feature
  • Skip Certificate Verification: Turn off TLS certificate verification

Node Renaming

Use regular expressions to rename nodes in the format: regex@replacement

For example:

  • Remove flags: Remove flags from node names @
  • Add prefix: (.*)@[NA] $1 (add "[NA] " prefix before each node)
  • Use counter: .*@Node$count(01) (rename all nodes to "Node01", "Node02", etc.)

2. Use JS Scripts for Advanced Operations

Sub-Store supports using JavaScript scripts for more complex node operations:

  1. On the subscription editing page, click "Script Operations"
  2. Select "Local Script" or "Remote Script"
  3. Fill in script content or URL
    • Node rename script: https://raw.githubusercontent.com/Keywos/rule/refs/heads/main/rename.js I only use this one
    • Node alive test script: https://raw.githubusercontent.com/xream/scripts/main/surge/modules/is-node-alive/index.js
    • Unlock detection script: https://raw.githubusercontent.com/Keywos/rule/main/script/notion.js
  4. Parameter settings
    1. For dlercloud blkey ; iplc+gpt+NF+IPLC+IEPL+[Air]+[Std]+[Pro] name ; dler |
    2. For TAG blkey ; 1x+2x+3x+5x+10x name ; TAG |

Export Subscriptions

After editing, you can export subscriptions to various formats:

  1. Click the "Copy" button on the right side of the subscription
  2. Select target platform (Surge, QX, Clash, etc.)
  3. Copy the generated subscription link

The generated subscription link format is:

https://sub.yourdomain.com/download/[subscription_name]?target=[platform]

But the rules exported this way don't have routing rules

Use File Management to Create Rules

Sub-Store supports creating complete proxy rule configurations through file management:

1. Surge Rule File

  1. Click "File Management" on the left
  2. Click the "+" button to create new file
  3. Name it: surge-config.conf
  4. Content example:
[General]
loglevel = notify
bypass-system = true
dns-server = system, 223.5.5.5, 119.29.29.29
skip-proxy = 127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, localhost, *.local

[Proxy Group]
Proxy = select, policy-path=https://sub.yourdomain.com/download/MySubscription?target=Surge

[Rule]
RULE-SET,https://raw.githubusercontent.com/DivineEngine/Profiles/master/Surge/Ruleset/Global.list,Proxy
FINAL,DIRECT

Surge config files include node addresses, which won't be shown here

2. Mihomo (Clash Meta) Rule File

  1. Create new file, name it: mihomo-config.yaml
  2. Content example:
port: 7890
socks-port: 7891
allow-lan: true
mode: rule
log-level: info

proxies: {}

proxy-providers:
  MySubscription:
    type: http
    url: https://sub.yourdomain.com/download/MySubscription?target=ClashMeta
    interval: 3600
    path: ./proxies/myprovider.yaml
    health-check:
      enable: true
      interval: 300
      url: http://www.gstatic.com/generate_204

proxy-groups:
  - name: 🚀 Node Selection
    type: select
    proxies:
      - ♻️ Auto Select
      - DIRECT
    use:
      - MySubscription

  - name: ♻️ Auto Select
    type: url-test
    use:
      - MySubscription
    url: http://www.gstatic.com/generate_204
    interval: 300

rules:
  - DOMAIN-SUFFIX,google.com,🚀 Node Selection
  - DOMAIN-KEYWORD,google,🚀 Node Selection
  - MATCH,DIRECT

Override(JavaScript/YAML) is supported here

You can maintain your own suitable js file here, for example I use my own https://raw.githubusercontent.com/geekhuashan/Substore-rules/refs/heads/main/Mihomo/override.js

3. Sing-box Rule File

  1. Create new file, name it: sing-box-config.json
  2. Content example:
{
  "dns": {
    "servers": [
      {
        "tag": "dns_proxy",
        "address": "https://1.1.1.1/dns-query",
        "address_resolver": "dns_resolver",
        "strategy": "ipv4_only",
        "detour": "proxy"
      },
      {
        "tag": "dns_direct",
        "address": "https://223.5.5.5/dns-query",
        "address_resolver": "dns_resolver",
        "strategy": "ipv4_only",
        "detour": "direct"
      },
      {
        "tag": "dns_resolver",
        "address": "223.5.5.5",
        "strategy": "ipv4_only",
        "detour": "direct"
      }
    ],
    "rules": [
      {
        "domain": ["geosite:google"],
        "server": "dns_proxy"
      }
    ]
  },
  "inbounds": [
    {
      "type": "mixed",
      "tag": "mixed-in",
      "listen": "::",
      "listen_port": 7890
    }
  ],
  "outbounds": [
    {
      "type": "selector",
      "tag": "proxy",
      "outbounds": ["auto", "all"]
    },
    {
      "type": "urltest",
      "tag": "auto",
      "outbounds": ["all"],
      "url": "https://www.gstatic.com/generate_204",
      "interval": "1m"
    },
    {
      "type": "remote",
      "tag": "all",
      "path": "https://sub.yourdomain.com/download/MySubscription?target=SingBox",
      "cache_file": "./cache/remote.json",
      "download_detour": "direct"
    },
    {
      "type": "direct",
      "tag": "direct"
    },
    {
      "type": "block",
      "tag": "block"
    },
    {
      "type": "dns",
      "tag": "dns-out"
    }
  ],
  "route": {
    "rules": [
      {
        "domain": ["geosite:google"],
        "outbound": "proxy"
      },
      {
        "domain_suffix": [".cn"],
        "outbound": "direct"
      }
    ]
  }
}

Sing-box needs two files, one js to process node information, one json file to define your own routing rules. These are also customized by me, you can find and modify them online. If you don't know how, use Cursor or similar tools for easy vibe coding modifications - that's what I did.

Usage Example: Sub-Store Integration with Mihomo Party

If you use the Mihomo Party client, you can integrate Sub-Store following these steps:

  1. In Mihomo Party, go to "Subscription Management" > "Sub-Store"
  2. Click "Add" button
  3. Enter your Sub-Store backend address: https://sub.yourdomain.com/sEcUrEpaThExaMpLe98765
  4. Select the subscription you created from the dropdown menu
  5. Click "Save"

Now you can directly use Sub-Store managed subscriptions in Mihomo Party.

Advanced Tips

1. Use GitHub to Sync Configuration

Sub-Store supports syncing your configuration via GitHub Gist:

  1. Create a Personal Access Token on GitHub
  2. Fill in the Token in Sub-Store's Settings > Sync
  3. Click "Upload" to create backup
  4. On other devices, fill in the same Token and click "Download" to restore configuration

2. Scheduled Auto-Sync Subscriptions

In some proxy tools, you can set scheduled tasks to automatically sync your subscriptions:

  • Surge: Add scheduled task module
  • Quantumult X: Add scheduled task
  • Loon: Configure scheduled script

Common Problem Resolution

1. Cannot Access Web Page

  • Check if Caddy configuration is correct
  • Confirm ports 80 and 443 are open
  • Verify domain DNS record correctly points to your server

2. Nodes Not Working

  • Check if subscription URL is correct
  • Confirm proxy tool correctly imported the subscription
  • Verify node information is complete

3. Auto-Sync Failed

  • Check GitHub Token permissions are correct
  • Confirm there are no network connection issues
  • Verify Sub-Store service is running normally

Through this guide, you should be able to fully utilize Sub-Store's powerful features to manage your proxy nodes and subscriptions. For more help, visit Sub-Store's GitHub repository for more information.

Deploying Sub-Store on VPS (Docker Compose + Caddy) | 原子比特之间