Airnotifier for Moodle: Self-Hosting Push Notifications (2026 Guide)

Branded Moodle mobile app showing push notifications and offline course access

Key Insights & Technical Highlights

  • Why It Exists: Moodle cannot talk to Apple APNs or Google FCM directly — every push alert is relayed through the open-source Airnotifier gateway.
  • The 50-Device Ceiling: Moodle HQ's free hosted gateway (messages.moodle.net) drops notifications silently once a site passes 50 active devices/month.
  • Custom Apps Need Self-Hosting: Any white-label or custom-branded app (its own Bundle ID / Package Name) cannot use Moodle HQ's shared credentials at all.
  • Production Deployment: Docker Compose (Airnotifier + MongoDB) behind an Nginx reverse proxy with Let's Encrypt TLS.
  • Credentials: Apple APNs token-based .p8 keys (never expire) and Google FCM HTTP v1 OAuth2 service accounts (legacy server keys are deprecated).
  • Full App Context: Building the app itself? See our companion Moodle Mobile App Development Guide.

Push notifications are the single most effective tool for driving course retention and learner engagement. Automated deadline reminders, grade publications, direct messages, and discussion forum mentions achieve an average 90%+ open rate on mobile devices — compared to less than 20% for automated LMS emails.

However, delivering push notifications in Moodle is technically distinct from standard web notifications. Moodle LMS cannot communicate directly with Apple Push Notification service (APNs) or Google Firebase Cloud Messaging (FCM). Instead, Moodle relies on an open-source notification gateway called Airnotifier. This guide walks through why it exists, its default 50-device limit, and how to self-host your own instance for a custom or white-label Moodle mobile app.

1. Why Moodle Needs Airnotifier

Every mobile push alert follows an eight-step pipeline across client devices, Moodle core, Airnotifier, and OS notification gateways:

  1. Device Token Acquisition: When a learner installs and opens your mobile app on iOS or Android, the app requests system notification permissions. The operating system registers with APNs or FCM and returns a unique, device-specific push token (the pushid).
  2. Web Service Device Registration: The mobile app invokes Moodle's core web service function core_user_add_user_device. It transmits device attributes: user ID, platform (ios or android), device model, OS version, application ID, push token, and a persistent UUID.
  3. Database Persistence: Moodle stores the registration inside the mdl_user_devices table. Each user can have multiple registered devices (e.g., an iPad and an Android smartphone).
  4. LMS Event Trigger: A trigger event occurs in Moodle (such as an instructor publishing assignment feedback, a quiz deadline approaching, or a new forum post in an enrolled course).
  5. Message Processor Dispatch: Moodle's internal message processor evaluates active outputs. If message_airnotifier is enabled and the recipient has active mobile devices in mdl_user_devices, a push payload is queued.
  6. Outbound HTTP POST to Airnotifier: Moodle formats a JSON payload containing the notification subject, body, badge count, user metadata, and custom context parameters, then dispatches an authenticated HTTP POST request to the configured Airnotifier server URL (/api/v2/push/).
  7. Airnotifier Gateway Relay: Airnotifier inspects the targeted device platforms. It packages Apple payloads into HTTP/2 frames authenticated with APNs authentication keys, and packages Android payloads into OAuth2-authenticated Google FCM HTTP v1 JSON messages.
  8. Native Delivery & Deep Linking: The learner's device receives the push message, presents the banner alert, increments the app's badge counter, and upon tapping, deep-links the student directly to the relevant course module or assignment submission page.
// Moodle to Device Notification Flow
[Learner Device] --(1. Register Token)----------------> [APNs / FCM]
[Learner Device] --(2. core_user_add_user_device)---> [Moodle LMS (mdl_user_devices)]
[Moodle Event] --(3. message_airnotifier queue)---> [Moodle Message Processor]
[Moodle LMS] --(4. Authenticated REST POST)-------> [Airnotifier Middleware]
[Airnotifier] --(5. APNs HTTP/2 & FCM v1)--------> [Apple & Google Gateways]
[Gateways] --(6. Push Notification Alert)------> [Learner Device Screen]

