Skip to content

appleboy/gorush

Repository files navigation

gorush

A push notification micro server using Gin framework written in Go (Golang) and see the demo app.

Run Lint and TestingTrivy Security ScanGoDoccodecovGo Report CardDocker PullsNetlify StatusFinancial Contributors on Open Collective

Quick Start

Get started with gorush in 3 simple steps:

# 1. Download the latest binary wget https://github.com/appleboy/gorush/releases/download/v1.18.9/gorush-1.18.9-linux-amd64 -O gorush chmod +x gorush # 2. Start the server (default port 8088) ./gorush # 3. Send your first notification curl -X POST http://localhost:8088/api/push \ -H "Content-Type: application/json" \ -d '{ "notifications": [{ "tokens": ["your_device_token"], "platform": 2, "title": "Hello World", "message": "Your first notification!" }] }'

📱 Platform codes: 1 = iOS (APNS), 2 = Android (FCM), 3 = Huawei (HMS)

Contents

Support Platform

A live server on Netlify and get notification token on Firebase Cloud Messaging web. You can use the token to send a notification to the device.

curl -X POST \ -H "Content-Type: application/json" \ -d '{ "notifications": [{ "tokens": [ "your_device_token" ], "platform": 2, "title": "Test Title", "message": "Test Message" } ]}' \ https://gorush.netlify.app/api/push

Features

  • Support Firebase Cloud Messaging using go-fcm library for Android.
  • Support HTTP/2 Apple Push Notification Service using apns2 library.
  • Support HMS Push Service using go-hms-push library for Huawei Devices.
  • Support YAML configuration.
  • Support command line to send single Android or iOS notification.
  • Support Web API to send push notification.
  • Support HTTP/2 or HTTP/1.1 protocol.
  • Support notification queue and multiple workers.
  • Support /api/stat/app show notification success and failure counts.
  • Support /api/config show your YAML config.
  • Support store app stat to memory, Redis, BoltDB, BuntDB, LevelDB or BadgerDB.
  • Support p8, p12 or pem format of iOS certificate file.
  • Support /sys/stats show response time, status code count, etc.
  • Support for HTTP, HTTPS or SOCKS5 proxy.
  • Support retry send notification if server response is fail.
  • Support expose prometheus metrics.
  • Support install TLS certificates from Let's Encrypt automatically.
  • Support send notification through RPC protocol, we use gRPC as default framework.
  • Support running in Docker, Kubernetes or AWS Lambda (Native Support in Golang)
  • Support graceful shutdown that workers and queue have been sent to APNs/FCM before shutdown service.
  • Support different Queue as backend like NSQ, NATS or Redis streams, defaut engine is local Channel.

Performance: Average memory usage ~28MB. Supports high-throughput notification delivery with configurable workers and queue systems.

Configuration

Gorush uses YAML configuration. Create a config.yml file with your settings:

Basic Configuration

core: port: "8088"# HTTP server portworker_num: 0# Workers (0 = CPU cores)queue_num: 8192# Queue sizemode: "release"# or "debug"# Enable platforms you needandroid: enabled: truekey_path: "fcm-key.json"# FCM service account keyios: enabled: truekey_path: "apns-key.pem"# APNS certificateproduction: true # Use production APNShuawei: enabled: falseappid: "YOUR_APP_ID"appsecret: "YOUR_APP_SECRET"

Advanced Configuration

Click to expand full configuration options
core: enabled: trueaddress: ""shutdown_timeout: 30port: "8088"worker_num: 0queue_num: 0max_notification: 100sync: falsefeedback_hook_url: ""feedback_timeout: 10feedback_header: mode: "release"ssl: falsecert_path: "cert.pem"key_path: "key.pem"cert_base64: ""key_base64: ""http_proxy: ""pid: enabled: falsepath: "gorush.pid"override: trueauto_tls: enabled: falsefolder: ".cache"host: ""grpc: enabled: falseport: 9000api: push_uri: "/api/push"stat_go_uri: "/api/stat/go"stat_app_uri: "/api/stat/app"config_uri: "/api/config"sys_stat_uri: "/sys/stats"metric_uri: "/metrics"health_uri: "/healthz"android: enabled: truekey_path: ""credential: ""max_retry: 0huawei: enabled: falseappsecret: "YOUR_APP_SECRET"appid: "YOUR_APP_ID"max_retry: 0queue: engine: "local"nsq: addr: 127.0.0.1:4150topic: gorushchannel: gorushnats: addr: 127.0.0.1:4222subj: gorushqueue: gorushredis: addr: 127.0.0.1:6379group: gorushconsumer: gorushstream_name: gorushwith_tls: falseusername: ""password: ""db: 0ios: enabled: falsekey_path: ""key_base64: ""key_type: "pem"password: ""production: falsemax_concurrent_pushes: 100max_retry: 0key_id: ""team_id: ""log: format: "string"access_log: "stdout"access_level: "debug"error_log: "stderr"error_level: "error"hide_token: truehide_messages: falsestat: engine: "memory"redis: cluster: falseaddr: "localhost:6379"username: ""password: ""db: 0boltdb: path: "bolt.db"bucket: "gorush"buntdb: path: "bunt.db"leveldb: path: "level.db"badgerdb: path: "badger.db"

