// resources

Everything you need, in one place.

Plugin downloads, setup guides, configuration reference, API docs, and support — all the tools to get PulsePanel running and keep it running.

welcome

Resource hub.

Whether you're just installing the plugin, troubleshooting a quirk, or building something custom on top of the API — everything lives here.

Top destinations

plugin download

PulseConnect plugin.

The free, server-side companion to PulsePanel. Drop it in your plugins/ folder, configure once, and the iOS app can talk to your server.

PulseConnect.jar
v1.0.0 · Paper / Spigot / Purpur · MC 1.20+

Where the plugin lives

PulseConnect is hosted on GitHub as an open-source project under the MIT license.

  • Latest JAR — the Download button above always grabs the newest release.
  • All versions — see the Releases page for version history.
  • Source code — inspect, fork, or contribute on GitHub.
  • Issues & feature requests — file them on GitHub Issues, or email support@pulsepanelapp.com.
Need to install it?
The setup guide walks through dropping the JAR, configuring config.yml, and connecting the app — about 5 minutes.
Open setup guide
requirements

What you'll need.

PulsePanel runs on most modern Minecraft servers and any iPhone or iPad on iOS 17+. Here's the full compatibility matrix.

Server

Software
Paper · Spigot · Purpur
Minecraft version
1.21 or newer
Java
17 or newer
Memory overhead
~64 MB additional

Network

Default port
7070 TCP (configurable)
Port forwarding
Required for remote access

iOS app

iOS version
17.0 or newer
Devices
iPhone · iPad
Distribution
Apple App Store
Permissions
Local Network · Notifications

Managed Minecraft hosts

Many managed hosts (BisectHosting, Apex, Shockbyte, PebbleHost) lock down their network and only expose the Minecraft port. Before signing up, confirm the host supports opening additional TCP ports for plugins — without it, PulsePanel can't reach your server remotely.

Self-hosted servers and most VPS providers (DigitalOcean, Linode, Hetzner, etc.) work without restrictions.

configuration

Configuration reference.

Every key in plugins/PulseConnect/config.yml, what it does, and what to watch out for. The plugin generates this file with sensible defaults on first start — you only need to touch a few keys.

api:

How the plugin exposes its HTTP + WebSocket interface to the app.
api.port integer default 7070

The TCP port the plugin listens on. The app connects to this port. Forward this port on your router for remote access.

Change it if 7070 is already in use, or if your hosting provider only allows specific ports.

api.jwt-secret string required security

A server-internal secret the plugin uses to sign session tokens. Treat it like a password.

This is not something you enter in the app — it stays on the server. Use 32+ random characters; openssl rand -hex 32 works well.

change thisThe plugin generates a random secret on first launch, so the default is already safe. Only change it if you suspect it was leaked — changing it invalidates every signed-in session.
api.token-expiry-hours integer default 24

How long an app sign-in stays valid before the user has to sign in again.

Lower values are slightly more secure but more annoying. Higher values are convenient but extend the lifetime of a leaked token. The default of 24 hours is a reasonable trade-off.

admin:

Used only on first launch to create the initial owner account.
admin.username string default admin

The username for the owner account. This is what you'll sign in with on the app.

admin.password string default password123 change before launch

The password for the owner account. Stored hashed (BCrypt) in the database after first launch.

do this firstThe plugin ships with password123 as the placeholder. Change this in config.yml before you start the server, or change it via the app's account settings immediately after first sign-in.
first-launch only behavior

The admin: block is read only on first plugin startup, when the database is empty. Once the owner account exists, this block is ignored — changing the values here won't affect the existing account.

To change credentials after first launch, use the app's account settings (or do a clean reset; see troubleshooting).

You can blank these fields out after first launch — the plugin doesn't need them anymore.

security:

Built-in protections for the sign-in flow and API rate limiting.
security.max-login-attempts integer default 5

How many failed sign-in attempts allowed before the (username, IP) pair is locked out.

Lower values are stricter against brute-force attacks but more punishing if you fat-finger your password.

security.lockout-minutes integer default 15

How long the lockout lasts after hitting max-login-attempts.

Restarting the server clears the in-memory lockout state regardless of this value.

security.rate-limit-per-minute integer default 60

Maximum API requests per minute, per authenticated user. Prevents a misbehaving client from hammering the server.

The default is generous for normal app usage. Custom integrations doing heavy polling may need a higher value — or better, switch to the WebSocket for real-time data.