2. The 50-Device Limitation on Hosted messages.moodle.net

By default, standard Moodle installations route push notifications through Moodle HQ's hosted messaging gateway at https://messages.moodle.net. While this provides zero-configuration setup for small trials, it introduces a severe operational bottleneck for growing organizations:

  • Free Plan Limit: Moodle HQ caps free sites at 50 active registered devices per calendar month.
  • Silent Failure: Once 50 unique devices have connected to your site in a given month, notifications for the 51st learner and beyond are silently dropped by the hosted gateway. Instructors assume notifications are delivering, but students never receive them.
  • Tiered Subscription Costs: Upgrading through Moodle Apps Portal requires purchasing a Pro plan (up to 500 devices at ~€199/year), a Premium plan (up to 3,200 devices at ~€799/year), or custom enterprise pricing.

3.Why Custom & White-Label Apps Cannot Use Moodle HQ's Airnotifier

If your organization decides to publish a custom branded Moodle mobile app (whether by forking the official Ionic app or engineering a bespoke Flutter/React Native application), you cannot use messages.moodle.net without purchasing Moodle's expensive Branded Moodle App (BMA) enterprise subscription.

The limitation is enforced by Apple and Google security standards:

  • Bundle ID & Package Name Isolation: Your custom app is published under your own bundle identifier (e.g., com.youruniversity.learn). APNs will reject any push message not signed with the private key corresponding to that exact bundle ID.
  • FCM Project Identity: Google FCM validates push payloads against your Google Cloud project's service credentials.
  • Shared Server Credentials: Moodle HQ's shared server only holds cryptographic keys for the official com.moodle.moodlemobile package. It cannot sign push requests for third-party bundle identifiers.

Consequently, deploying a self-hosted Airnotifier server is the standard architectural requirement for any organization running a white-label or custom Moodle mobile application. It completely eliminates per-device licensing costs, removes the 50-device ceiling, and guarantees total data sovereignty. Need the app itself too? See our Moodle Mobile App Development Services.

4.Self-Hosting Airnotifier: Docker Compose & Nginx Setup

Airnotifier is an asynchronous, high-throughput push server developed in Python using the Tornado web framework and backed by MongoDB. Deploying your own private Airnotifier instance requires a modest virtual private server (e.g., 2 vCPU, 2GB–4GB RAM) running Ubuntu 22.04 or 24.04 LTS.

4.1 Production Docker Compose Deployment

The most reliable deployment model encapsulates Airnotifier and MongoDB in isolated Docker containers behind an Nginx reverse proxy providing TLS 1.3 encryption:

# docker-compose.yml — Production Airnotifier Stack
version: '3.8'

services:
  mongodb:
    image: mongo:6.0
    container_name: airnotifier-mongodb
    restart: always
    volumes:
      - mongo_data:/data/db
    networks:
      - airnotifier-net

  airnotifier:
    image: airnotifier/airnotifier:latest
    container_name: airnotifier-app
    restart: always
    depends_on:
      - mongodb
    ports:
      - "127.0.0.1:8801:8801"
    environment:
      - MONGO_HOST=mongodb
      - MONGO_PORT=27017
      - MONGO_DB=airnotifier
    volumes:
      - airnotifier_certs:/airnotifier/certificates
      - ./config.py:/airnotifier/config.py:ro
    networks:
      - airnotifier-net

networks:
  airnotifier-net:
    driver: bridge

volumes:
  mongo_data:
  airnotifier_certs:

4.2 Nginx Reverse Proxy with Let's Encrypt SSL

Moodle's PHP cURL client strictly enforces valid TLS handshakes. Your Airnotifier instance must run behind a fully qualified domain (e.g., notifications.yourdomain.com) with a complete CA certificate chain:

# /etc/nginx/sites-available/airnotifier.conf
server {
    listen 443 ssl http2;
    server_name notifications.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/notifications.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/notifications.yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8801;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 90;
    }
}

5. Configuring Push Gateway Credentials in Airnotifier

Once your Airnotifier container is live, access the web administration dashboard at your configured domain:

  1. Create an Application: In the Airnotifier dashboard, navigate to Applications > Add Application. Set the Application Name to your mobile app ID (e.g., com.yourorg.learn or moodle_mobile_app).
  2. Apple APNs Configuration (Token-Based Authentication):
    • Obtain an Apple Push Notification Authentication Key (.p8 file) from your Apple Developer account (Certificates, Identifiers & Profiles > Keys). Unlike legacy .p12 certificates that expire every 12 months, .p8 token authentication keys never expire.
    • Upload the .p8 file, enter the 10-character Key ID, 10-character Team ID, and your exact Bundle Identifier. Set the environment to Production for App Store releases.
  3. Google Firebase Cloud Messaging (FCM HTTP v1) Setup:
    • Google completely deprecated legacy FCM server keys in favor of the modern FCM HTTP v1 API, which requires OAuth2 token authentication.
    • In your Firebase Console, navigate to Project Settings > Service accounts. Click Generate new private key to download the service account JSON key file.
    • Upload the service account JSON into Airnotifier. This grants Airnotifier permission to request short-lived OAuth2 bearer tokens dynamically for Android push dispatches.
  4. Generate an Access Key: Under Access Keys, generate a dedicated API token. Copy this key string—Moodle will use it to authenticate outbound push requests.

6. Connecting Moodle LMS to Your Private Airnotifier Instance

Log in to your Moodle LMS as a Site Administrator and configure the native mobile notification plugin:

  1. Navigate to Site administration > Plugins > Message outputs > Mobile notifications (or Airnotifier).
  2. Configure the connection settings:
    • Airnotifier server URL: https://notifications.yourdomain.com
    • Airnotifier app name: Enter the exact application name configured in your Airnotifier dashboard (e.g., moodle_mobile_app).
    • Airnotifier access key: Paste the API access key generated in Step 5.
  3. Alternatively, configure via Moodle CLI on your LMS server:
    php admin/cli/cfg.php --component=message_airnotifier --name=airnotifierurl --set="https://notifications.yourdomain.com"
    php admin/cli/cfg.php --component=message_airnotifier --name=airnotifierappname --set="moodle_mobile_app"
    php admin/cli/cfg.php --component=message_airnotifier --name=airnotifieraccesskey --set="YOUR_SECRET_ACCESS_KEY"
  4. Click Save changes. Your Moodle instance is now connected directly to your private, unthrottled push notification gateway.

7.Troubleshooting Airnotifier & Moodle Push Failures

When notifications fail to arrive on student devices, issues usually stem from token registration mismatches, network firewalls, or SSL negotiation errors. Use this battle-tested diagnostic checklist to pinpoint the failure:

Diagnostic StepCommand / Inspection PointExpected Result & Resolution
1. Device Token PersistenceSELECT id, userid, appid, platform, pushid, timecreated FROM mdl_user_devices ORDER BY id DESC LIMIT 5;Verify records exist. If empty, the user has never logged into the app while online, or the device was denied notification permissions.
2. Role CapabilitiesSite administration > Users > Permissions > Define roles > Authenticated userEnsure capability message/airnotifier:managedevice is set to Allow. If prohibited, device tokens cannot register.
3. Moodle Scheduled Taskphp admin/cli/scheduled_task.php --execute=\message_airnotifier\task\send_notificationsExecutes the push queue immediately. Look for cURL errors or HTTP status code failures in the CLI output.
4. SSL/TLS Certificate Chaincurl -Iv https://notifications.yourdomain.com/api/v2/push/Must return valid SSL certificate handshake. If you see cURL error 60: SSL certificate problem, verify intermediate certificates (fullchain.pem) in Nginx.
5. Airnotifier Container Logsdocker logs -f airnotifier-appMonitor live dispatch. Inspect for 401 Unauthorized (access key mismatch), BadDeviceToken (APNs sandbox vs prod), or UNREGISTERED (app uninstalled).
6. End-to-End Encryption (E2EE)Moodle LMS 4.1.4+ / Moodle App 4.2+ public key exchangeMoodle encrypts payloads with the device's public key. Airnotifier acts as a zero-knowledge pipe, relaying ciphertext that only the recipient device decrypts.
Real-World Client Build