See the complete example config file.

Installation

Recommended: Install Script

The easiest way to install gorush is using the install script:

curl -fsSL https://raw.githubusercontent.com/appleboy/gorush/master/install.sh | bash

This will automatically:

  • Detect your OS and architecture
  • Download the latest version
  • Install to ~/.gorush/bin
  • Add to your PATH

Options:

# Install specific version (replace X.Y.Z with the desired version, e.g., 1.19.2) VERSION=X.Y.Z curl -fsSL https://raw.githubusercontent.com/appleboy/gorush/master/install.sh | bash # Custom install directory INSTALL_DIR=/usr/local/bin curl -fsSL https://raw.githubusercontent.com/appleboy/gorush/master/install.sh | bash # Skip SSL verification (not recommended) INSECURE=1 curl -fsSL https://raw.githubusercontent.com/appleboy/gorush/master/install.sh | bash

Manual Download

Download from releases page:

Package Managers

Homebrew (macOS/Linux)

brew tap appleboy/tap brew install gorush

Go Install

# Latest stable version go install github.com/appleboy/gorush@latest # Development version go install github.com/appleboy/gorush@master

Build from Source

Requirements: Go 1.24+, Git

git clone https://github.com/appleboy/gorush.git cd gorush make build # Binary will be in the root directory

Docker

# Run directly docker run --rm -p 8088:8088 appleboy/gorush # With custom config docker run --rm -p 8088:8088 -v $(pwd)/config.yml:/home/gorush/config.yml appleboy/gorush

Usage

Starting the Server

# Use default config (port 8088) ./gorush # Use custom config file ./gorush -c config.yml # Set specific options ./gorush -p 9000 -c config.yml

Command Line Notifications

Android (FCM)

Prerequisites: Generate FCM service account key from Firebase Console → Settings → Service Accounts → Generate New Private Key.

# Single notification gorush -android -m "Hello Android!" --fcm-key "path/to/fcm-key.json" -t "device_token"# Using environment variable (recommended)export GOOGLE_APPLICATION_CREDENTIALS="path/to/fcm-key.json" gorush -android -m "Hello Android!" -t "device_token"# Topic message gorush --android --topic "news" -m "Breaking News!" --fcm-key "path/to/fcm-key.json"

iOS (APNS)

# Development environment gorush -ios -m "Hello iOS!" -i "cert.pem" -t "device_token" --topic "com.example.app"# Production environment gorush -ios -m "Hello iOS!" -i "cert.pem" -t "device_token" --topic "com.example.app" -production # With password-protected certificate gorush -ios -m "Hello iOS!" -i "cert.p12" -P "cert_password" -t "device_token"

Huawei (HMS)

# Single notification gorush -huawei -title "Hello" -m "Hello Huawei!" -hk "APP_SECRET" -hid "APP_ID" -t "device_token"# Topic message gorush --huawei --topic "updates" -title "Update" -m "New version available" -hk "APP_SECRET" -hid "APP_ID"

REST API Usage

Health Check

curl http://localhost:8088/healthz

Send Notifications

curl -X POST http://localhost:8088/api/push \ -H "Content-Type: application/json" \ -d '{ "notifications": [{ "tokens": ["device_token_1", "device_token_2"], "platform": 2, "title": "Hello World", "message": "This is a test notification" }] }'

Get Statistics

# Application stats curl http://localhost:8088/api/stat/app # Go runtime stats curl http://localhost:8088/api/stat/go # System stats curl http://localhost:8088/sys/stats # Prometheus metrics curl http://localhost:8088/metrics

CLI Options Reference