logging:

What the plugin writes to the server console.
logging.log-requests boolean default true

Log every API request to the server console. Useful for debugging client integrations and verifying the plugin is reachable.

Set to false on busy servers to reduce log noise. Privileged actions are still recorded in the audit log regardless.

logging.log-commands boolean default true

Log every command executed via POST /command to the server console.

Recommended to leave on — commands run via the API have the same authority as console commands. The audit log captures these regardless, but console visibility is useful in real time.

// commands

In-game commands the plugin registers.

/pulseconnect

aliases: /pc

Admin command for inspecting and managing the plugin from in-game or the server console.

  • /pulseconnect help — list available subcommands
  • /pulseconnect status — show plugin status (port, connected sessions, uptime)
  • /pulseconnect reload — reload config.yml without restarting the server

/ticket

player-facing

Player command for the in-game support ticket system. Players use this to ask staff for help; tickets show up in the app for the owner to respond to.

  • /ticket create <message> — open a new ticket
  • /ticket reply <message> — reply to your active ticket
  • /ticket close — close your active ticket
  • /ticket list — view your ticket history

pulseconnect.admin

permission node · default: op

Bukkit permission required to run /pulseconnect subcommands. Granted to operators by default; reassign via your permission plugin (LuckPerms, etc.) if you want it to behave differently.

Building a custom client?
The API reference covers every endpoint, the WebSocket protocol, and the full permission catalog — all the values config.yml influences but doesn't fully document on its own.
Open API reference
troubleshooting

When things break.

Most issues fall into one of a dozen patterns. Start with the diagnostic flowchart if the app won't connect, otherwise jump to the relevant category below.

App won't connect — diagnose in 4 steps

// the most common failure path

1
Does the server console show [PulseConnect] API listening on :7070 after startup?
Yes The plugin is loaded and listening. Continue to step 2.
No The plugin didn't load. See Plugin doesn't load below.
2
From a different network (or your phone on cellular, Wi-Fi off), can you reach the port? Test at canyouseeme.org.
Yes — port open Network is fine. Continue to step 3.
No — port closed Port forward isn't working, host is blocking, or you're behind CGNAT. See Port forwarding & CGNAT.
3
In the app, does the error say connection refused / timeout, or authentication failed?
Refused / timeout Address or port is wrong, or a firewall is in the path. See Connection refused.
Auth failed Credentials don't match the database. See Auth failed with correct password.
4
Did the connection ever work before, or is this the first time?
First time Most likely a router or host config issue. Recheck the setup guide.
Worked before Something changed: router restart, dynamic IP, plugin update, or iOS update. See Worked yesterday, broken today.

Connection & network

5 issues
Connection refused or timeout
Cause

The plugin isn't running, or it isn't reachable on the address/port you gave the app.

Diagnose
  1. Check the server console for [PulseConnect] API listening on :7070 after startup. If it's missing, the plugin didn't load — see Plugin doesn't load.
  2. Confirm the address in the app matches your server's public IP or hostname. If you self-host, your public IP (not 192.168.x.x).
  3. Confirm the port matches api.port in config.yml (default 7070).
  4. Test the port from outside your network using canyouseeme.org or your phone on cellular data. If the port is closed, your forward isn't working.
  5. If you're behind a managed Minecraft host, confirm they've opened that port for you. Many hosts only expose the Minecraft port by default.
Port forwarding & CGNAT
Cause

Either the router rule isn't applying, or your ISP is using Carrier-Grade NAT (CGNAT) — common on mobile, rural, and cellular ISPs — which makes inbound connections impossible without a workaround.

Diagnose
  1. In your router, confirm the rule: external port 7070 → internal IP of your server, internal port 7070, protocol TCP.
  2. Make sure you're forwarding to the server's current internal IP — DHCP can change it. Set a static lease for the server in your router.
  3. Compare your public IP at whatismyipaddress.com with the IP your router shows on its WAN interface. If they differ, you're behind CGNAT and standard port forwarding won't work.
Workarounds for CGNAT
  • Ask your ISP for a public IPv4 address (sometimes free, sometimes a small monthly fee).
  • Use a tunneling service: Tailscale Funnel, Cloudflare Tunnel, or a small VPS reverse proxy.
  • Move the Minecraft server to a VPS provider that gives you a real public IP (DigitalOcean, Linode, Hetzner, etc.).
Connects on Wi-Fi but fails on cellular (or vice versa)
Cause