Case Study: IDEAL Learning Solutions Moodle Mobile App

See how Softosmith delivered a branded iOS and Android Moodle mobile app with self-hosted native push notifications, offline course sync, and custom store listings for IELTS & TOEFL exam prep students.

Read the Full Case Study →

8. Frequently Asked Questions (FAQ)

What is Airnotifier and why does Moodle need it for mobile push notifications?

Airnotifier is an open-source push notification middleware server developed specifically to relay notifications between Moodle LMS and mobile operating system gateways (Apple APNs for iOS and Firebase Cloud Messaging for Android). Because Moodle cannot communicate directly with device push protocols, it forwards event payloads to Airnotifier over REST APIs, which then formats, signs, and delivers the alerts to learner devices.

Why did push notifications stop working on my Moodle site after 50 users?

Moodle's default hosted notification service (messages.moodle.net) restricts free installations to 50 active registered devices per calendar month. Once your site exceeds 50 mobile users, notifications for subsequent users are dropped. Organizations must either upgrade to a paid Moodle App subscription (Pro/Premium) or self-host their own Airnotifier server to support unlimited devices.

Can I use Moodle's default notification server (messages.moodle.net) for a custom branded app?

No. Apple APNs and Google FCM require push alerts to be signed with credentials matching the app's unique Bundle ID / Package Name. Moodle's shared server only holds certificates for the official Moodle app (com.moodle.moodlemobile). If you build a custom white-label app with your own store identity, you must connect Moodle to a private self-hosted Airnotifier server.

How do you resolve Google FCM v1 notification errors in Airnotifier?

Google deprecated legacy FCM Server Keys in favor of the FCM HTTP v1 API, which enforces OAuth2 token authentication using a Google Cloud IAM Service Account JSON key. To resolve delivery failures, use an Airnotifier version supporting FCM v1, create a service account with Firebase Cloud Messaging API permissions in Google Cloud Console, and upload the private key JSON file into your Airnotifier application settings.

How does end-to-end encryption (E2EE) work in Moodle push notifications?

Introduced in Moodle 4.1.4 and Moodle App 4.2, end-to-end encryption uses asymmetric public-key cryptography. When a learner logs in, the mobile app creates a keypair and registers its public key with Moodle via core_user_add_user_device. Moodle encrypts notification payloads prior to dispatch. Airnotifier acts as a zero-knowledge relay, forwarding encrypted ciphertext that only the recipient device can decrypt locally with its private key.

Is Airnotifier required for Moodle push notifications, or is there an alternative?

Airnotifier is the only supported gateway for Moodle mobile push notifications; there is no built-in alternative. Moodle's core message_airnotifier plugin is hard-wired to talk to an Airnotifier server, either Moodle HQ's free hosted instance (capped at 50 devices/month) or a self-hosted Airnotifier deployment for unlimited devices and custom-branded apps.

Need Help Deploying Airnotifier for Your Moodle App?

Self-hosting Airnotifier is one piece of shipping a fully custom or white-label Moodle mobile app. Explore our specialized Moodle Mobile App Development Services, read our companion Moodle Mobile App Development Guide, or contact Softosmith to schedule a technical architecture session with our lead LMS engineers.