Click to expand all CLI options
Server Options: -A, --address <address> Address to bind (default: any) -p, --port <port> Use port for clients (default: 8088) -c, --config <file> Configuration file path -m, --message <message> Notification message -t, --token <token> Notification token -e, --engine <engine> Storage engine (memory, redis ...) --title <title> Notification title --proxy <proxy> Proxy URL --pid <pid path> Process identifier path --redis-addr <redis addr> Redis addr (default: localhost:6379) --ping healthy check commandfor container iOS Options: -i, --key <file> certificate key file path -P, --password <password> certificate key password --ios enabled iOS (default: false) --production iOS production mode (default: false) Android Options: --fcm-key <fcm_key_path> FCM Key Path --android enabled android (default: false) Huawei Options: -hk, --hmskey <hms_key> HMS App Secret -hid, --hmsid <hms_id> HMS App ID --huawei enabled huawei (default: false) Common Options: --topic <topic> iOS, Android or Huawei topic message -h, --help Show this message -V, --version Show version

Web API

Overview

Gorush provides RESTful APIs for sending notifications and monitoring system status:

EndpointMethodDescription
/api/pushPOSTSend push notifications
/api/stat/appGETApplication statistics
/api/stat/goGETGo runtime statistics
/sys/statsGETSystem performance metrics
/metricsGETPrometheus metrics
/healthzGETHealth check
/api/configGETCurrent configuration

Send Notifications - POST /api/push

Basic Examples

iOS (APNS)

{"notifications": [{"tokens": ["ios_device_token"], "platform": 1, "title": "Hello iOS", "message": "Hello World iOS!" }] }

Android (FCM)

{"notifications": [{"tokens": ["android_device_token"], "platform": 2, "title": "Hello Android", "message": "Hello World Android!" }] }

Huawei (HMS)

{"notifications": [{"tokens": ["huawei_device_token"], "platform": 3, "title": "Hello Huawei", "message": "Hello World Huawei!" }] }

Advanced Examples

iOS with Custom Sound

{"notifications": [{"tokens": ["ios_device_token"], "platform": 1, "title": "Important Alert", "message": "Critical notification", "apns":{"payload":{"aps":{"sound":{"name": "custom.wav", "critical": 1, "volume": 0.8 } } } } }] }

Multiple Platforms

{"notifications": [{"tokens": ["ios_token"], "platform": 1, "message": "Hello iOS!" },{"tokens": ["android_token"], "platform": 2, "message": "Hello Android!" } ] }

Statistics APIs

Application Stats - GET /api/stat/app

{"version": "v1.18.9", "busy_workers": 0, "success_tasks": 150, "failure_tasks": 5, "submitted_tasks": 155, "total_count": 155, "ios":{"push_success": 80, "push_error": 2 }, "android":{"push_success": 65, "push_error": 3 }, "huawei":{"push_success": 5, "push_error": 0 } }

System Performance - GET /sys/stats

{"pid": 12345, "uptime": "2h30m15s", "total_response_time": "45.2ms", "average_response_time": "1.2ms", "total_status_code_count":{"200": 1450, "400": 12, "500": 3 } }

Advanced Configuration

Complete API request parameters

Request body

The Request body must have a notifications array. The following is a parameter table for each notification.