Almost always a network-side restriction, not the app. Some Wi-Fi networks (corporate, school, public guest) block non-standard ports outbound. Some cellular carriers throttle or block similarly. Or, if it works on Wi-Fi but not cellular, you might be using a local IP that only resolves on your home network.

Diagnose
  1. If you used a 192.168.x.x address in the app, that only works on your home Wi-Fi. Use your public IP or hostname instead.
  2. Test from cellular by toggling Wi-Fi off. If it fails, the Wi-Fi network is blocking outbound traffic to your port.
  3. Try a non-default port like 8443 in api.port — many networks allow that range while blocking unusual ones.
"Local Network" permission prompt didn't appear
Cause

iOS only prompts once. If you dismissed it or denied it, the app can't reach servers on your local Wi-Fi (only over the internet).

Fix

The app's connection-error screen has an Open Settings button that deep-links to the right place. Or manually: iOS Settings → PulsePanel → Local Network → On.

This only matters when connecting to a server on the same Wi-Fi network as your phone. Connecting to a remote server over the internet doesn't need Local Network permission.

Worked yesterday, broken today
Cause

Something on either side changed. The usual suspects, in order of likelihood:

  • Dynamic IP changed (most common for self-hosters) — your home IP rotates, and the address saved in the app no longer points to your server. Check your current public IP and update the app.
  • Router restarted — port-forward rules sometimes don't survive firmware updates or reboots. Verify the rule is still active.
  • Plugin or server updated — check the server console for [PulseConnect] errors after startup.
  • iOS or app updated — try fully quitting and relaunching the app. If still broken, sign out and sign back in.
  • Token expired — by default JWTs expire after 24 hours. Sign in again.
Long-term fix

If your IP rotates often, set up a dynamic DNS hostname (DuckDNS, No-IP, Cloudflare with a script) and point the app at the hostname instead of the raw IP.

The plugin itself

3 issues
Plugin doesn't load on server start
Cause

The JAR is missing, in the wrong folder, incompatible with the server software, or has a corrupted config.yml.

Diagnose
  1. Confirm PulseConnect.jar is in plugins/, not a subfolder.
  2. Check the full server console output during startup. Look for any line containing PulseConnect — if the JAR is being seen, you'll get either a success line or an explicit error.
  3. If you see a YAML parse error, your config.yml has bad indentation or unquoted special characters. Restore the default by deleting plugins/PulseConnect/config.yml and restarting the server — it'll regenerate.
  4. Confirm Java version: PulseConnect requires Java 17 or newer. Run java -version on the server.
  5. Confirm server software: Paper, Spigot, or Purpur on Minecraft 1.21+. Forge and Fabric aren't supported.
Port already in use / BindException
Cause

Something else is already listening on port 7070 (or whatever you set in api.port). Common culprits: another instance of the same plugin, a different admin plugin (ServerTap, AdminAPI, etc.), or a leftover process from a previous server crash.

Fix
  1. Stop the server cleanly. If a plugin from a previous run is still holding the port, give it 30 seconds to release.
  2. On Linux: sudo lsof -i :7070 shows what's using the port. Kill that process if it's stale.
  3. If two plugins genuinely need different ports, change api.port in config.yml to something unused (e.g. 7080) and update your port forward + the app.
Database errors — SQLITE_BUSY or Hikari pool exhausted
Cause

The plugin's SQLite database is being hit by multiple writers at once and locking up. This is rare in normal use but can happen on very busy servers, after a crash, or if another tool is reading plugins/PulseConnect/pulseconnect.db while the plugin is running.

