Features Showcase Commands Setup Docs Current Release: v.X.Y.Z GitHub โ†’
โ† Back to Home

Getting Started

Welcome to CraftDaemon! This documentation covers everything you need to know to install, configure, and run CraftDaemon on your Linux server. If this is your first time, read through each section in order, skipping steps is the most common cause of setup issues.

What is CraftDaemon?

CraftDaemon is a Discord bot that lets you manage your Minecraft server directly from Discord using slash commands. It integrates with systemd (Linux's service manager) to start, stop, and restart your server process, and uses RCON (a remote console protocol built into Minecraft) to query live server data like player count and TPS. You don't need to SSH into your server just to restart it, CraftDaemon handles it all from a Discord channel.

System Requirements

  • Operating System: Linux with systemd (Ubuntu, Debian, Arch, etc.) - Check Operating System Compatibility
  • Node.js: v18+ (v22 recommended; used for development and testing). To check what you have, run: node --version
  • Minecraft Server:: Any server with RCON support enabled (Although Paper is recommended)
  • Network: Outbound HTTPS access for the Discord API, and a local connection to RCON (127.0.0.1 by default)
โ„น๏ธ Paper vs Other servers

CraftDaemon works with any Minecraft server that supports RCON for start/stop/restart commands. However, the full /status command (Specifically for TPS) requires a Paper server. This is the sole reason Paper is recommended, apart from it being extremely light. Compatiblity is being worked on for future updates.

โ„น๏ธ Operating System Compatibility

This bot does not run natively on Windows or macOS. Advanced users may still run it using environments like Windows Subsystem for Linux (WSL) on Windows, or other Unix-like setups on macOS, but this is not officially supported.

โš ๏ธ Node Version Note

A future migration to TypeScript is planned, which will likely require Node.js v22+.

Installation

Step 1: Clone the Repository

SSH into your Linux server and run the following to download CraftDaemon into the current directory, then navigate into it:

git clone https://github.com/d1vid3d/CraftDaemon
cd CraftDaemon

Step 2: Install Node.js Dependencies

This installs all required packages listed in package.json. Run this from inside the CraftDaemon directory:

npm install

If you get a "command not found" error, Node.js is not installed or not in your PATH. Verify with node --version and which node.

Step 3: Create Discord Bot Application

You'll need to create a bot account in Discord's developer portal. This gives you a token (like a password) that CraftDaemon uses to log in as your bot.

  1. Go to Discord Developer Portal at discord.com/developers/applications
  2. Click "New Application" and give it a name (e.g., "CraftDaemon")
  3. Navigate to the "Bot" section in the left sidebar and click "Add Bot"
  4. Click "Reset Token" to reveal your bot token, then copy it โ€” you'll paste this into your .env file later. You only see it once, so save it now.
  5. Scroll down to "Privileged Gateway Intents" and enable both:
    • Server Members Intent
    • Message Content Intent
  6. Go to "OAuth2" โ†’ "URL Generator" in the left sidebar. Under "Scopes", check bot and applications.commands
  7. Under "Bot Permissions", check: Send Messages, Embed Links, Read Message History
  8. Copy the generated URL at the bottom of the page and open it in your browser to invite the bot to your Discord server
โš ๏ธ Token Security

Your bot token is like a password, never share it. If you are contributing or modifying the for code yourself, never commit it to Git. Keep it only in your config/.env file, and make sure .env is listed in your .gitignore. If it gets leaked, immediately regenerate it in the Developer Portal.

Step 4: Set Up Minecraft as a systemd Service (If you haven't already)

CraftDaemon controls your Minecraft server through systemd, Linux's service manager. If your server isn't already running as a systemd service, you'll need to set this up. Create the service file using a text editor with root privileges:

sudo nano /etc/systemd/system/minecraft.service

Paste the following content into the file, then save and exit (Ctrl+O, Enter, Ctrl+X in nano):

[Unit]
Description=Minecraft Server
After=network.target

[Service]
Type=simple
User=minecraft
WorkingDirectory=/home/minecraft/server
ExecStart=/usr/bin/java -Xmx8G -Xms8G -jar server.jar nogui
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Adjust the following to match your setup before saving:

  • User: the Linux user that owns the Minecraft server files
  • WorkingDirectory: the full path to your server folder
  • ExecStart: make sure the java path is correct (which java will tell you) and the .jar filename matches your actual server jar
  • -Xmx8G / -Xms8G: the maximum and starting RAM for your server โ€” adjust to suit your machine

Then reload systemd and enable the service to start on boot:

sudo systemctl daemon-reload
sudo systemctl enable minecraft
sudo systemctl start minecraft

Step 5: Enable RCON on Your Server

RCON (Remote Console) is a protocol built into Minecraft that allows CraftDaemon to query live server data and send commands. You need to enable it in your server's server.properties file, which is located in your Minecraft server directory. Open it with:

sudo nano /home/minecraft/server/server.properties

Find and update (or add) these three lines:

enable-rcon=true
rcon.port=25575
rcon.password=your_secure_password_here

Use a strong, unique password โ€” this password must exactly match the RCON_PASSWORD value in your .env later. After saving, restart your Minecraft server:

sudo systemctl restart minecraft

Step 6: Configure Environment Variables

CraftDaemon uses a .env file to store all sensitive configuration like your bot token and RCON password. Start by copying the provided example file:

cp config/.env.example config/.env

Then open it for editing:

nano config/.env

Fill in your values. At minimum, set these required fields:

TOKEN=your_bot_token_here
GUILD_ID=your_server_id
CLIENT_ID=your_client_id
STATUS_CHANNEL_ID=your_channel_id
MC_SERVICE=minecraft
RCON_HOST=127.0.0.1
RCON_PORT=25575
RCON_PASSWORD=your_rcon_password
AUTO_STOP_MINUTES=10
WARNING_MINUTES=8

See the Configuration section for a full breakdown of every available variable.

Step 7: Register Slash Commands

Before users can see or use slash commands in Discord, they need to be registered with Discord's API. Run this once from the CraftDaemon directory:

node src/register-commands.js
โ„น๏ธ When to re-run command registration

You only need to run this once after initial setup, or again if you add or modify commands. Slash commands may take up to a minute to appear in Discord after registration.

Step 8: Set Up Sudoers Permissions

CraftDaemon needs to run systemctl commands (to start/stop/restart your Minecraft server) without being prompted for a password. This is done by adding a rule to the sudoers file. Always edit sudoers with visudo โ€” it validates the file before saving and prevents you from locking yourself out:

sudo visudo

Scroll to the bottom of the file and add this line, replacing botuser with the Linux username the bot runs as:

botuser ALL=(ALL) NOPASSWD: /bin/systemctl start minecraft, /bin/systemctl stop minecraft, /bin/systemctl restart minecraft, /bin/systemctl show minecraft

Save and exit (Ctrl+O, Enter, Ctrl+X). To verify which user the bot will run as, check your craftdaemon.service file's User= field.

๐Ÿ”’ Least Privilege

Only grant the bot the specific systemctl permissions it needs (as shown above). Never add the bot user to ALL=(ALL) NOPASSWD: ALL โ€” that would give it unrestricted root access to your entire system.

Step 9: Install as systemd Service (Optional but Recommended)

Running CraftDaemon as a systemd service means it automatically starts on boot and restarts itself if it crashes. Create the service file:

sudo nano /etc/systemd/system/craftdaemon.service

Paste the following, then update User and WorkingDirectory to match your setup:

[Unit]
Description=CraftDaemon Bot
After=network.target

[Service]
Type=simple
User=botuser
WorkingDirectory=/path/to/CraftDaemon
ExecStart=/usr/bin/node src/index.js
Restart=on-failure
RestartSec=10s
StandardOutput=journal
StandardError=journal
Environment="NODE_ENV=production"

[Install]
WantedBy=multi-user.target

Make sure the node path in ExecStart is correct โ€” run which node to find yours. Then enable and start:

sudo systemctl daemon-reload
sudo systemctl enable craftdaemon
sudo systemctl start craftdaemon
โ„น๏ธ Node version note

CraftDaemon requires Node.js 18+ and is tested on Node.js 22. Check your version with node --version. If you need to install or update Node.js, use nvm or your distro's package manager.

Configuration

Environment Variables (.env)

All configuration is managed through config/.env. This file should never be shared or committed to Version Control, it lives only on your server (If you're using GitHub). If the file doesn't exist yet, create it by copying the example: cp config/.env.example config/.env, then edit it with nano config/.env. Here's a complete reference of every available variable:

Variable Required Description Options (Suggested Range)
TOKEN โœ… Your Discord bot token Discord bot token string
GUILD_ID โœ… Your Discord server ID (for registration) Discord guild/server ID
CLIENT_ID โœ… Your Discord application client ID Discord application client ID
STATUS_CHANNEL_ID โœ… Channel for status/warning messages Discord channel ID
MC_SERVICE โœ… Minecraft systemd service name Systemd unit name (default: minecraft)
SERVER_TYPE โ˜‘๏ธ Server type for TPS reporting in /status PAPER (default left blank), change to PAPER for Paper tps parsing
RCON_HOST โœ… RCON server address Default: 127.0.0.1
RCON_PORT โœ… RCON port (from server.properties) Valid: 1-65535 (default: 25575)
RCON_PASSWORD โœ… RCON password (from server.properties) Must exactly match server.properties
AUTO_STOP_MINUTES โ˜‘๏ธ Minutes before auto-stop (set 0 to disable) 0 or 5-60 (default: 10)
WARNING_MINUTES โ˜‘๏ธ Minutes before warning is posted 0 to disable warning, otherwise below AUTO_STOP_MINUTES (default: 8)
CHECK_INTERVAL_MS โ˜‘๏ธ Auto-stop check interval in milliseconds 10000-60000 (default: 30000)
SAVEALL_DELAY_MS โ˜‘๏ธ Delay between save-all and stop/restart 500-3000 (default: 1000)
COMMAND_COOLDOWN_MS โ˜‘๏ธ Cooldown between start/stop/restart commands 0 or 2000-60000 (default: 10000)
PRESENCE_SYSTEMD_FALLBACK_INTERVAL_MS โ˜‘๏ธ Presence fallback interval while RCON is disconnected 10000-30000 (default: 15000)
RCON_KEEPALIVE_INTERVAL_MS โ˜‘๏ธ Persistent RCON keepalive interval 30000-60000 (default: 45000)
RCON_RECONNECT_INTERVAL_MS โ˜‘๏ธ Delay between RCON reconnect attempts 3000-10000 (default: 5000)
RCON_STARTING_GRACE_PERIOD_MS โ˜‘๏ธ How long to keep "Server Starting..." state after reconnect 5000-20000 (default: 10000)
RCON_COMMAND_TIMEOUT_MS โ˜‘๏ธ Timeout for individual RCON commands 5000-15000 (default: 8000)
RCON_MAX_KEEPALIVE_FAILURES โ˜‘๏ธ Keepalive failures before forced reconnect 1-3 (default: 2)
RCON_REFUSED_LOG_INTERVAL_MS โ˜‘๏ธ Throttle interval for repeated ECONNREFUSED logs 0 or 30000-120000 (default: 60000)
LOG_LEVEL โ˜‘๏ธ Global log level DEBUG, INFO, WARN, ERROR
DEBUG_PERMS โ˜‘๏ธ Enable detailed permission check logs true or false (default: false)
MAIN_ADDRESS โ˜‘๏ธ Public server address for /address command Any reachable public address (optional)
LOCAL_ADDRESS โ˜‘๏ธ LAN address for /address command LAN address + port (optional)
JAVA_EDITION_VERSION โ˜‘๏ธ Java version text shown in /address Any Java version label text (optional)
UPDATE_NOTIFY_CHANNEL_ID โ˜‘๏ธ Preferred channel for update announcement embeds Discord channel ID (optional; has fallback behavior)
UPDATE_SERVICE_DEBUG โ˜‘๏ธ Enable mock latest-version override for testing true or false (default: false)
UPDATE_SERVICE_FORCE_LATEST โ˜‘๏ธ Forced semver used as latest when update debug is enabled Semver string, used when UPDATE_SERVICE_DEBUG=true

Legend: โœ… = Required, โ˜‘๏ธ = Optional (defaults are used when omitted).

Permission Configuration

Edit config/permission-config.js to control which Discord roles and users can run which commands. Open it with nano config/permission-config.js. The file exports a single object with four keys:

  • owner: an array of Discord user IDs that bypass all permission checks โ€” typically just you
  • roles: a map of short label names (e.g. ADMIN) to Discord role IDs
  • commands: maps each permission key to an array of role labels that can use it
  • users: optional per-user overrides that grant specific permission keys to individual users regardless of their roles
module.exports = {
  owner: ["123456789012345678"],
  roles: {
    ADMIN: "111111111111111111",
    MOD: "222222222222222222",
    Add more...: "333333333333333333"
  },
  commands: {
    "server.start": ["ADMIN", "MOD"],
    "server.stop": ["ADMIN", "MOD"],
    "server.restart": ["ADMIN"],
    "server.status": ["ADMIN", "MOD"],
    "server.address": ["ADMIN", "MOD"],
    "bot.checkUpdate":["ADMIN", "MOD"]
  },
  users: {
    "444444444444444444": ["logs.delete"]
  }
};

Replace the placeholder IDs with your actual Discord role and user IDs. Owners bypass all command checks entirely. Entries in users take precedence over role-based permissions โ€” useful for granting or restricting access to specific individuals.

Commands Reference

/start

Starts the Minecraft server by running systemctl start on your configured service. The bot replies with a status embed confirming the start was triggered.

  • Permission: server.start
  • Response: Confirmation embed with server startup status
  • Notes: The server itself may take 10โ€“30 seconds to fully boot depending on world size โ€” this is normal. The command only triggers the start; it does not wait for the server to be ready.

/stop

Gracefully stops the server. Before stopping, CraftDaemon sends a save-all command via RCON to ensure no world data is lost, then calls systemctl stop.

  • Permission: server.stop
  • Response: Confirmation embed with stop status
  • Notes: This is safe to use at any time โ€” the save-all happens automatically before shutdown

/restart

Restarts the server by saving world data first, then calling systemctl restart. Useful after config changes or to apply updates without manually stopping and starting.

  • Permission: server.restart
  • Response: Confirmation embed with restart status
  • Notes: Like /stop, this always performs a save-all before restarting

/status

Shows a full live snapshot of your server: systemd service state, uptime, TPS (ticks per second), online player count, and current RCON round-trip latency.

  • Permission: server.status
  • Response: Rich embed with all server metrics
  • Requires: A Paper server for full metrics (TPS, vanilla and other servers will not show TPS)
  • Latency: Shows RCON round-trip time, which reflects the connection health between the bot and your server

/address

Displays your server's connection details: public IP/domain, LAN address, and the Java edition version label. Useful for sharing with players.

  • Permission: server.address
  • Response: Embed with connection details
  • Requires: MAIN_ADDRESS and LOCAL_ADDRESS set in config/.env โ€” the command still works without them but will show empty fields

/ping

Checks the bot's connection health by measuring Discord API round-trip latency. Does not interact with the Minecraft server.

  • Permission: No restriction โ€” all Discord members can use this
  • Response: Simple message showing API latency in milliseconds
  • Notes: Useful for confirming the bot is alive and responsive if other commands seem slow

/checkupdate

Fetches the latest release from GitHub and compares it to the version currently running. If a newer version is available, the full changelog is displayed in the embed.

  • Permission: bot.checkUpdate
  • Response: Embed showing current version vs latest GitHub release
  • If newer: Displays the full changelog from the release notes

Permissions & RBAC

How Permissions Work

CraftDaemon uses a role-based access control (RBAC) system defined in config/permission-config.js. The idea is simple: each bot command has a permission key (e.g. server.start), and you decide which Discord roles can use it. You never configure permissions inside Discord itself โ€” everything is in that one JS file on your server.

Available Permission Keys

Permission Key Controls
server.start /start command
server.stop /stop command
server.restart /restart command
server.status /status command
server.address /address command
bot.checkUpdate /checkupdate command

Example Configuration

Here's a typical setup with Owner, Admin, and Moderator roles. Replace the placeholder IDs with your real ones (see "Finding Discord IDs" below):

module.exports = {
  owner: ["OWNER_USER_ID"],
  roles: {
    ADMIN: "ADMIN_ROLE_ID",
    MOD: "MODERATOR_ROLE_ID"
  },
  commands: {
    "server.start": ["ADMIN", "MOD"],
    "server.stop": ["ADMIN", "MOD"],
    "server.restart": ["ADMIN"],
    "server.status": ["ADMIN", "MOD"],
    "server.address": ["ADMIN", "MOD"],
    "bot.checkUpdate":["ADMIN"]
  },
  users: {
    "YOUR_USER_ID": ["server.start"]
  }
};

Finding Discord IDs

Discord IDs are long numeric strings that identify users, roles, and servers. To copy them, you first need to enable Developer Mode in Discord:

  • Open Discord โ†’ User Settings (gear icon) โ†’ Advanced โ†’ enable Developer Mode
  • To get a Role ID: go to Server Settings โ†’ Roles, then right-click the role and select "Copy Role ID"
  • To get a User ID: right-click any user in the server member list and select "Copy User ID"
  • To get your Guild (Server) ID: right-click the server name/icon and select "Copy Server ID"
โ„น๏ธ Owner Override

Users listed in the owner array can run any command regardless of what's in commands. This is intended for the server admin โ€” typically just your own Discord user ID.

Features Guide

Auto-Shutdown

CraftDaemon can automatically shut down your Minecraft server when no players have been online for a specified duration. This is especially useful if you're paying for a VPS or cloud server โ€” no one online means no point running it.

Configuration (in config/.env):

  • AUTO_STOP_MINUTES โ€” how many idle minutes before the server stops. Set to 0 to disable auto-shutdown entirely
  • WARNING_MINUTES โ€” how many minutes before shutdown to post a warning message in your status channel. Must be less than AUTO_STOP_MINUTES
  • CHECK_INTERVAL_MS โ€” how often (in milliseconds) the bot checks if the server is idle (default: 30000 = every 30 seconds)

How it works, step by step:

  1. The last player leaves the server โ€” player count hits 0
  2. The idle countdown timer starts
  3. When WARNING_MINUTES remain, the bot posts a warning in the status channel
  4. When the full AUTO_STOP_MINUTES expires, CraftDaemon automatically runs /stop (saves world first)

Live Bot Presence

CraftDaemon updates your bot's Discord status in real time to reflect your server state. Anyone in your Discord server can glance at the bot in the member list and immediately know if the server is up without running a command.

Presence states:

  • ๐Ÿ”ด Do Not Disturb โ€” Server is offline
  • ๐ŸŸก Idle โ€” Server is starting up
  • ๐ŸŸข Online โ€” Shows live player count (e.g. "3 player(s) online")

RCON Manager

CraftDaemon maintains a persistent RCON connection to your Minecraft server rather than opening a new one for every command. This makes queries faster and allows the bot to detect connection drops and recover automatically.

What this handles for you:

  • Automatic reconnection if the RCON connection drops (e.g. after a server restart)
  • Command queueing so requests don't fail if sent during a brief reconnect window
  • Live TPS and player count polling for presence updates
  • RCON round-trip latency monitoring shown in /status

Update Notifications

Run /checkupdate at any time to see if a newer version of CraftDaemon is available. The bot fetches the latest release tag from GitHub and compares it to the version currently running. If an update is available, the full changelog from the release notes is shown in the response embed so you know exactly what changed before updating.

Troubleshooting

Bot Won't Start

Problem: "TOKEN not found in config/.env"

The bot can't find your Discord token. Make sure config/.env exists (not just config/.env.example) and that TOKEN= is set. Create it with cp config/.env.example config/.env, then edit it with nano config/.env.

Problem: "Failed to connect to RCON"

Check three things: (1) enable-rcon=true is set in server.properties, (2) the RCON_PASSWORD in your .env exactly matches rcon.password in server.properties, and (3) the Minecraft server is actually running (sudo systemctl status minecraft).

Commands Not Working

Problem: Slash commands don't appear in Discord

Run node src/register-commands.js again. Make sure GUILD_ID and CLIENT_ID in your .env are correct. Commands can take up to a minute to appear in Discord after registration.

Problem: "You do not have permission to run this command"

Check config/permission-config.js. Verify that your Discord role ID or user ID is correctly entered โ€” IDs are 18โ€“19 digit numbers. Open it with nano config/permission-config.js and double-check the values. You can also set DEBUG_PERMS=true in your .env to see detailed permission check logs.

Server Control Issues

Problem: "/start doesn't work"

This is almost always a sudoers issue. Run sudo visudo and verify the bot user has the correct NOPASSWD rule for systemctl commands. Also confirm the service name in the sudoers rule matches MC_SERVICE in your .env (default is minecraft).

Problem: "/status shows no data"

Full status data (TPS) requires a Paper server. Also verify RCON is connected by checking the bot logs.

Checking Logs

If CraftDaemon is running as a systemd service, view its live logs with:

journalctl -u craftdaemon -f

The -f flag follows the log in real time (like tail -f). Press Ctrl+C to exit. If you want to run the bot directly to see output in your terminal instead (useful for debugging), stop the service first and run:

sudo systemctl stop craftdaemon
node src/index.js

For Minecraft server logs:

journalctl -u minecraft -f

Architecture

System Overview

CraftDaemon sits between Discord and your Minecraft server, translating slash commands into systemd and RCON calls:

Discord User
โ†“
โ†“ /slash command
โ†“
CraftDaemon Bot โ†โ†’ systemctl start/stop/restart โ†โ†’ Minecraft (systemd)
โ†‘ โ†“
โ†โ†’ RCON 127.0.0.1:25575 โ†โ†’ RCON Server

Directory Structure

Here's the full layout of the repository and what each file/folder of the bot does:

CraftDaemon/
โ”œโ”€โ”€ config/
โ”‚ โ”œโ”€โ”€ permission-config.js # RBAC rules (owners/roles/command permissions)
โ”‚ โ””โ”€โ”€ .env.example # Environment variable template
โ”œโ”€โ”€ src/
โ”‚ โ”œโ”€โ”€ index.js # Bot entry: client, RconManager, presence, auto-stop, command loader
โ”‚ โ”œโ”€โ”€ register-commands.js # Guild slash registration (reads src/commands/*.js)
โ”‚ โ”œโ”€โ”€ commands/ # One file per slash command (data + permission + execute)
โ”‚ โ”‚ โ”œโ”€โ”€ ping.js
โ”‚ โ”‚ โ”œโ”€โ”€ start.js
โ”‚ โ”‚ โ”œโ”€โ”€ stop.js
โ”‚ โ”‚ โ”œโ”€โ”€ restart.js
โ”‚ โ”‚ โ”œโ”€โ”€ address.js
โ”‚ โ”‚ โ”œโ”€โ”€ status.js
โ”‚ โ”‚ โ””โ”€โ”€ checkUpdate.js
โ”‚ โ”œโ”€โ”€ events/
โ”‚ โ”‚ โ””โ”€โ”€ interactionCreate.js # Slash dispatch: RBAC middleware โ†’ command.execute()
โ”‚ โ”œโ”€โ”€ permissions/
โ”‚ โ”‚ โ”œโ”€โ”€ index.js
โ”‚ โ”‚ โ”œโ”€โ”€ middleware.js # permissionMiddleware (ephemeral deny)
โ”‚ โ”‚ โ””โ”€โ”€ resolver.js # hasPermission() against permission-config.js
โ”‚ โ”œโ”€โ”€ utils/
โ”‚ โ”‚ โ””โ”€โ”€ storage.js # JSON persistence for per-guild update-notification state
โ”‚ โ””โ”€โ”€ services/
โ”‚ โ”œโ”€โ”€ autoStopService.js # Auto-Stop/Auto-Shutdown logic and handler
โ”‚ โ”œโ”€โ”€ updateService.js # GitHub release polling, ETag cache, update embed delivery
โ”‚ โ”œโ”€โ”€ rconManager.js # Persistent RCON connection lifecycle + command pipeline
โ”‚ โ”œโ”€โ”€ rconQuery.js # Command-facing RCON helpers (wired after clientReady)
โ”‚ โ”œโ”€โ”€ minecraftSystemd.js # systemctl + save-all before stop/restart
โ”‚ โ”œโ”€โ”€ commandLock.js # Cooldown lock for start/stop/restart
โ”‚ โ””โ”€โ”€ logger.js # Structured logging utility used across bot modules
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ README.md
โ„น๏ธ Layout flexibility (Advanced)

The src/ layout is the intended structure, but the bot isn't rigid about it. If you prefer running index.js from the project root, that works too, as long as the paths in your systemd ExecStart point to the right place AND your file imports are correct.

Key Services

  • logger.js: Structured logging with category prefixes, timestamps, and color-coded log levels. Used across all modules โ€” see the Logging section for full details
  • rconManager.js: Persistent RCON connection lifecycle โ€” handles connect, keepalive pinging, automatic reconnect on failure, and the command pipeline
  • rconQuery.js: Command-facing RCON helpers (e.g. player list, TPS queries) that are wired up after the client is ready
  • minecraftSystemd.js: Wraps systemctl calls with a save-all flow before stop/restart operations to prevent data loss
  • updateService.js: Polls the GitHub Releases API with ETag caching to compare the running version against the latest tag; delivers update embeds to a configured channel
  • commandLock.js: Cooldown guard that prevents rapid repeated start/stop/restart calls within the configured COMMAND_COOLDOWN_MS window
  • middleware.js / resolver.js: RBAC enforcement layer โ€” every slash command interaction passes through permissionMiddleware before command.execute() is called
  • storage.js: Lightweight JSON persistence for per-guild state (e.g. update notification tracking)

Managing Services

Once both CraftDaemon and your Minecraft server are running, you'll mostly interact with them through Discord slash commands. But you'll occasionally need to manage things directly from the server โ€” here's a reference for every useful command.

systemctl โ€” Controlling Services

These commands let you start, stop, and inspect both the bot and the Minecraft server as systemd services. Replace craftdaemon with minecraft (or whatever you named your service) where applicable.

# Check the current status of a service (active state, recent logs, PID)
sudo systemctl status craftdaemon
sudo systemctl status minecraft

# Start a service
sudo systemctl start craftdaemon

# Stop a service
sudo systemctl stop craftdaemon

# Restart a service (stop then start)
sudo systemctl restart craftdaemon

# Enable a service to start automatically on boot
sudo systemctl enable craftdaemon

# Disable autostart on boot
sudo systemctl disable craftdaemon

# Reload systemd after creating or editing a .service file
sudo systemctl daemon-reload

journalctl โ€” Reading Logs

journalctl reads logs written by systemd services. These are your main tool for debugging when something isn't working as expected.

# View the last 50 lines of logs for the bot
journalctl -u craftdaemon -n 50 --no-pager

# Follow live logs in real time (like tail -f) โ€” press Ctrl+C to exit
journalctl -u craftdaemon -f

# Follow live logs for the Minecraft server
journalctl -u minecraft -f

# View logs since the last boot only
journalctl -u craftdaemon -b

# View logs from a specific time window
journalctl -u craftdaemon --since "1 hour ago"
โ„น๏ธ Best debugging workflow

Open two terminals: run journalctl -u craftdaemon -f in one, and reproduce the issue in the other. You'll see exactly what the bot is doing in real time as it happens.

Logging

CraftDaemon uses a structured logging system with category-based prefixes, timestamps, and color-coded log levels. Every log line tells you when something happened, which component produced it, and how severe it is โ€” making it much easier to trace issues across the bot.

Log Format

Every log entry follows this structure:

HH:MM:SS [Category] [Level] Message

For example:

12:35:47 [RCON] [DEBUG] Sending command: list
12:35:47 [RCON] [DEBUG] RCON response received: There are 0 of a max of 20 players online
12:36:02 [AutoStop] [WARN] Server has been empty for 8 minutes
12:36:12 [SystemD] [ERROR] Failed to start server: Permission denied

Log Categories

Each category corresponds to a specific part of the bot. You'll see these as the bracketed label after the timestamp:

Category Color What it covers
[Bot] Cyan General bot lifecycle and startup configuration
[Discord] Blue Discord.js client events and API interactions
[Minecraft] Red Minecraft server-specific events
[RCON] Magenta RCON connection lifecycle, commands sent, responses received
[AutoStop] Yellow Auto-shutdown timer events and idle detection
[SystemD] White systemctl calls โ€” start, stop, restart, status

Log Levels

Level Color When you'll see it
[DEBUG] Gray Detailed internal info (RCON commands, reconnect attempts). Hidden by default โ€” enable with LOG_LEVEL=DEBUG
[INFO] Green Normal operation โ€” bot started, server started/stopped, commands executed
[WARN] Yellow Something worth noticing but not broken โ€” RCON refused while server starts, idle warning sent
[ERROR] Red Something failed and needs attention โ€” permission denied, unhandled exception

Changing the Log Level

By default the log level is INFO, which hides DEBUG output. To change it, set LOG_LEVEL in your config/.env:

LOG_LEVEL=DEBUG

Valid values: DEBUG, INFO, WARN, ERROR. No code changes or restarts of systemd are needed beyond restarting the bot itself (sudo systemctl restart craftdaemon).

Real Log Examples

Startup configuration summary โ€” printed every time the bot comes online:

03:15:30 [Bot] [INFO] ========== BOT STARTUP CONFIGURATION ==========
03:15:30 [Bot] [INFO] RCON Host: 127.0.0.1
03:15:30 [Bot] [INFO] RCON Port: 25575
03:15:30 [Bot] [INFO] Minecraft Service: minecraft-service.service
03:15:30 [Bot] [INFO] Auto-stop enabled: Yes (10 min idle, warning at 8 min)
03:15:30 [Bot] [INFO] Status channel ID: 1404683867265489235
03:15:30 [Bot] [INFO] Main address: my-minecraft-server.joinmc.link
03:15:30 [Bot] [INFO] =============================================
03:15:31 [Discord] [INFO] โœ… CraftDaemon is online.
03:15:31 [Discord] [INFO] Logged in as CraftDaemon#2232
03:15:31 [SystemD] [INFO] Managing systemd service: minecraft-server.service

A slash command received from Discord:

03:16:29 [SystemD] [INFO] Start command from steve

RCON refused while the server is starting up โ€” the bot throttles repeated refusal logs so they don't flood your output:

12:32:41 [RCON] [WARN] RCON connection refused (server may be offline/starting). Retrying every 5s. [connect ECONNREFUSED 127.0.0.1:25575]
12:33:41 [RCON] [WARN] RCON connection refused (server may be offline/starting). Retrying every 5s. (+11 similar refusals suppressed) [connect ECONNREFUSED 127.0.0.1:25575]

Auto-stop engaging โ€” the full idle โ†’ warning โ†’ shutdown sequence:

03:17:00 [AutoStop] [INFO] Server is now empty. Auto-stop timer started (10 minutes until shutdown).
03:25:00 [AutoStop] [WARN] Server empty for 8.0 minutes. Warning sent (2 min until shutdown).
03:27:00 [AutoStop] [INFO] Server empty for 10.0 minutes (threshold: 10). Initiating shutdown.

Adding Logging to Custom Code

If you're extending CraftDaemon with your own modules, you can use the same logger. Import createLogger and give your component a category name:

const { createLogger } = require("./services/logger");
const myLogger = createLogger('MyComponent');

myLogger.info("Something happened");
myLogger.warn("This might be a problem");
myLogger.error("An error occurred: " + err.message);
myLogger.debug("Detailed debug info โ€” only visible with LOG_LEVEL=DEBUG");
โ„น๏ธ Performance note

Logging is lightweight and designed for production use. DEBUG-level calls are completely skipped (not just filtered) when the log level is set to INFO or higher, so there's no performance penalty for leaving debug calls in your code.

Contributing

Want to Help?

CraftDaemon is a solo project and contributions are very welcome! Whether it's bug fixes, new features, documentation improvements, or just suggestions โ€” any input is appreciated.

How to Contribute

  1. Fork the repository on GitHub (click "Fork" on the repo page)
  2. Clone your fork locally: git clone https://github.com/YOUR_USERNAME/CraftDaemon
  3. Create a feature branch: git checkout -b feature/my-feature
  4. Make your changes
  5. Test thoroughly โ€” make sure existing functionality still works
  6. Commit with a clear message: git commit -m "Add my feature"
  7. Push to your fork: git push origin feature/my-feature
  8. Open a Pull Request on GitHub against the main repo
๐Ÿ’ก Note

You should open an issue first for substantial, larger changes, or breaking changes, so we can align before you put work in.

Reporting Bugs

Found a bug? Open an issue on GitHub Issues. A good bug report includes:

  • A clear description of what went wrong
  • Steps to reproduce the issue
  • What you expected to happen vs what actually happened
  • Your environment details: Linux distro, Node.js version (node --version), Minecraft server type
  • Relevant log output from journalctl -u craftdaemon if applicable

Code Standards

  • Use consistent indentation (2 spaces)
  • Write descriptive variable and function names
  • Add comments for any complex or non-obvious logic
  • Test your changes before submitting
  • Follow the existing code style throughout the project

License

CraftDaemon is licensed under the MIT License. By contributing, you agree that your contributions will be licensed under the same license.

๐Ÿ’ฌ Questions?

Feel free to open a GitHub Discussion or Issue if you have questions about contributing. There's no such thing as a dumb question here, so don't hesitate to reach out.

๐ŸŒŸ Like this project?

If CraftDaemon has been useful to you, consider giving it a โญ on GitHub! It helps others discover the project and means a lot to the development. Thanks for using it.