nametypedescriptionrequirednote
notif_idstringA unique string that identifies the notification for async feedback-
tokensstring arraydevice tokenso
platformintplatform(iOS,Android)o1=iOS, 2=Android (Firebase), 3=Huawei (HMS)
messagestringmessage for notification-
titlestringnotification title-
prioritystringSets the priority of the message.-normal or high
content_availablebooldata messages wake the app by default.-
soundinterface{}sound type-
datastring arrayextensible partition-only Android and IOS
huawei_datastringJSON object as string to extensible partition partition-only Huawei. See the detail
retryintretry send notification if fail response from server. Value must be small than max_retry field.-
topicstringsend messages to topics
imagestringimage url to show in notification-only Android and Huawei
tostringThe value must be a registration token, notification key, or topic.-only Android
collapse_keystringa key for collapsing notifications-only Android
huawei_collapse_keyinta key integer for collapsing notifications-only Huawei See the detail
delay_while_idleboola flag for device idling-only Android
time_to_liveuintexpiration of message kept on FCM storage-only Android
huawei_ttlstringexpiration of message kept on HMS storage-only Huawei See the detail
restricted_package_namestringthe package name of the application-only Android
dry_runboolallows developers to test a request without actually sending a message-only Android
notificationstring arraypayload of a FCM message-only Android. See the detail
huawei_notificationstring arraypayload of a HMS message-only Huawei. See the detail
app_idstringhms app id-only Huawei. See the detail
bi_tagstringTag of a message in a batch delivery task-only Huawei. See the detail
fast_app_targetintState of a mini program when a quick app sends a data message.-only Huawei. See the detail
expirationintexpiration for notification-only iOS
apns_idstringA canonical UUID that identifies the notification-only iOS
collapse_idstringAn identifier you use to coalesce multiple notifications into a single notification for the user-only iOS
push_typestringThe type of the notification. The value of this header is alert or background.-only iOS
badgeintbadge count-only iOS
categorystringthe UIMutableUserNotificationCategory object-only iOS
alertstring arraypayload of a iOS message-only iOS. See the detail
mutable_contentboolenable Notification Service app extension.-only iOS(10.0+).
namestringsets the name value on the aps sound dictionary.-only iOS
volumefloat32sets the volume value on the aps sound dictionary.-only iOS
interruption_levelstringdefines the interruption level for the push notification.-only iOS(15.0+)
content-statestring arraydynamic and custom content for live-activity notification.-only iOS(16.1+)
timestampintthe UNIX time when sending the remote notification that updates or ends a Live Activity-only iOS(16.1+)
eventstringdescribes whether you update or end an ongoing Live Activity-only iOS(16.1+)
stale-dateintthe date which a Live Activity becomes stale, or out of date-only iOS(16.1+)
dismissal-dateintthe UNIX time -timestamp- which a Live Activity will end and will be removed-only iOS(16.1+)

iOS alert payload

nametypedescriptionrequirednote
titlestringApple Watch & Safari display this string as part of the notification interface.-
bodystringThe text of the alert message.-
subtitlestringApple Watch & Safari display this string as part of the notification interface.-
actionstringThe label of the action button. This one is required for Safari Push Notifications.-
action-loc-keystringIf a string is specified, the system displays an alert that includes the Close and View buttons.-
launch-imagestringThe filename of an image file in the app bundle, with or without the filename extension.-
loc-argsarray of stringsVariable string values to appear in place of the format specifiers in loc-key.-
loc-keystringA key to an alert-message string in a Localizable.strings file for the current localization.-
title-loc-argsarray of stringsVariable string values to appear in place of the format specifiers in title-loc-key.-
title-loc-keystringThe key to a title string in the Localizable.strings file for the current localization.-

See more detail about APNs Remote Notification Payload.

iOS sound payload

nametypedescriptionrequirednote
namestringsets the name value on the aps sound dictionary.-
volumefloat32sets the volume value on the aps sound dictionary.-
criticalintsets the critical value on the aps sound dictionary.-

request format:

{"sound":{"critical": 1, "name": "default", "volume": 2.0 } }

Android notification payload

nametypedescriptionrequirednote
iconstringIndicates notification icon.-
tagstringIndicates whether each notification message results in a new entry on the notification center on Android.-
colorstringIndicates color of the icon, expressed in #rrggbb format-
click_actionstringThe action associated with a user click on the notification.-
body_loc_keystringIndicates the key to the body string for localization.-
body_loc_argsstringIndicates the string value to replace format specifiers in body string for localization.-
title_loc_keystringIndicates the key to the title string for localization.-
title_loc_argsstringIndicates the string value to replace format specifiers in title string for localization.-

See more detail about Firebase Cloud Messaging HTTP Protocol reference.

Huawei notification

  1. app_id: app id from huawei developer console
  2. bi_tag:
  3. fast_app_target:
  4. huawei_data: mapped to data
  5. huawei_notification: mapped to notification
  6. huawei_ttl: mapped to ttl
  7. huawei_collapse_key: mapped to collapse_key

See more detail about Huawei Mobulse Services Push API reference.

iOS Example

Send normal notification.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 1, "message": "Hello World iOS!" } ] }

The following payload asks the system to display an alert with a Close button and a single action button.The title and body keys provide the contents of the alert. The “PLAY” string is used to retrieve a localized string from the appropriate Localizable.strings file of the app. The resulting string is used by the alert as the title of an action button. This payload also asks the system to badge the app’s icon with the number 5.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 1, "badge": 5, "alert":{"title": "Game Request", "body": "Bob wants to play poker", "action-loc-key": "PLAY" } } ] }