Fix
  1. Close any external SQLite browser, sqlite3 CLI session, or backup tool that's accessing the plugin's database.
  2. Stop the server. Wait 10 seconds. Start it again.
  3. If errors persist, the database may be partially corrupt. Stop the server, copy pulseconnect.db somewhere safe as a backup, then delete it. The plugin will recreate a fresh database on next startup. (You'll lose audit log history, ticket history, and accounts — re-add the admin account via config.yml.)

Authentication

3 issues
Auth failed with correct password
Cause

Username or password doesn't match what the plugin's database stored. Common reasons: trailing spaces from copy-paste, caps lock, or the credentials in config.yml were changed after first launch (those fields only matter on first launch — the database is the source of truth after that).

Fix
  1. Type the username and password manually instead of pasting. Watch for caps lock and trailing spaces.
  2. If you changed admin.username or admin.password in config.yml after the plugin's first run, those changes had no effect. Use whatever credentials existed at first launch.
  3. If you've truly forgotten, see Forgot admin credentials below.
Locked out — "too many attempts"
Cause

5 failed login attempts within 15 minutes triggers an automatic lockout (configurable). The lockout is keyed by username + IP, and resets on its own.

Fix
  1. Wait 15 minutes (or whatever security.lockout-minutes is in config.yml) and try once more — this time with the correct credentials.
  2. If you need to bypass it immediately, restarting the server clears the in-memory lockout state.
// developers The same lockout applies to API calls to POST /auth/login — your custom client will get a 429 Too Many Requests. Implement an exponential backoff after a 401 to avoid tripping the lockout during testing.
Forgot admin credentials
Cause

The owner password is BCrypt-hashed in the plugin's database and isn't recoverable. The clean reset path is to wipe the database and let the plugin recreate the account from config.yml.

Fix — clean reset
  1. Stop the server.
  2. Edit plugins/PulseConnect/config.yml and set admin.username and admin.password to fresh values.
  3. Delete (or move aside as backup) plugins/PulseConnect/pulseconnect.db.
  4. Start the server. The plugin will create a new database and a new owner account from the values in config.yml.
  5. Sign in with the new credentials in the app.

What you lose: audit log history, closed tickets, any flagged players, ban/mute history that's stored in the plugin (server-side bans in the vanilla banlist are unaffected).

Push notifications

2 issues
Notifications not arriving
Cause

Push delivery has several layers — any one of them can be off. Work through them in order.

Diagnose
  1. iOS-level permission — Settings → PulsePanel → Notifications → confirm Allow Notifications is on.
  2. App-level toggles — in the app, Settings → Notifications → confirm the categories you care about (tickets, server lag, etc.) are enabled.
  3. Server has internet access — the plugin needs outbound HTTPS to deliver pushes. If your server is firewalled to local-only, push won't work. A quick curl https://www.google.com from the server confirms outbound is open.
  4. Device is registered — open the app once on the device you want notifications on. The app registers its APNs token on each launch.
  5. Trigger a test event — join the server yourself (player_join is an easy one to verify), or open and reply to a ticket in-game.

If all of the above check out and notifications still aren't arriving, send the symptom + your iOS version to support@pulsepanelapp.com.

Notifications arrive delayed (minutes late)
Cause

Almost always iOS-side, not server-side. Apple intentionally batches and throttles pushes when the device is in low-power mode, on a constrained network, or has been idle for a while. The relay forwards within milliseconds — Apple's queue is what introduces delay.

Things that help
  • Disable Low Power Mode on the device.
  • Open the PulsePanel app at least once a day — apps that haven't been opened in a while get more aggressively throttled.
  • For tickets specifically, raising priority (tickets.manage + Set priority → high) marks the push as time-sensitive on iOS, which bypasses some throttling.

For genuinely real-time monitoring, the in-app live console and dashboard are sub-second; push is for awareness when you're not in the app.

App behavior

2 issues
Dashboard is empty after connecting
Cause

The app authenticated but no data is flowing. Most often this means the server is still mid-startup, or there's a plugin error suppressing the data streams.

Fix
  1. Wait 20-30 seconds, then pull-to-refresh the dashboard.
  2. Check the server console for any [PulseConnect] error lines around the time you signed in.
  3. Force quit the app (swipe up from app switcher) and reopen it.
  4. If the dashboard fills in but specific tabs (Console, Players, etc.) are empty, that points to a permission issue — sign out and back in to refresh your token.
File manager won't save — "file changed" conflict
Cause

The plugin uses optimistic locking on file writes. If the file changed on disk between when you opened it in the app and when you tried to save, the plugin returns a conflict instead of overwriting blindly.

Fix
  1. Tap the file again to reload the latest version.
  2. Re-apply your edits to the fresh content.
  3. Save again.

This usually happens when something else (a plugin auto-rewrite, a separate SSH session, or another admin) modified the same file. The conflict is protecting your edits — the file would have lost data otherwise.

// developers The same mechanism applies to POST /files/write — if your expected_hash doesn't match, you'll get 409 Conflict with the current hash in the response. Re-read with GET /files/read and retry. Full details in the API reference.

Hosting-specific gotchas

1 issue
Reverse proxy (nginx / Caddy / Cloudflare) breaks WebSocket
Cause

HTTP requests work but the live console / chat / events don't stream. Reverse proxies often need explicit WebSocket upgrade headers, and Cloudflare's free tier will sometimes interfere with long-lived WebSocket connections.

Fix — nginx
location /api/v1/ws {
  proxy_pass http://localhost:7070;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_read_timeout 86400;
}
Fix — Caddy

Caddy handles WebSocket upgrades automatically. A simple reverse_proxy localhost:7070 works for both REST and WebSocket — no extra config needed.

Fix — Cloudflare

Cloudflare's free plan supports WebSockets, but you may need to enable it explicitly under Network → WebSockets. If you're seeing intermittent disconnects, also check your Page Rules aren't caching the API path.

Still stuck?
If your issue isn't above, the Contact section has a checklist of what to include in a bug report so I can help fast.
Open contact
changelog

What's changing.

Release history for both the iOS app and the PulseConnect plugin. Newest first.

First release pending

The full changelog will start populating with the App Store launch. Subsequent updates to the iOS app and plugin will all land here with version numbers, dates, and notes.

// awaiting v1.0
faq

Frequently asked.

Quick answers to the questions that come up most often. If yours isn't here, get in touch.

Compatibility & hosting

What server software is supported?

Paper, Spigot, and Purpur on Minecraft 1.21 or newer. Anything that runs Bukkit-API plugins on Java 17+. Forge and Fabric are not currently supported.

Will it work on a managed Minecraft host?

Only if the host allows you to open an additional TCP port beyond the Minecraft port. Some managed hosts lock the network down and only expose Minecraft itself — PulsePanel can't reach the server in that case.

Before paying for a host, ask whether they support opening custom TCP ports for plugins. Many do, some on request, some not at all.

Do I need to open ports on my server?

Yes — one TCP port for the plugin (7070 by default, configurable). Forward it on your router for remote access. Setup takes about a minute on most routers, and the setup guide walks through the common cases.

Security & privacy

Is it safe to expose my server like this?

Yes, with the standard caveats that apply to any service exposed to the internet. The plugin authenticates every request, file access is sandboxed to plugin folders, every privileged action is logged, and login attempts are rate-limited with lockouts.

The app authenticates over TLS using the credentials you create on the server. Your data flows directly between the app and your server — never through anyone else's infrastructure.

Where do my credentials live?

On your server (hashed with BCrypt in the plugin's database) and on your iPhone (in the iOS Keychain). Nothing is stored on PulsePanel infrastructure — there are no PulsePanel accounts.

What does PulseRelay see?

The relay is a pass-through for push notifications. It forwards to Apple's Push Notification service and discards the data. No database, no logs of notification contents, no IP retention. Full details in the privacy policy.

Pricing & licensing

Is the plugin free?

Yes. PulseConnect is free and stays free. You only pay once for the iOS app — no subscription, no per-server fee.

Is there a free trial?

The plugin is free, so you can run it on your server with no commitment. The iOS app is a one-time purchase — Apple's standard refund policy applies if it doesn't work for you.

Features & roadmap

Can multiple staff use the app?

Not yet. The current release is owner-only — one admin account, one device. Multi-staff support with per-user permissions is on the roadmap.

The plugin's API does support multi-user accounts and granular permissions if you're building a custom client. See the API reference.

Can I manage multiple servers from one app?

Not in the current release — single server only. Multi-server is on the roadmap.

Can I integrate with Discord / a web dashboard / a CLI?

Yes. The plugin's REST + WebSocket API is fully documented. See the API reference for endpoint specs and worked examples in Python, Node, and curl.

contact

Get in touch.

PulsePanel is built and maintained by one developer. Every email reaches me directly.

Email

For bug reports, feature requests, billing questions, security disclosures, or anything else:

support@pulsepanelapp.com

Typical response: within a couple of days.

Bug reports — what to include

The more of the following you can include, the faster I can help:

  • What happened vs. what you expected
  • Steps to reproduce, if you can find them
  • Server software and version (e.g. Paper 1.21.4)
  • Plugin version from config.yml or the plugin list
  • iOS version and device
  • Server console excerpt with any [PulseConnect] lines around the time of the issue

A screenshot of the app's error message also helps a lot.

Security disclosures

If you've found a security vulnerability, please email support@pulsepanelapp.com with details. Don't open a public issue or post about it publicly until it's been addressed.

I take this seriously and will respond as soon as possible — typically same day for anything that affects user security.