The following payload specifies that the device should display an alert message, plays a sound, and badges the app’s icon.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 1, "message": "You got your emails.", "badge": 9, "sound":{"critical": 1, "name": "default", "volume": 1.0 } } ] }

Add other fields which user defined via data field.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 1, "message": "Hello World iOS!", "data":{"key1": "welcome", "key2": 2 } } ] }

Support send notification from different environment. See the detail of issue.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 1, + "production": true, "message": "Hello World iOS Production!" },{"tokens": ["token_a", "token_b"], "platform": 1, + "development": true, "message": "Hello World iOS Sandbox!" } ] }

Android Example

Send normal notification.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 2, "message": "Hello World Android!", "title": "You got message" } ] }

Label associated with the message's analytics data.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 2, "message": "Hello World Android!", "title": "You got message", "fcm_options":{"analytics_label": "example" } } ] }

Add notification payload.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 2, "message": "Hello World Android!", "title": "You got message", "notification":{"icon": "myicon", "color": "#112244" } } ] }

Add other fields which user defined via data field.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 2, "message": "Hello World Android!", "title": "You got message", "data":{"Nick": "Mario", "body": "great match!", "Room": "PortugalVSDenmark" } } ] }

Send messages to topic

{"notifications": [{"topic": "highScores", "platform": 2, "message": "This is a Firebase Cloud Messaging Topic Message" } ] }

Huawei Example

Send normal notification.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 3, "message": "Hello World Huawei!", "title": "You got message" } ] }

Add notification payload.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 3, "message": "Hello World Huawei!", "title": "You got message", "huawei_notification":{"icon": "myicon", "color": "#112244" } } ] }

Add other fields which user defined via huawei_data field.

{"notifications": [{"tokens": ["token_a", "token_b"], "platform": 3, "huawei_data": "{'title' : 'Mario','message' : 'great match!', 'Room' : 'PortugalVSDenmark'}" } ] }

Send messages to topics

{"notifications": [{"topic": "foo-bar", "platform": 3, "message": "This is a Huawei Mobile Services Topic Message", "title": "You got message" } ] }

Response body

Error response message table:

status codemessage
400Missing notifications field.
400Notifications field is empty.
400Number of notifications(50) over limit(10)

Success response:

{"counts": 60, "logs": [], "success": "ok" }

If you need error logs from sending fail notifications, please set a feedback_hook_url and feedback_header for custom header. The server with send the failing logs asynchronously to your API as POST requests.

core: port: "8088" # ignore this port number if auto_tls is enabled (listen 443). worker_num: 0 # default worker number is runtime.NumCPU() queue_num: 0 # default queue number is 8192 max_notification: 100 sync: false - feedback_hook_url: ""+ feedback_hook_url: "https://exemple.com/api/hook"+ feedback_header:+ - x-gorush-token:4e989115e09680f44a645519fed6a976

You can also switch to sync mode by setting the sync value as true on yaml config. It only works when the queue engine is local.

core: port: "8088" # ignore this port number if auto_tls is enabled (listen 443). worker_num: 0 # default worker number is runtime.NumCPU() queue_num: 0 # default queue number is 8192 max_notification: 100 - sync: false+ sync: true

See the following error format.

{"counts": 60, "logs": [{"type": "failed-push", "platform": "android", "token": "*******", "message": "Hello World Android!", "error": "InvalidRegistration" },{"type": "failed-push", "platform": "ios", "token": "*****", "message": "Hello World iOS1111!", "error": "Post https://api.push.apple.com/3/device/bbbbb: remote error: tls: revoked certificate" },{"type": "failed-push", "platform": "ios", "token": "*******", "message": "Hello World iOS222!", "error": "Post https://api.push.apple.com/3/device/token_b: remote error: tls: revoked certificate" } ], "success": "ok" }

Deployment

Docker

Quick Start

# Run with default config docker run --rm -p 8088:8088 appleboy/gorush # Run with custom config docker run --rm -p 8088:8088 \ -v $(pwd)/config.yml:/home/gorush/config.yml \ appleboy/gorush # Run in background docker run -d --name gorush -p 8088:8088 appleboy/gorush

Docker Compose

version: '3'services: gorush: image: appleboy/gorushports: - "8088:8088"volumes: - ./config.yml:/home/gorush/config.ymlredis: image: redis:alpineports: - "6379:6379"

Kubernetes

Quick Deploy

# Create namespace and config kubectl create -f k8s/gorush-namespace.yaml kubectl create -f k8s/gorush-configmap.yaml # Deploy Redis (optional, for queue/stats) kubectl create -f k8s/gorush-redis-deployment.yaml kubectl create -f k8s/gorush-redis-service.yaml # Deploy Gorush kubectl create -f k8s/gorush-deployment.yaml kubectl create -f k8s/gorush-service.yaml

AWS Load Balancer

For AWS ELB:

kubectl create -f k8s/gorush-service.yaml

For AWS ALB, modify service type:

# k8s/gorush-service.yamlspec: type: NodePort # Change from LoadBalancer

Then deploy ingress:

kubectl create -f k8s/gorush-aws-alb-ingress.yaml

Cleanup

kubectl delete -f k8s/

AWS Lambda

Build and Deploy

# Build Lambda binary git clone https://github.com/appleboy/gorush.git cd gorush make build_linux_lambda # Create deployment package zip deployment.zip release/linux/lambda/gorush # Deploy with AWS CLI aws lambda update-function-code \ --function-name gorush \ --zip-file fileb://deployment.zip

Automated Deployment

Using drone-lambda:

AWS_ACCESS_KEY_ID=your_key \ AWS_SECRET_ACCESS_KEY=your_secret \ drone-lambda --region us-west-2 \ --function-name gorush \ --source release/linux/lambda/gorush

Netlify Functions

Alternative serverless deployment without AWS:

# netlify.toml [build] command = "make build_linux_lambda"functions = "release/linux/lambda" [build.environment] GO_VERSION = "1.24" [[redirects]] from = "/*"status = 200to = "/.netlify/functions/gorush/:splat"

gRPC Service

Enable gRPC server for high-performance applications:

# config.ymlgrpc: enabled: trueport: 9000

Or via environment:

GORUSH_GRPC_ENABLED=true GORUSH_GRPC_PORT=9000 gorush

gRPC Client Example (Go)

package main import ( "context""log""github.com/appleboy/gorush/rpc/proto""google.golang.org/grpc" ) funcmain(){conn, err:=grpc.NewClient("localhost:9000", grpc.WithInsecure()) iferr!=nil{log.Fatal(err) } deferconn.Close() client:=proto.NewGorushClient(conn) resp, err:=client.Send(context.Background(), &proto.NotificationRequest{Platform: 2, Tokens: []string{"device_token"}, Message: "Hello gRPC!", Title: "Test Notification", }) iferr!=nil{log.Fatal(err) } log.Printf("Success: %v, Count: %d", resp.Success, resp.Counts) }

FAQ

Common Issues

Q: How do I get FCM credentials? A: Go to Firebase Console → Project Settings → Service Accounts → Generate New Private Key. Download the JSON file.

Q: iOS notifications not working in production? A: Make sure you:

  1. Use production APNS certificates (production: true)
  2. Set correct bundle ID in certificate
  3. Test with production app build

Q: Getting "certificate verify failed" error? A: This usually means:

  • Wrong certificate format (use .pem or .p12)
  • Certificate expired
  • Wrong environment (dev vs production)

Q: How to handle large notification volumes? A: Configure workers and queue settings:

core: worker_num: 8# Increase workersqueue_num: 16384# Increase queue sizequeue: engine: "redis"# Use external queue

Q: Can I send to multiple platforms at once? A: Yes, include multiple notification objects in the request:

{"notifications": [{"platform": 1, "tokens": ["ios_token"], "message": "iOS"},{"platform": 2, "tokens": ["android_token"], "message": "Android"} ] }

Q: How to monitor notification failures? A: Enable sync mode or feedback webhook:

core: sync: true # Get immediate responsefeedback_hook_url: "https://your-api"# Async webhook

Q: What's the difference between platforms? A: Platform codes: 1 = iOS (APNS), 2 = Android (FCM), 3 = Huawei (HMS)

Performance Tips

  • Use Redis for queue and stats storage in production
  • Enable gRPC for better performance
  • Set appropriate worker numbers based on CPU cores
  • Use connection pooling for high-volume scenarios

Security Best Practices

  • Store credentials as files, not in config
  • Use environment variables for sensitive data
  • Enable SSL/TLS in production
  • Rotate certificates before expiration
  • Monitor failed notifications for security issues

Stargazers over time

Stargazers over time

License

Copyright 2019 Bo-Yi Wu @appleboy.

Licensed under the MIT License.