Minecraft 1.20.6 Paper Server Setup and Management Guide (AWS Lightsail, Ubuntu 22.04 LTS, Java 21)

Posted by

Minecraft 1.20.6 Paper Server Setup and Management Guide (AWS Lightsail, Ubuntu 22.04 LTS, Java 21)

Table of Contents:

1. Creating an AWS Lightsail Instance

This section explains in detail the process of creating an Ubuntu 22.04 LTS instance on AWS Lightsail.

  1. Log in to AWS Account:

  2. Select Lightsail Service:

    • Search for "Lightsail" in the AWS console or select it from the service list.
  3. Create an Instance:

    • Click on the "Create instance" button in the Lightsail dashboard.
  4. Select Instance Plan:

    • Region: Choose the region where you want to operate the server. In most cases, it's best to choose a region close to your users.
    • Platform: Select "Linux/Unix".
    • Blueprint: Choose "OS Only" and then select "Ubuntu 22.04 LTS".
  5. Choose Instance Plan:

    • For a Minecraft server, a minimum of 2GB RAM is recommended.
    • Choose an appropriate plan based on your budget and expected number of players.
    • You can start with a 2GB RAM / 1 vCPU plan and upgrade as needed.
  6. Name Your Instance:

    • Give it an easily identifiable name (e.g., "minecraft-paper-server").
  7. Create Instance:

    • Click the "Create instance" button to create the instance.
  8. Start Instance:

    • Once the instance is created, it will start automatically. Wait for the status to change to "Running".
  9. Allocate Static IP:

    • Go to the "Networking" tab on the instance management page.
    • Click the "Create static IP" button to allocate a static IP.
  10. Configure Firewall:

    • Check the firewall settings in the "Networking" tab.
    • Ensure there are inbound rules for SSH (port 22) and Minecraft server (default port 25565).
    • If the Minecraft port is missing, click "Add rule" and add "Custom" TCP 25565.
  11. Prepare for SSH Connection:

    • Go to the "Connect" tab on the instance management page.
    • Note the username (default: ubuntu) and IP address for SSH use.

Your AWS Lightsail instance is now ready. In the next step, we'll connect to this instance via SSH and proceed with server setup.

2. Basic System Configuration

After connecting to the AWS Lightsail instance via SSH, proceed with the basic system configuration.

  1. SSH Connection:

    • Windows users: Use PuTTY or Windows Terminal.
    • macOS/Linux users: Use the following command in the terminal:
      ssh ubuntu@your_instance_ip
  2. System Update:

    sudo apt update
    sudo apt upgrade -y
  3. Install Essential Packages:

    sudo apt install -y curl wget unzip screen htop
  4. Set Time Zone:

    sudo timedatectl set-timezone Asia/Seoul
  5. Configure Firewall:

    sudo ufw allow OpenSSH
    sudo ufw allow 25565/tcp
    sudo ufw enable
  6. Create Swap File (Optional, recommended if RAM is less than 4GB):

    sudo fallocate -l 4G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
  7. Adjust System Resource Limits:

    sudo nano /etc/security/limits.conf

    Add the following at the end of the file:

    * soft nofile 24000
    * hard nofile 40000
  8. Optimize sysctl Settings:

    sudo nano /etc/sysctl.conf

    Add the following at the end of the file:

    net.ipv4.tcp_fin_timeout = 30
    net.ipv4.tcp_keepalive_time = 1200
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_max_syn_backlog = 8192
    net.ipv4.ip_local_port_range = 10000 65535
    net.core.netdev_max_backlog = 65536
  9. Apply Changes:

    sudo sysctl -p
  10. Reboot:

    sudo reboot

After rebooting, reconnect via SSH to proceed with the next steps.

3. Installing Java 21

Install Java 21 to run the Paper server.

  1. Add Java 21 Repository:

    sudo add-apt-repository ppa:linuxuprising/java
  2. Update System:

    sudo apt update
  3. Install Java 21:

    sudo apt install oracle-java21-installer
  4. Verify Java Version:

    java -version

    Example output:

    java version "21.0.1" 2023-10-17 LTS
    Java(TM) SE Runtime Environment (build 21.0.1+12-LTS-29)
    Java HotSpot(TM) 64-Bit Server VM (build 21.0.1+12-LTS-29, mixed mode, sharing)
  5. Set JAVA_HOME Environment Variable:

    echo 'export JAVA_HOME=/usr/lib/jvm/java-21-oracle' >> ~/.bashrc
    echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
    source ~/.bashrc
  6. Verify JAVA_HOME:

    echo $JAVA_HOME

Java 21 is now successfully installed. Next, we'll install the Minecraft Paper server.

4. Installing Minecraft Paper Server

Paper server is a high-performance fork of Spigot, providing better performance and optimization. Here we'll install the Paper server for Minecraft version 1.20.6.

  1. Create Server Directory:

    mkdir ~/minecraft-server
    cd ~/minecraft-server
  2. Download Paper Server JAR File:

    wget https://api.papermc.io/v2/projects/paper/versions/1.20.6/builds/320/downloads/paper-1.20.6-320.jar

    Note: The above URL may change. Check the latest version at https://papermc.io/downloads.

  3. Create Server Startup Script:

    nano start.sh

    Enter the following content:

    #!/bin/bash
    java -Xms2G -Xmx2G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -jar paper-1.20.6-320.jar nogui

    This script uses Aikar's Flags to optimize server performance.

  4. Grant Execute Permission to the Script:

    chmod +x start.sh
  5. Agree to EULA:
    The first time you run the server, you need to agree to the EULA.

    ./start.sh

    When the server stops, agree to the EULA with the following command:

    echo "eula=true" > eula.txt
  6. Restart Server:

    ./start.sh

The Minecraft Paper server is now installed and running. In the next step, we'll configure and optimize the server.

5. Server Configuration and Optimization

To optimize the performance of the Minecraft server and configure it as desired, you can adjust various settings.

  1. server.properties Configuration:

    nano server.properties

    Key settings:

    server-port=25565
    max-players=20
    view-distance=10
    simulation-distance=6
    spawn-protection=16
    max-world-size=29999984
    network-compression-threshold=256
    online-mode=true
    allow-flight=false
    white-list=false

    Description of each setting:

    • server-port: Server port (default: 25565)
    • max-players: Maximum number of concurrent players
    • view-distance: Chunk distance players can see
    • simulation-distance: Chunk distance the server simulates
    • spawn-protection: Radius of spawn area protection
    • max-world-size: Maximum size of the world
    • network-compression-threshold: Network compression threshold
    • online-mode: Whether to authenticate with Mojang servers
    • allow-flight: Whether to allow flying
    • white-list: Whether to use a whitelist
  2. spigot.yml Configuration:

    nano spigot.yml

    Key settings:

    settings:
     save-user-cache-on-stop-only: true
     moved-wrongly-threshold: 0.0625
     moved-too-quickly-multiplier: 10.0
    world-settings:
     default:
       merge-radius:
         item: 2.5
         exp: 3.0
       item-despawn-rate: 6000
       view-distance: 10
       entity-activation-range:
         animals: 32
         monsters: 32
         raiders: 48
         misc: 16
       tick-inactive-villagers: false
       mob-spawn-range: 6
  3. paper-world-defaults.yml Configuration:

    nano config/paper-world-defaults.yml

    Key settings:

    entities:
     behavior:
       disable-chest-cat-detection: true
     spawning:
       despawn-ranges:
         ambient:
           soft: 32
           hard: 128
         axolotls:
           soft: 32
           hard: 128
         creature:
           soft: 32
           hard: 128
         misc:
           soft: 32
           hard: 128
         monster:
           soft: 32
           hard: 128
         underground_water_creature:
           soft: 32
           hard: 128
         water_ambient:
           soft: 32
           hard: 64
         water_creature:
           soft: 32
           hard: 128
    chunks:
     max-auto-save-chunks-per-tick: 6
    tick-rates:
     mob-spawner: 2
     container-update: 1
     grass-spread: 4
     bed-search-radius: 1
  4. bukkit.yml Configuration:

    nano bukkit.yml

    Key settings:

    settings:
     allow-end: true
     warn-on-overload: true
     permissions-file: permissions.yml
     update-folder: update
     plugin-profiling: false
     connection-throttle: 4000
     query-plugins: true
     deprecated-verbose: default
     shutdown-message: Server closed
    spawn-limits:
     monsters: 70
     animals: 10
     water-animals: 5
     water-ambient: 20
     water-underground-creature: 5
     ambient: 15
    chunk-gc:
     period-in-ticks: 600
    ticks-per:
     animal-spawns: 400
     monster-spawns: 1
     water-spawns: 1
     water-ambient-spawns: 1
     water-underground-creature-spawns: 1
     ambient-spawns: 1
  5. paper-global.yml Configuration:

    nano config/paper-global.yml

    Key settings:

    proxies:
     velocity:
       enabled: false
       online-mode: true
       secret: ''
    timings:
     enabled: true
     verbose: true
     server-name-privacy: false
     hidden-config-entries:
     - database
     - settings.bungeecord-addresses
    messages:
     kick:
       authentication-servers-down: Authentication servers are down. Please try again later.
       connection-throttle: Connection throttled! Please wait before reconnecting.
       flying-player: Flying is not enabled on this server
       flying-vehicle: Flying is not enabled on this server

These settings can greatly improve the server's performance and behavior. However, the optimal settings may vary depending on the server's hardware specifications and the number of players, so adjustments may be necessary.

6. Creating a Startup Script

Let's create a startup script to manage the Paper server more easily and enable automatic restarts. This script is based on the tool provided at https://docs.papermc.io/misc/tools/start-script-gen.

  1. Create a Startup Script:

    nano start.sh
  2. Paste the following content:

#!/bin/bash

# Server JAR file name
SERVER_JAR="paper-1.20.6-320.jar"

# Minimum and maximum memory allocation for the server
MIN_RAM="2G"
MAX_RAM="2G"

# Whether to run in the background (true/false)
BACKGROUND="false"

# Whether to automatically restart (true/false)
RESTART="true"

# Wait time for restart after crash (in seconds)
CRASH_TIMER=10

# JVM arguments
JVM_ARGS="-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true"

# Server directory
SERVER_DIR="$HOME/minecraft-server"

cd $SERVER_DIR

while true; do
    if [ "$BACKGROUND" == "true" ]; then
        screen -dmS minecraft java -Xms$MIN_RAM -Xmx$MAX_RAM $JVM_ARGS -jar $SERVER_JAR nogui
    else
        java -Xms$MIN_RAM -Xmx$MAX_RAM $JVM_ARGS -jar $SERVER_JAR nogui
    fi

    if [ "$RESTART" != "true" ]; then
        exit 0
    fi

    echo "Server has stopped. Restarting in $CRASH_TIMER seconds."
    sleep $CRASH_TIMER
done
  1. Grant execute permission to the script:

    chmod +x start.sh
  2. Run the script:

    ./start.sh

This script starts the server and automatically restarts it if it crashes. To run in the background, set BACKGROUND="true".

7. Managing Server Updates

Keeping your Paper server up to date is important to receive new features, bug fixes, and security patches. Here's how to update the server:

  1. Stop the Current Server:
    Enter the stop command in the server console or terminate the running screen session.

  2. Create a Backup:

    cp -r ~/minecraft-server ~/minecraft-server-backup-$(date +%Y%m%d)
  3. Check the Latest Paper Version:
    Check the latest version at https://papermc.io/downloads.

  4. Download the New JAR File:

    cd ~/minecraft-server
    wget https://api.papermc.io/v2/projects/paper/versions/1.20.6/builds/320/downloads/paper-1.20.6-320.jar

    Note: Update the URL to match the latest version.

  5. Update the start.sh Script:
    Update the SERVER_JAR variable with the new JAR file name.

  6. Restart the Server:

    ./start.sh
  7. Verify the Update:
    Check the version information in the server console.

You can also create an automatic update script to automate this process. Here's a simple example:

#!/bin/bash

# Change current directory to server directory
cd ~/minecraft-server

# Save current version information
CURRENT_VERSION=$(ls paper-*.jar | sed 's/paper-//' | sed 's/.jar//')

# Get latest version information
LATEST_VERSION=$(curl -s https://papermc.io/api/v2/projects/paper | jq -r '.versions[-1]')
LATEST_BUILD=$(curl -s https://papermc.io/api/v2/projects/paper/versions/${LATEST_VERSION} | jq -r '.builds[-1]')

# Compare versions
if [ "$CURRENT_VERSION" != "${LATEST_VERSION}-${LATEST_BUILD}" ]; then
    echo "New version available. Starting update."

    # Stop server
    screen -S minecraft -X stuff "say Server will restart for update in 5 seconds.\n"
    sleep 5
    screen -S minecraft -X stuff "stop\n"
    sleep 10

    # Create backup
    cp -r ~/minecraft-server ~/minecraft-server-backup-$(date +%Y%m%d)

    # Download new version
    wget https://papermc.io/api/v2/projects/paper/versions/${LATEST_VERSION}/builds/${LATEST_BUILD}/downloads/paper-${LATEST_VERSION}-${LATEST_BUILD}.jar

    # Update start.sh
    sed -i "s/SERVER_JAR=\"paper-.*\.jar\"/SERVER_JAR=\"paper-${LATEST_VERSION}-${LATEST_BUILD}.jar\"/" start.sh

    # Restart server
    ./start.sh

    echo "Update completed."
else
    echo "Server is already on the latest version."
fi

Save this script as update.sh, grant it execute permissions, and you can set it up as a cron job to run periodically.

8. Server Maintenance and Backup

Regular maintenance and backups are crucial for server stability and data protection.

  1. Regular Backup:
    Here's a simple backup script:

    #!/bin/bash
    
    # Backup directory setup
    BACKUP_DIR="/home/ubuntu/minecraft-backups"
    SERVER_DIR="/home/ubuntu/minecraft-server"
    BACKUP_NAME="minecraft-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
    
    # Create backup directory if it doesn't exist
    mkdir -p $BACKUP_DIR
    
    # Send backup start message to server
    screen -S minecraft -X stuff "say Starting backup. There may be some lag for a moment.\n"
    
    # Save world and disable auto-save
    screen -S minecraft -X stuff "save-all\n"
    screen -S minecraft -X stuff "save-off\n"
    
    # Create backup
    tar -czf $BACKUP_DIR/$BACKUP_NAME -C $SERVER_DIR world world_nether world_the_end
    
    # Re-enable auto-save
    screen -S minecraft -X stuff "save-on\n"
    
    # Delete old backups (older than 30 days)
    find $BACKUP_DIR -name "minecraft-backup-*.tar.gz" -mtime +30 -delete
    
    # Send backup completion message to server
    screen -S minecraft -X stuff "say Backup completed.\n"
    
    echo "Backup completed: $BACKUP_NAME"

    Save this script as backup.sh and grant it execute permissions:

    chmod +x backup.sh

    You can register it in crontab to run periodically:

    crontab -e

    Add the following line to run the backup daily at 4 AM:

    0 4 * * * /home/ubuntu/minecraft-server/backup.sh
  2. Log Management:
    Minecraft servers generate a lot of logs. You can use logrotate to manage them.

    Create a file /etc/logrotate.d/minecraft and add the following content:

    /home/ubuntu/minecraft-server/logs/*.log {
       daily
       rotate 7
       compress
       missingok
       notifempty
       create 644 ubuntu ubuntu
    }

    This setting compresses log files daily and keeps them for 7 days.

  3. Plugin Management:
    Plugins should be updated periodically. Here's a simple script for updating plugins:

    #!/bin/bash
    
    SERVER_DIR="/home/ubuntu/minecraft-server"
    PLUGINS_DIR="$SERVER_DIR/plugins"
    
    # Stop server
    screen -S minecraft -X stuff "say Server will restart for plugin updates in 5 seconds.\n"
    sleep 5
    screen -S minecraft -X stuff "stop\n"
    sleep 10
    
    # Move to plugins directory
    cd $PLUGINS_DIR
    
    # For each plugin
    for plugin in *.jar; do
       # Extract plugin name
       name=$(echo $plugin | sed 's/-.*//')
    
       # Download latest version from Spigot site (example URL)
       wget -O "$name-new.jar" "https://api.spigotmc.org/v2/plugins/$name/download"
    
       # If new version was successfully downloaded, replace
       if [ -f "$name-new.jar" ]; then
           mv "$name-new.jar" "$plugin"
           echo "Plugin $name has been updated."
       else
           echo "Failed to update plugin $name."
       fi
    done
    
    # Restart server
    cd $SERVER_DIR
    ./start.sh
    
    echo "Plugin updates completed."

    This script is just an example. In practice, you should use the official download URL for each plugin.

  4. Performance Monitoring:
    You can use the following tools to monitor server performance:

    • htop: Monitor system resource usage
    • nethogs: Monitor network usage
    • iotop: Monitor disk I/O

    To install these:

    sudo apt install htop nethogs iotop
  5. Regular Server Restart:
    Regularly restarting the server can prevent issues like memory leaks. You can use a script like this:

    #!/bin/bash
    
    # Send restart warning message to server
    screen -S minecraft -X stuff "say Server will restart in 5 minutes for maintenance.\n"
    sleep 240
    screen -S minecraft -X stuff "say Server will restart in 1 minute.\n"
    sleep 50
    screen -S minecraft -X stuff "say Server will restart in 10 seconds.\n"
    sleep 10
    
    # Stop server
    screen -S minecraft -X stuff "stop\n"
    sleep 30
    
    # Restart server
    /home/ubuntu/minecraft-server/start.sh

    Save this script as restart.sh and register it in crontab to run daily at 3 AM:

    0 3 * * * /home/ubuntu/minecraft-server/restart.sh
  6. Disk Space Management:
    Regularly check and manage the server's disk space. You can check disk usage with this command:

    df -h

    Script to clean up unnecessary files:

    #!/bin/bash
    
    SERVER_DIR="/home/ubuntu/minecraft-server"
    
    # Delete old log files (older than 30 days)
    find $SERVER_DIR/logs -name "*.log.*" -mtime +30 -delete
    
    # Delete old crash reports (older than 30 days)
    find $SERVER_DIR/crash-reports -name "*.txt" -mtime +30 -delete
    
    # Clean up player data (players who haven't connected in 6 months)
    find $SERVER_DIR/world/playerdata -name "*.dat" -mtime +180 -delete
    
    echo "Server cleanup completed."

By performing these maintenance tasks regularly, you can maintain the stability and performance of your server. Each script and setting should be adjusted according to the characteristics and needs of your server.

9. Troubleshooting and Logging

When operating a Minecraft server, you may encounter various issues. Effective troubleshooting requires good use of logs.

  1. Log Locations:

    • Server logs: /home/ubuntu/minecraft-server/logs/latest.log
    • Crash reports: /home/ubuntu/minecraft-server/crash-reports/
  2. Common Issues and Solutions:

    a) Server won't start:

    • Check the log file for error messages.
    • Verify that the Java version is correct.
    • Check if the server JAR file is not corrupted.

    b) Server lag:

    • Check the server's resource usage (CPU, RAM, disk I/O).
    • Verify that the number of players and server settings are appropriate for the hardware specifications.
    • Remove or disable unnecessary plugins.

    c) Plugin conflicts:

    • Disable recently added or updated plugins and check if the problem is resolved.
    • Check plugin logs for error messages.

    d) World corruption:

    • Restore the world from a backup.
    • Use tools like MCEdit to remove corrupted chunks.
  3. Log Analysis Tools:
    You can use the following tools to analyze logs more easily:

    • Graylog: Centralized log management system
    • ELK Stack (Elasticsearch, Logstash, Kibana): Log collection, analysis, and visualization tools
  4. Debug Mode:
    You can run the server in debug mode for troubleshooting. Add the following JVM argument to the start.sh script:

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

    Also, open port 5005 for remote debugging.

  5. Profiling:
    You can use profiling tools to analyze server performance issues. Paper has a built-in profiler:

    /timings on

    After some time:

    /timings paste

    This command provides a URL for the timing report.

  6. Adjusting Log Level:
    You can adjust the logging level to get more detailed information. In the server.properties file:

    debug=true

    However, be cautious as this setting can dramatically increase the size of log files.

  7. Periodic Health Check:
    You can create a script to periodically check the server's health status:

    #!/bin/bash
    
    SERVER_DIR="/home/ubuntu/minecraft-server"
    LOG_FILE="$SERVER_DIR/logs/latest.log"
    ALERT_EMAIL="your@email.com"
    
    # Check server process
    if ! pgrep -f "java.*paper-1.20.6-320.jar" > /dev/null; then
       echo "Server is not running. Restarting."
       $SERVER_DIR/start.sh
       echo "Server was down and has been restarted." | mail -s "Minecraft Server Alert" $ALERT_EMAIL
    fi
    
    # Check for errors in recent logs
    if grep -i "error\|exception\|crash" $LOG_FILE | tail -n 50 > /tmp/mc_errors.log; then
       echo "Errors found in server logs:"
       cat /tmp/mc_errors.log
       cat /tmp/mc_errors.log | mail -s "Minecraft Server Error Alert" $ALERT_EMAIL
    fi
    
    # Check disk space
    DISK_USAGE=$(df -h | awk '$NF=="/"{printf "%s", $5}' | sed 's/%//')
    if [ $DISK_USAGE -ge 90 ]; then
       echo "Disk usage has exceeded 90%. Current usage: $DISK_USAGE%" | mail -s "Minecraft Server Disk Warning" $ALERT_EMAIL
    fi
    
    echo "Server health check completed."

    You can set this script as a cron job to run periodically.

Effective troubleshooting requires careful monitoring of logs, a good understanding of server behavior, and a systematic approach when problems occur.

10. Security Configuration

Proper security configuration is essential for safely operating a Minecraft server. Here are several methods to enhance server security:

  1. Strengthen SSH Security:
    a) Disable root login:
    In the /etc/ssh/sshd_config file:

      PermitRootLogin no

    b) Allow only key-based authentication:

      PasswordAuthentication no

    c) Change SSH port:

      Port 2222  # Use a different port number instead of 22

    After changes, restart the SSH service:

    sudo systemctl restart sshd
  2. Firewall Configuration:
    Use UFW (Uncomplicated Firewall) to open only necessary ports:

    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 2222/tcp  # SSH port
    sudo ufw allow 25565/tcp  # Minecraft server port
    sudo ufw enable
  3. Regular System Updates:

    sudo apt update
    sudo apt upgrade -y
  4. Install and Configure fail2ban:
    fail2ban detects repeated login failures and blocks the corresponding IP.

    sudo apt install fail2ban
    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
    sudo nano /etc/fail2ban/jail.local

    Add or modify the following settings in the jail.local file:

    [sshd]
    enabled = true
    port = 2222
    filter = sshd
    logpath = /var/log/auth.log
    maxretry = 3
    bantime = 3600

    Start the fail2ban service:

    sudo systemctl start fail2ban
    sudo systemctl enable fail2ban
  5. Minecraft Server Security:
    a) Enable whitelist:
    In the server.properties file:

      white-list=true

    And add only allowed players:

      /whitelist add 

    b) Restrict op permissions:
    Edit the ops.json file to limit op levels.

    c) Plugin security:

    • Download plugins only from trusted sources.
    • Update plugins regularly.
    • Remove unused plugins.

    d) Set RCON password:
    In the server.properties file:

      rcon.password=
  6. DDoS Protection:
    AWS Lightsail provides basic DDoS protection, but for additional protection, consider the following methods:

    • Use DDoS protection services like CloudFlare
    • Set traffic limits (e.g., using iptables)
  7. Regular Security Audits:
    Regularly check the following items:

    • System and software update status
    • Open ports and running services
    • User accounts and permissions
    • Review log files
  8. Backup Encryption:
    Encrypt important data and backup files before storage:

    gpg -c backup.tar.gz

    This command encrypts the backup file. To decrypt:

    gpg backup.tar.gz.gpg
  9. SELinux or AppArmor Configuration:
    On Ubuntu, you can use AppArmor to configure an additional security layer:

    sudo apt install apparmor-utils
    sudo aa-genprof java

    Then run the Minecraft server and set the necessary permissions.

  10. Enhanced Log Monitoring:
    Set up tools to continuously monitor log files and detect suspicious activities. For example, you can use logwatch:

    sudo apt install logwatch
    sudo logwatch --output mail --mailto your@email.com --detail high
  11. Enhance Network Security:
    a) Configure TCP Wrappers:
    Use /etc/hosts.allow and /etc/hosts.deny files to control access.

    b) Set Iptables Rules:

       sudo iptables -A INPUT -p tcp --dport 25565 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
       sudo iptables -A OUTPUT -p tcp --sport 25565 -m conntrack --ctstate ESTABLISHED -j ACCEPT

    c) Optimize Packet Filtering:

       sudo sysctl -w net.ipv4.tcp_syncookies=1
       sudo sysctl -w net.ipv4.tcp_max_syn_backlog=2048
       sudo sysctl -w net.ipv4.tcp_synack_retries=2
       sudo sysctl -w net.ipv4.tcp_syn_retries=5
  12. Regular Vulnerability Scans:
    Use tools like OpenVAS or Nessus to periodically scan your system for vulnerabilities.

Applying these security settings can greatly enhance the security of your Minecraft server. However, security is an ongoing process, so it's important to always keep an eye on the latest security recommendations and keep your system up to date.

11. Performance Monitoring and Tuning

To optimize and maintain the performance of your Minecraft server, continuous monitoring and tuning are necessary. Here are methods to do this:

  1. Monitor System Resources:
    a) Using htop:

      htop

    You can check CPU, memory usage, and running processes in real-time.

    b) Using vmstat:

      vmstat 1

    Monitors system activity at 1-second intervals.

    c) Using iostat:

      iostat -x 1

    Monitors disk I/O statistics.

  2. Network Monitoring:
    a) Using iftop:

      sudo apt install iftop
      sudo iftop

    Monitors real-time network traffic.

    b) Using netstat:

      netstat -tuln

    Checks open ports and connection status.

  3. Monitor Java Heap Memory:
    You can use the jstat tool to monitor Java heap memory usage:

    jstat -gcutil  1000

    Here, is the Java process ID.

  4. Internal Performance Monitoring of Minecraft Server:
    a) /tps command:
    Checks the server's TPS (Ticks Per Second). 20 is ideal.

    b) /timings command:
    Analyzes the timing of internal server operations.

  5. Performance Tuning:
    a) JVM Tuning:
    Optimize the JVM arguments in the start.sh script. For example:

      java -Xms4G -Xmx4G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -jar paper.jar nogui

    b) Optimize Server Settings:
    Adjust settings in server.properties, spigot.yml, paper.yml files.

    c) World Optimization:

    • Limit render distance
    • Limit mob spawns
    • Optimize chunk loading

    d) Plugin Optimization:

    • Remove unnecessary plugins
    • Identify and replace resource-intensive plugins
  6. Build Performance Monitoring Dashboard:
    You can build a real-time performance monitoring dashboard using Grafana, Prometheus, InfluxDB, etc.

    a) Install InfluxDB:

      wget https://dl.influxdata.com/influxdb/releases/influxdb_1.8.10_amd64.deb
      sudo dpkg -i influxdb_1.8.10_amd64.deb
      sudo systemctl start influxdb

    b) Install Grafana:

      sudo apt-get install -y apt-transport-https
      sudo apt-get install -y software-properties-common wget
      wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
      echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
      sudo apt-get update
      sudo apt-get install grafana
      sudo systemctl start grafana-server

    c) Install Prometheus:

      wget https://github.com/prometheus/prometheus/releases/download/v2.30.3/prometheus-2.30.3.linux-amd64.tar.gz
      tar xvfz prometheus-2.30.3.linux-amd64.tar.gz
      cd prometheus-2.30.3.linux-amd64/
      ./prometheus

    Then add InfluxDB and Prometheus as data sources in Grafana and configure the dashboard.

  7. Automated Performance Reports:
    You can use a script like this to generate regular performance reports:

    #!/bin/bash
    
    # Collect system information
    echo "System Information:" > performance_report.txt
    echo "-------------" >> performance_report.txt
    echo "CPU Usage:" >> performance_report.txt
    top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}' >> performance_report.txt
    echo "Memory Usage:" >> performance_report.txt
    free -m | awk 'NR==2{printf "%.2f%%\n", $3*100/$2 }' >> performance_report.txt
    echo "Disk Usage:" >> performance_report.txt
    df -h | awk '$NF=="/"{printf "%s\n", $5}' >> performance_report.txt
    
    # Collect Minecraft server information
    echo "Minecraft Server Information:" >> performance_report.txt
    echo "-------------------------" >> performance_report.txt
    echo "Current Players:" >> performance_report.txt
    screen -S minecraft -X stuff "list^M"
    sleep 1
    tail -n 1 /home/ubuntu/minecraft-server/logs/latest.log | cut -d ' ' -f7- >> performance_report.txt
    echo "TPS:" >> performance_report.txt
    screen -S minecraft -X stuff "tps^M"
    sleep 1
    tail -n 1 /home/ubuntu/minecraft-server/logs/latest.log | cut -d ' ' -f7- >> performance_report.txt
    
    # Send report
    mail -s "Minecraft Server Performance Report" your@email.com < performance_report.txt

    You can set this script as a cron job to run periodically.

  8. Performance Benchmarking:
    You can use benchmarking tools to objectively evaluate server performance. For example, you can use the MinecraftBenchmark plugin to measure server performance.

  9. Log Analysis:
    Regularly analyze server logs to identify the causes of performance issues. For example:

    grep "Can't keep up!" /home/ubuntu/minecraft-server/logs/latest.log | wc -l

    This command counts the number of times the server "can't keep up".

  10. Monitor Network Latency:
    You can use the ping command to monitor network latency between the server and clients:

    ping -c 100 your_server_ip

    This command sends 100 packets and measures the average response time.

  11. Use Profiling Tools:
    You can use profiling tools like Java Flight Recorder (JFR) to perform in-depth analysis of server performance:

    java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr -jar paper.jar nogui

    This command profiles the server for 60 seconds and saves the result to the myrecording.jfr file.

  12. Server Warm-up:
    Allow some time for the server performance to stabilize after starting. Here's an example script for this:

    #!/bin/bash
    echo "Starting server warm-up..."
    ./start.sh &
    sleep 300  # Wait for 5 minutes
    echo "Warm-up complete. Server is ready."
  13. Chunk Preloading:
    You can preload frequently used chunks to improve performance. Paper provides a command for this:

    /paper chunk-task queue     load
  14. Monitor Garbage Collection:
    You can enable and analyze GC logs to understand memory usage patterns:

    java -Xms4G -Xmx4G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -Xloggc:gc.log -jar paper.jar nogui
  15. Analyze Plugin Performance:
    You can use tools like Plugin Metrics or Spark to analyze the performance impact of plugins.

  16. System Tuning:

    • Optimize disk I/O: Use noatime option
      sudo mount -o remount,noatime /
    • Minimize swap usage:
      echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
      sudo sysctl -p
  17. Periodic Performance Tests:
    Create and regularly run test scripts that put load on the server. For example:

    import socket
    import time
    
    def test_server(host, port, duration):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port))
        start_time = time.time()
        while time.time() - start_time < duration:
            sock.send(b'\xFE\x01')
            response = sock.recv(1024)
            time.sleep(1)
        sock.close()
        test_server('your_server_ip', 25565, 300)  # Test for 5 minutes
  18. Custom Monitoring Scripts:
    You can write custom scripts to monitor specific metrics of your server:

    #!/bin/bash
    while true; do
        players=$(screen -S minecraft -X stuff "list^M" && sleep 1 && tail -n 1 /home/ubuntu/minecraft-server/logs/latest.log | cut -d ' ' -f7-)
        tps=$(screen -S minecraft -X stuff "tps^M" && sleep 1 && tail -n 1 /home/ubuntu/minecraft-server/logs/latest.log | cut -d ' ' -f7-)
        cpu=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}')
        mem=$(free -m | awk 'NR==2{printf "%.2f%%", $3*100/$2 }')
        echo "$(date), Players: $players, TPS: $tps, CPU: $cpu, MEM: $mem" >> server_stats.log
        sleep 60
    done
  19. Automated Performance Optimization:
    You can create a script that automatically adjusts settings based on server performance:

    #!/bin/bash
    while true; do
        tps=$(screen -S minecraft -X stuff "tps^M" && sleep 1 && tail -n 1 /home/ubuntu/minecraft-server/logs/latest.log | cut -d ' ' -f7- | cut -d ',' -f1)
        if (( $(echo "$tps < 18" | bc -l) )); then
            screen -S minecraft -X stuff "gamerule randomTickSpeed 1^M"
            echo "TPS is low, reduced randomTickSpeed."
        else
            screen -S minecraft -X stuff "gamerule randomTickSpeed 3^M"
            echo "TPS is normal, set randomTickSpeed to default value."
        fi
        sleep 300
    done
  20. Performance Data Visualization:
    You can visualize collected performance data to analyze long-term trends. For example, you can use Python's matplotlib library:

    import matplotlib.pyplot as plt
    import pandas as pd
    
    # Read data from log file
    df = pd.read_csv('server_stats.log', parse_dates=[0], header=None, names=['timestamp', 'players', 'tps', 'cpu', 'mem'])
    
    # Create graph
    plt.figure(figsize=(12, 6))
    plt.plot(df['timestamp'], df['tps'], label='TPS')
    plt.plot(df['timestamp'], df['players'], label='Players')
    plt.xlabel('Time')
    plt.ylabel('Value')
    plt.title('Server Performance Over Time')
    plt.legend()
    plt.savefig('performance_graph.png')

By combining and using these tools and techniques, you can continuously monitor and optimize the performance of your Minecraft server. It's important to choose and customize appropriate methods according to the characteristics and usage patterns of your server.

12. Plugin Management

One of the great advantages of the Minecraft Paper server is the ability to extend server functionality using various plugins. However, it's also important to manage plugins effectively. Here's a detailed guide on plugin management:

  1. Plugin Selection:

  2. Plugin Installation:

    cd ~/minecraft-server/plugins
    wget 

    Restart the server or use the /reload confirm command to load the plugin.

  3. Plugin Configuration:
    Most plugins can be configured via the config.yml file:

    cd ~/minecraft-server/plugins/
    nano config.yml
  4. Plugin Updates:
    Regularly update plugins to apply bug fixes and new features:

    cd ~/minecraft-server/plugins
    rm .jar
    wget 

    Restart the server to load the new version.

  5. Disable Plugins:
    To temporarily disable a plugin without completely removing it:

    mv .jar .jar.disabled

    The plugin won't load when you restart the server.

  6. Manage Plugin Dependencies:
    Some plugins may depend on other plugins. Check dependencies and install all necessary plugins.

  7. Resolve Plugin Conflicts:
    If conflicts occur between plugins:

    • Check server logs to analyze error messages
    • Disable plugins one by one to find the cause of the problem
    • Contact the plugin developer or look for alternative plugins
  8. Monitor Plugin Performance:

    • Use the Spark plugin to analyze the performance impact of each plugin
    • Identify plugins that use excessive resources and optimize or replace them
  9. Automatic Plugin Updates:
    You can configure automatic plugin updates using plugins like UpdaterPlus.

  10. Plugin Backup:
    Regularly backup plugins and their configuration files:

    tar -czf plugins_backup_$(date +%Y%m%d).tar.gz ~/minecraft-server/plugins
  11. Plugin Documentation:
    Document the list of plugins installed on your server, their purposes, and settings:

    # Server Plugin List
    
    1. EssentialsX
       - Purpose: Provides basic server commands and features
       - Version: 2.19.0
       - Configuration: /plugins/Essentials/config.yml
    
    2. WorldEdit
       - Purpose: World editing tool
       - Version: 7.2.8
       - Configuration: /plugins/WorldEdit/config.yml
    
    ...
  12. Plugin Permission Management:
    Use permission management plugins like LuckPerms to control access to plugin commands.

  13. Separate Development and Production Environments:
    Use a separate test server when testing new plugins or configurations.

  14. Utilize Plugin APIs:
    Learn the APIs of frequently used plugins to develop custom scripts or plugins.

  15. Community Participation:
    Participate in plugin development communities to learn about the latest trends and best practices. You can use platforms like Reddit, Discord, or official Minecraft forums.

  16. Plugin Compatibility Testing:
    Before adding a new plugin, test its compatibility with existing plugins. It's best to try it on a test server first.

  17. Optimize Plugin Load Order:
    Some plugins may be sensitive to load order. You can adjust the load order using the 'plugin-priority' setting in the 'server.properties' file.

  18. Plugin Performance Profiling:
    Use plugins like TickProfiler or Timings to analyze the performance impact of each plugin in detail.

  19. Version Control for Plugin Settings:
    Use a version control system like Git to track changes in plugin configuration files.

    cd ~/minecraft-server
    git init
    git add plugins/*/config.yml
    git commit -m "Initial plugin configurations"
  20. Create Plugin Configuration Templates:
    Create configuration templates for frequently used plugins to save time when setting up new servers.

  21. Collect Plugin Usage Statistics:
    Use plugins like Plan to collect and analyze server and plugin usage statistics.

  22. Create Plugin Dependency Graphs:
    Visualize dependencies between plugins to understand the overall structure and optimize.

    import os
    import yaml
    import networkx as nx
    import matplotlib.pyplot as plt
    
    def get_dependencies(plugin_folder):
        dependencies = {}
        for plugin in os.listdir(plugin_folder):
            plugin_yml = os.path.join(plugin_folder, plugin, 'plugin.yml')
            if os.path.exists(plugin_yml):
                with open(plugin_yml, 'r') as f:
                    data = yaml.safe_load(f)
                    if 'depend' in data:
                        dependencies[plugin] = data['depend']
        return dependencies
    
    def create_dependency_graph(dependencies):
        G = nx.DiGraph()
        for plugin, deps in dependencies.items():
            G.add_node(plugin)
            for dep in deps:
                G.add_edge(plugin, dep)
        return G
    
    dependencies = get_dependencies('/path/to/plugins')
    G = create_dependency_graph(dependencies)
    nx.draw(G, with_labels=True)
    plt.savefig('plugin_dependencies.png')
  23. Plugin Configuration Validation:
    Write a script to automatically check the validity of plugin configuration files.

    import yaml
    import os
    
    def validate_config(config_path, schema):
        with open(config_path, 'r') as f:
            config = yaml.safe_load(f)
    
        for key, value_type in schema.items():
            if key not in config:
                print(f"Missing key: {key}")
            elif not isinstance(config[key], value_type):
                print(f"Invalid type for {key}: expected {value_type}, got {type(config[key])}")
    
    # Example schema
    essentials_schema = {
        'spawn-on-join': bool,
        'default-stack-size': int,
        'max-nick-length': int,
    }
    
    validate_config('/path/to/plugins/Essentials/config.yml', essentials_schema)
  24. Plugin Configuration Migration:
    The structure of configuration files may change when updating plugins. Write migration scripts to handle this automatically.

  25. Write Plugin Usage Guides:
    Document usage guides for each plugin for server administrators and players.

  26. Participate in Plugin Development:
    If a needed feature is missing, you can develop your own plugin or contribute to existing ones. This requires learning Java and the Bukkit API.

  27. Synchronize Plugin Settings:
    If you're operating multiple servers, write a script to synchronize plugin settings.

    #!/bin/bash
    
    SOURCE_SERVER="/path/to/source/server"
    TARGET_SERVERS=("/path/to/target/server1" "/path/to/target/server2")
    
    for target in "${TARGET_SERVERS[@]}"; do
        rsync -avz --delete $SOURCE_SERVER/plugins/ $target/plugins/
        echo "Synchronized plugins to $target"
    done
  28. Monitor Plugin Usage:
    Monitor the frequency and importance of use for each plugin to identify and remove unnecessary plugins.

  29. Plugin Configuration Backup and Restore:
    Write a script that can easily backup and restore plugin configurations.

    #!/bin/bash
    
    BACKUP_DIR="/path/to/backups"
    SERVER_DIR="/path/to/server"
    
    # Backup
    backup() {
        tar -czf $BACKUP_DIR/plugin_configs_$(date +%Y%m%d).tar.gz -C $SERVER_DIR plugins/*/config.yml
        echo "Backup created: $BACKUP_DIR/plugin_configs_$(date +%Y%m%d).tar.gz"
    }
    
    # Restore
    restore() {
        latest_backup=$(ls -t $BACKUP_DIR/plugin_configs_*.tar.gz | head -1)
        tar -xzf $latest_backup -C $SERVER_DIR
        echo "Restored configurations from $latest_backup"
    }
    
    case "$1" in
        backup)
            backup
            ;;
        restore)
            restore
            ;;
        *)
            echo "Usage: $0 {backup|restore}"
            exit 1
    esac
  30. Plugin Conflict Resolution Guide:
    Create and document a guide on common plugin conflict issues and their solutions.

By utilizing these advanced techniques, you can manage plugins on your Minecraft Paper server more effectively. Plugin management is an ongoing process, so it's important to continuously optimize and improve according to changes in server requirements.

13. Custom Maps and Game Modes

One of the charms of Minecraft is the ability to create and play various maps and game modes. Let's look in detail at how to implement custom maps and game modes on a Paper server.

  1. Creating Custom Maps:
    a) Using WorldEdit:
    WorldEdit is a powerful map editing tool.

      # Install WorldEdit
      wget https://dev.bukkit.org/projects/worldedit/files/latest -O plugins/WorldEdit.jar

    Key commands:

    • //wand: Get editing tool
    • //set : Fill selected area with specific block
    • //copy: Copy selected area
    • //paste: Paste copied area

    b) Using VoxelSniper:
    Useful for more detailed terrain manipulation.

      wget https://dev.bukkit.org/projects/voxelsniper/files/latest -O plugins/VoxelSniper.jar

    c) Utilizing External Tools:

    • MCEdit: Edit maps offline
    • World Painter: Generate large-scale terrains
  2. Creating Custom Structures:
    a) Using Structure Blocks:

      /give @p minecraft:structure_block

    You can save and load structures.

    b) Using Schematic Files:
    You can save and share structures as .schematic files with WorldEdit.

      //copy
      //schem save mystructure
  3. Implementing Custom Game Modes:
    a) Utilizing Scoreboards:

      /scoreboard objectives add Kills playerKillCount
      /scoreboard objectives setdisplay sidebar Kills

    b) Using Command Blocks:
    You can implement complex game logic.

      /give @p minecraft:command_block

    c) Plugin Development:
    Develop custom plugins using Java.

      public class MyGameMode extends JavaPlugin {
          @Override
          public void onEnable() {
              getLogger().info("Custom game mode has been activated!");
              this.getCommand("startgame").setExecutor(new StartGameCommand());
          }
      }
  4. World Management:
    a) Multi-World Setup:
    Use the Multiverse-Core plugin.

      wget https://dev.bukkit.org/projects/multiverse-core/files/latest -O plugins/Multiverse-Core.jar

    Key commands:

      /mv create  normal -t flat
      /mv tp 

    b) Setting World Border:

      /worldborder set 1000
  5. Setting Game Rules:
    a) Basic Game Rules:

      /gamerule keepInventory true
      /gamerule doDaylightCycle false

    b) Implementing Custom Rules:
    Implement more complex rules through plugins.

  6. Events and Mini-games:
    a) Using Event Scheduler:

      Bukkit.getScheduler().runTaskTimer(this, () -> {
          // Event logic
      }, 0L, 20L * 60); // Run every minute

    b) Utilizing Mini-game Plugins:
    Add various mini-games using plugins like MiniGames or Arcade.

  7. Custom Items and Mobs:
    a) Modifying Item Attributes:

      /give @p diamond_sword{display:{Name:'{"text":"Super Sword"}'},Enchantments:[{id:sharpness,lvl:10}]} 1

    b) Creating Custom Mobs:
    Use the MythicMobs plugin to create custom mobs.

  8. Creating Parkour Maps:
    a) Jump Pads:

      /setblock ~ ~ ~ slime_block

    b) Checkpoint System:
    Implement using command blocks.

  9. Setting up PvP Arena:
    a) Team Setup:

      /team add Red
      /team add Blue
      /team join Red @p

    b) Kill Count System:
    Utilize scoreboards.

  10. Implementing Economy System:
    Install an economy plugin that can be used with the Vault plugin.

    wget https://dev.bukkit.org/projects/vault/files/latest -O plugins/Vault.jar
  11. Quest System:
    Use the BetonQuest plugin to create complex quest lines.

    wget https://dev.bukkit.org/projects/betonquest/files/latest -O plugins/BetonQuest.jar
  12. Creating Custom NPCs:
    Use the Citizens plugin to create interactive NPCs.

    wget https://dev.bukkit.org/projects/citizens/files/latest -O plugins/Citizens.jar
  13. Particle Effects:

    player.getWorld().spawnParticle(Particle.FLAME, player.getLocation(), 50, 0.5, 0.5, 0.5, 0.1);

    This code creates flame particles around the player.

  14. Sound Effects:

    player.playSound(player.getLocation(), Sound.ENTITY_ENDER_DRAGON_GROWL, 1.0f, 1.0f);

    This code plays the Ender Dragon sound at the player's location.

  15. Custom Inventory GUI:

    Inventory gui = Bukkit.createInventory(null, 27, "Custom GUI");
    gui.setItem(13, new ItemStack(Material.DIAMOND));
    player.openInventory(gui);

    This code creates a custom GUI with a diamond in the center.

  16. Scenario Scripting:
    Use the Skript plugin to easily implement complex game scenarios.

    wget https://github.com/SkriptLang/Skript/releases/download/2.6.3/Skript.jar -O plugins/Skript.jar

    Skript example:

    on right click on stone:
        set block to diamond ore
        send "You found a diamond!" to player
  17. Custom Generators:

    public void spawnCustomMob(Location loc) {
        Zombie zombie = (Zombie) loc.getWorld().spawnEntity(loc, EntityType.ZOMBIE);
        zombie.setCustomName("Super Zombie");
        zombie.setCustomNameVisible(true);
        zombie.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(40.0);
        zombie.setHealth(40.0);
    }

    This code generates a custom zombie with enhanced health.

  18. Timer System:

    BukkitRunnable timer = new BukkitRunnable() {
        int time = 300;  // 5 minutes
        @Override
        public void run() {
            if (time <= 0) {
                cancel();
                Bukkit.broadcastMessage("Time's up!");
            } else {
                Bukkit.broadcastMessage("Time remaining: " + time + " seconds");
                time--;
            }
        }
    };
    timer.runTaskTimer(this, 0L, 20L);  // Run every second
  19. Custom Enchantments:

    @EventHandler
    public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
        if (event.getDamager() instanceof Player) {
            Player player = (Player) event.getDamager();
            ItemStack weapon = player.getInventory().getItemInMainHand();
            if (weapon.getItemMeta().getLore().contains("Flame Sword")) {
                event.getEntity().setFireTicks(100);  // Set on fire for 5 seconds
            }
        }
    }

    This code sets the target on fire when attacked with a weapon that has the "Flame Sword" lore.

  20. Custom Portals:

    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        if (event.getTo().getBlock().getType() == Material.END_PORTAL) {
            Player player = event.getPlayer();
            Location destination = new Location(player.getWorld(), 100, 64, 100);
            player.teleport(destination);
            player.sendMessage("You've been teleported by a mysterious force!");
        }
    }

    This code teleports the player to a specified location when they step on an end portal block.

  21. Dynamic World Generation:

    WorldCreator creator = new WorldCreator("NewWorld");
    creator.environment(World.Environment.NORMAL);
    creator.type(WorldType.NORMAL);
    creator.generateStructures(true);
    World newWorld = creator.createWorld();

    This code dynamically generates a new world.

  22. Custom Recipes:

    NamespacedKey key = new NamespacedKey(this, "custom_item");
    ItemStack result = new ItemStack(Material.DIAMOND);
    ShapedRecipe recipe = new ShapedRecipe(key, result);
    recipe.shape("AAA", "BBB", "CCC");
    recipe.setIngredient('A', Material.IRON_INGOT);
    recipe.setIngredient('B', Material.GOLD_INGOT);
    recipe.setIngredient('C', Material.EMERALD);
    Bukkit.addRecipe(recipe);

    This code adds a custom recipe to create a diamond using iron ingots, gold ingots, and emeralds.

  23. Weather Control:

    public void setCustomWeather(World world, boolean storm, int duration) {
        world.setStorm(storm);
        world.setWeatherDuration(duration);
        if (storm) {
            world.setThundering(true);
            world.setThunderDuration(duration);
        }
    }

    This method can be used to control the weather in a specific world.

  24. Player Skill System:

    Map cooldowns = new HashMap<>();
    
    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent event) {
        Player player = event.getPlayer();
        if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
            if (player.getInventory().getItemInMainHand().getType() == Material.BLAZE_ROD) {
                if (cooldowns.containsKey(player.getUniqueId())) {
                    long secondsLeft = ((cooldowns.get(player.getUniqueId()) / 1000) + 10) - (System.currentTimeMillis() / 1000);
                    if (secondsLeft > 0) {
                        player.sendMessage("Skill cooldown: " + secondsLeft + " seconds");
                        return;
                    }
                }
                player.getWorld().strikeLightning(player.getTargetBlock(null, 50).getLocation());
                cooldowns.put(player.getUniqueId(), System.currentTimeMillis());
            }
        }
    }

    This code implements a skill that summons lightning with a 10-second cooldown when right-clicking with a blaze rod.

  25. Dynamic Texture Changes:
    You can dynamically change the texture of in-game items using resource packs.

    ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
    ItemMeta meta = item.getItemMeta();
    meta.setCustomModelData(1001);  // Custom model data defined in the resource pack
    item.setItemMeta(meta);
    player.getInventory().addItem(item);
  26. Event-based Storytelling:

    int storyProgress = 0;
    
    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        Player player = event.getPlayer();
        Location loc = player.getLocation();
        if (storyProgress == 0 && loc.getBlockX() == 100 && loc.getBlockZ() == 100) {
            player.sendMessage("You feel a mysterious energy...");
            storyProgress = 1;
        } else if (storyProgress == 1 && loc.getBlockX() == 200 && loc.getBlockZ() == 200) {
            player.sendMessage("You've discovered ancient ruins!");
            storyProgress = 2;
        }
    }

    This code progresses the story based on the player's location.

  27. Dynamic Difficulty Adjustment:

    @EventHandler
    public void onEntitySpawn(EntitySpawnEvent event) {
        if (event.getEntity() instanceof Monster) {
            Monster monster = (Monster) event.getEntity();
            int playerCount = Bukkit.getOnlinePlayers().size();
            double healthMultiplier = 1 + (playerCount * 0.1);  // Increase health based on player count
            monster.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(monster.getHealth() * healthMultiplier);
            monster.setHealth(monster.getHealth() * healthMultiplier);
        }
    }

    This code dynamically adjusts monster health based on the number of online players.

By combining and expanding these features, you can create unique and interesting custom maps and game modes. It's important to get player feedback and continuously improve, and to experiment with new ideas. Also, consider introducing complex systems gradually, taking into account the server's performance.

14. Multi-World Setup

Managing multiple worlds on a Minecraft server is very useful for providing diverse gaming experiences. Here, we'll look at how to set up and manage multiple worlds on a Paper server.

  1. Install Multiverse-Core Plugin:
    Multiverse-Core is the most widely used plugin for managing multiple worlds.

    cd ~/minecraft-server/plugins
    wget https://dev.bukkit.org/projects/multiverse-core/files/latest -O Multiverse-Core.jar

    Restart the server to load the plugin.

  2. Basic Multiverse Commands:

    • Create world: /mv create <world_name> <world_type>
    • Load world: /mv load <world_name>
    • Unload world: /mv unload <world_name>
    • Delete world: /mv delete <world_name>
    • List worlds: /mv list
    • World info: /mv info <world_name>
    • Teleport to world: /mv tp <world_name>
  3. Create Various World Types:

    /mv create normal_world normal
    /mv create nether_world nether
    /mv create end_world end
    /mv create flat_world normal -t flat
  4. Set Game Rules for Each World:

    /mv gamerule   

    Example: /mv gamerule pvp_world pvp true

  5. Create World Portals:
    Additionally install the Multiverse-Portals plugin.

    wget https://dev.bukkit.org/projects/multiverse-portals/files/latest -O Multiverse-Portals.jar

    Create portal:

    /mvp create 
    /mvp set dest  
  6. Set World Access Permissions:
    Use Multiverse-Core's built-in permission system.

    /mv modify set -p  
  7. Use Custom World Generator:
    You can specify a custom generator when creating a world.

    /mv create custom_world normal -g YourCustomGenerator
  8. World Backup and Restore:

    # Backup
    tar -czf world_backup.tar.gz /path/to/world
    
    # Restore
    tar -xzf world_backup.tar.gz -C /path/to/server
    /mv load 
  9. Import World:
    You can add externally created worlds to your server.

    # Copy world files to server directory
    cp -r /path/to/external_world /path/to/server/
    
    # Add world to Multiverse
    /mv import external_world normal
  10. Per-World Inventory:
    You can use the Multiverse-Inventories plugin to manage separate inventories for each world.

    wget https://dev.bukkit.org/projects/multiverse-inventories/files/latest -O Multiverse-Inventories.jar
  11. World Regeneration:
    To regenerate only specific areas, you can use it with WorldEdit.

    //sel
    //regen

    To regenerate the entire world:

    /mv regen 
  12. Manage World Time and Weather:
    You can manage time and weather independently for each world.

    /mv modify set time  
  13. Set World Spawn Location:

    /mv set spawn

    This sets the current player's location as the spawn point for that world.

  14. Set World Border:

    /mv modify set border  
  15. Per-World Chat Settings:
    You can use the Multiverse-ChatManager plugin to separate chat by world.

    wget https://dev.bukkit.org/projects/multiverse-chatmanager/files/latest -O Multiverse-ChatManager.jar
  16. Per-World Economy System:
    You can implement different economy systems for each world using Vault.

  17. Restrict Item Movement Between Worlds:

    /mvim no   
  18. Manage World Groups:
    You can manage multiple worlds as a group.

    /mvg create 
    /mvg addworld  
  19. Per-World Mob Spawn Settings:

    /mv modify set spawning  
    /mv modify set animals  
    /mv modify set monsters  
  20. Copy World:
    You can create a new world by copying an existing one.

    /mv clone  
  21. Set Per-World Game Mode:

    /mv modify set gamemode  
  22. Automate World Loading:
    You can set worlds to load automatically when the server starts.
    In the config.yml file:

    autoload: true
  23. Set Per-World Difficulty:

    /mv modify set difficulty  
  24. Set Teleport Cooldown Between Worlds:

    /mv modify set portalcooldown  
  25. Set Per-World PvP:

    /mv modify set pvp  
  26. Set Per-World Hunger:

    /mv modify set hunger  
  27. Set World Prefix:
    Set a prefix to use when displaying world names in chat.

    /mv modify set prefix  
  28. Set Custom Spawn Items Per World:
    Set items that new players receive when first entering a specific world.

    /mv modify set firstspawnitem  
  29. Set Per-World Environment:
    You can change the environment (normal, nether, end) of each world.

    /mv modify set environment  
  30. Custom Generator Options per World:
    You can set additional options when creating a world with a custom generator.

    /mv create  normal -g TerrainControl:TC_MAIN
  31. Block Commands in Specific Worlds:
    You can prevent certain commands from being used in specific worlds.

    /mv block  
  32. Effects When Moving Between Worlds:
    You can give special effects to players when they move between worlds.

    @EventHandler
    public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
        Player player = event.getPlayer();
        World from = event.getFrom();
        World to = player.getWorld();
    
        player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));
        player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1.0f, 1.0f);
        player.spawnParticle(Particle.PORTAL, player.getLocation(), 100, 0.5, 1, 0.5);
    }
  33. Per-World Scoreboard:
    You can display different scoreboards for each world.

    @EventHandler
    public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
        Player player = event.getPlayer();
        World world = player.getWorld();
    
        Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
        Objective objective = scoreboard.registerNewObjective("worldInfo", "dummy", ChatColor.GOLD + world.getName());
        objective.setDisplaySlot(DisplaySlot.SIDEBAR);
    
        Score score = objective.getScore(ChatColor.GREEN + "Players: ");
        score.setScore(world.getPlayers().size());
    
        player.setScoreboard(scoreboard);
    }
  34. Restrict Vehicles in Specific Worlds:
    You can restrict the use of certain vehicles in specific worlds.

    @EventHandler
    public void onVehicleEnter(VehicleEnterEvent event) {
        if (event.getEntered() instanceof Player) {
            Player player = (Player) event.getEntered();
            if (player.getWorld().getName().equals("no_vehicles_world")) {
                event.setCancelled(true);
                player.sendMessage("Vehicles cannot be used in this world.");
            }
        }
    }
  35. Per-World Chat Format:
    You can use different chat formats for each world.

    @EventHandler
    public void onPlayerChat(AsyncPlayerChatEvent event) {
        Player player = event.getPlayer();
        String worldName = player.getWorld().getName();
        String format = ChatColor.GRAY + "[" + worldName + "] " + ChatColor.WHITE + "%s: %s";
        event.setFormat(format);
    }

By combining these features, you can create diverse game environments with unique characteristics and rules for each world. Through multi-world setup, you can provide players with varied gaming experiences and enrich your server's content. However, be aware that loading too many worlds simultaneously can burden server performance, so proper management is important.

15. Backup and Recovery Strategy

An effective backup and recovery strategy is essential for stable operation of a Minecraft server. Here, we'll look at how to safely back up Paper server data and recover it when needed.

  1. Create Automatic Backup Script:
    Here's an example of a basic backup script:

    #!/bin/bash
    
    # Configuration
    SERVER_DIR="/home/ubuntu/minecraft-server"
    BACKUP_DIR="/home/ubuntu/minecraft-backups"
    WORLDS_TO_BACKUP=("world" "world_nether" "world_the_end")
    MAX_BACKUPS=7
    
    # Timestamp
    TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
    
    # Create backup directory
    mkdir -p "$BACKUP_DIR"
    
    # Send backup start message to server
    screen -S minecraft -X stuff "say Server backup is starting. There may be a brief lag.$(printf '\r')"
    
    # Save world and disable auto-save
    screen -S minecraft -X stuff "save-all$(printf '\r')"
    screen -S minecraft -X stuff "save-off$(printf '\r')"
    
    # Create backup
    for world in "${WORLDS_TO_BACKUP[@]}"; do
       tar -czf "$BACKUP_DIR/$world-$TIMESTAMP.tar.gz" -C "$SERVER_DIR" "$world"
    done
    
    # Backup plugin configurations
    tar -czf "$BACKUP_DIR/plugins-$TIMESTAMP.tar.gz" -C "$SERVER_DIR" "plugins"
    
    # Backup server properties file
    cp "$SERVER_DIR/server.properties" "$BACKUP_DIR/server.properties-$TIMESTAMP"
    
    # Re-enable auto-save
    screen -S minecraft -X stuff "save-on$(printf '\r')"
    
    # Delete old backups
    for world in "${WORLDS_TO_BACKUP[@]}"; do
       find "$BACKUP_DIR" -name "$world-*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | head -n -$MAX_BACKUPS | cut -d' ' -f2- | xargs -r rm
    done
    find "$BACKUP_DIR" -name "plugins-*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | head -n -$MAX_BACKUPS | cut -d' ' -f2- | xargs -r rm
    find "$BACKUP_DIR" -name "server.properties-*" -type f -printf '%T@ %p\n' | sort -n | head -n -$MAX_BACKUPS | cut -d' ' -f2- | xargs -r rm
    
    # Send backup completion message to server
    screen -S minecraft -X stuff "say Server backup is complete.$(printf '\r')"
    
    echo "Backup completed: $TIMESTAMP"

    Save this script as backup.sh and grant execute permissions:

    chmod +x backup.sh
  2. Schedule Regular Backups:
    Use cron to automate backups.

    crontab -e

    Add the following line to run backups daily at 4 AM:

    0 4 * * * /home/ubuntu/minecraft-server/backup.sh
  3. Remote Backup:
    It's a good idea to store backup files on a different server or cloud storage.

    For example, if using AWS S3:

    aws s3 sync /home/ubuntu/minecraft-backups s3://your-bucket-name/minecraft-backups
  4. Verify Backup Integrity:
    Regularly check the integrity of backup files.

    for backup in /home/ubuntu/minecraft-backups/*.tar.gz; do
       if ! tar -tzf "$backup" > /dev/null 2>&1; then
           echo "Corrupted backup file: $backup"
       fi
    done
  5. Incremental Backup:
    Instead of full backups, you can back up only changed files to save storage space.

    rsync -avz --link-dest="/path/to/last_backup" "/path/to/minecraft-server" "/path/to/new_backup"
  6. Database Backup:
    If plugins use databases, they should be backed up as well.
    MySQL example:

    mysqldump -u username -p database_name > /path/to/backup/database_backup.sql
  7. Recovery Procedure:
    Here's how to recover the server from a backup:

    a) Stop the server

    screen -S minecraft -X stuff "say Server will shut down for recovery in 5 seconds.$(printf '\r')"
    sleep 5
    screen -S minecraft -X stuff "stop$(printf '\r')"

    b) Restore from backup

    # Restore world files
    tar -xzf /path/to/backup/world-TIMESTAMP.tar.gz -C /home/ubuntu/minecraft-server
    tar -xzf /path/to/backup/world_nether-TIMESTAMP.tar.gz -C /home/ubuntu/minecraft-server
    tar -xzf /path/to/backup/world_the_end-TIMESTAMP.tar.gz -C /home/ubuntu/minecraft-server
    
    # Restore plugin configurations
    tar -xzf /path/to/backup/plugins-TIMESTAMP.tar.gz -C /home/ubuntu/minecraft-server
    
    # Restore server properties file
    cp /path/to/backup/server.properties-TIMESTAMP /home/ubuntu/minecraft-server/server.properties

    c) Restart the server

    screen -S minecraft -dm bash -c 'java -Xms4G -Xmx4G -jar paper.jar nogui'
  8. Automatic Recovery Script:
    You can create a script to automate the recovery process.

    #!/bin/bash
    
    # Configuration
    SERVER_DIR="/home/ubuntu/minecraft-server"
    BACKUP_DIR="/home/ubuntu/minecraft-backups"
    TIMESTAMP=$1  # Timestamp of the backup to recover, received as an argument
    
    # Stop server
    screen -S minecraft -X stuff "say Server will shut down for recovery in 5 seconds.$(printf '\r')"
    sleep 5
    screen -S minecraft -X stuff "stop$(printf '\r')"
    sleep 10
    
    # Backup current server state
    mv "$SERVER_DIR" "${SERVER_DIR}_old_$(date +%Y%m%d_%H%M%S)"
    
    # Create new server directory
    mkdir -p "$SERVER_DIR"
    
    # Restore from backup
    tar -xzf "$BACKUP_DIR/world-$TIMESTAMP.tar.gz" -C "$SERVER_DIR"
    tar -xzf "$BACKUP_DIR/world_nether-$TIMESTAMP.tar.gz" -C "$SERVER_DIR"
    tar -xzf "$BACKUP_DIR/world_the_end-$TIMESTAMP.tar.gz" -C "$SERVER_DIR"
    tar -xzf "$BACKUP_DIR/plugins-$TIMESTAMP.tar.gz" -C "$SERVER_DIR"
    cp "$BACKUP_DIR/server.properties-$TIMESTAMP" "$SERVER_DIR/server.properties"
    
    # Restart server
    screen -S minecraft -dm bash -c 'cd /home/ubuntu/minecraft-server && java -Xms4G -Xmx4G -jar paper.jar nogui'
    
    echo "Server has been recovered from backup $TIMESTAMP."

    Save this script as restore.sh and grant execute permissions:

    chmod +x restore.sh

    Usage example:

    ./restore.sh 2023-07-13_04-00-00
  9. Backup Rotation:
    Automatically delete old backups to efficiently use disk space.

    # Delete backups older than 30 days
    find "$BACKUP_DIR" -name "*.tar.gz" -type f -mtime +30 -delete
    find "$BACKUP_DIR" -name "server.properties-*" -type f -mtime +30 -delete
  10. Backup Encryption:
    You can encrypt backups to protect important data.

    # Encrypt backup
    gpg --symmetric --cipher-algo AES256 "$BACKUP_DIR/$world-$TIMESTAMP.tar.gz"
    
    # Decrypt encrypted backup
    gpg --decrypt "$BACKUP_DIR/$world-$TIMESTAMP.tar.gz.gpg" > "$BACKUP_DIR/$world-$TIMESTAMP.tar.gz"
  11. Backup Notifications:
    Send email notifications to the administrator after backup completion.

    echo "Minecraft server backup completed. Timestamp: $TIMESTAMP" | mail -s "Backup Completion Notification" admin@example.com
  12. Backup Testing:
    Regularly perform recovery tests from backups to verify backup reliability.

    # Create temporary directory for testing
    TEST_DIR="/tmp/minecraft_backup_test"
    mkdir -p "$TEST_DIR"
    
    # Restore from backup
    tar -xzf "$BACKUP_DIR/world-$TIMESTAMP.tar.gz" -C "$TEST_DIR"
    
    # Check restored files
    if [ -f "$TEST_DIR/world/level.dat" ]; then
        echo "Backup test successful: world/level.dat file exists."
    else
        echo "Backup test failed: world/level.dat file is missing."
    fi
    
    # Clean up test directory
    rm -rf "$TEST_DIR"
  13. Differential Backup:
    Use differential backups along with full backups to save backup time and storage space.

    # Backup only files changed since the last full backup
    rsync -avz --link-dest="$BACKUP_DIR/latest" "$SERVER_DIR" "$BACKUP_DIR/$TIMESTAMP"
    ln -sfn "$BACKUP_DIR/$TIMESTAMP" "$BACKUP_DIR/latest"
  14. Optimize Backup Compression:
    You can use advanced compression options to reduce the size of backup files.

    XZ_OPT='-9' tar -cJf "$BACKUP_DIR/$world-$TIMESTAMP.tar.xz" -C "$SERVER_DIR" "$world"
  15. Store Backup Metadata:
    Store metadata for each backup to facilitate management.

    echo "Timestamp: $TIMESTAMP
    Server Version: $(java -jar paper.jar --version)
    Worlds: ${WORLDS_TO_BACKUP[*]}
    Plugins: $(ls -1 "$SERVER_DIR/plugins" | grep .jar)
    " > "$BACKUP_DIR/backup_info_$TIMESTAMP.txt"
  16. Rollback Feature:
    Implement a feature to roll back the server to a specific point in time.

    #!/bin/bash
    
    ROLLBACK_TIME=$1  # Format: YYYY-MM-DD_HH:MM:SS
    
    # Find the closest backup
    CLOSEST_BACKUP=$(find "$BACKUP_DIR" -name "world-*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | awk -v time="$ROLLBACK_TIME" '$1 <= time' | tail -n 1 | cut -d' ' -f2-)
    
    if [ -z "$CLOSEST_BACKUP" ]; then
        echo "No backup found before the specified time."
        exit 1
    fi
    
    # Execute rollback
    ./restore.sh $(basename "$CLOSEST_BACKUP" | sed 's/world-\(.*\)\.tar\.gz/\1/')
  17. Optimize Backup Performance:
    Methods to minimize the impact on server performance during backups:

    • Use nice command: nice -n 19 tar -czf ...
    • Use ionice: ionice -c2 -n7 tar -czf ...
    • Run backup in background: (backup_command) & disown
  18. Log Backup Results:
    Maintain detailed logs of the backup process.

    exec > >(tee -a "/var/log/minecraft_backup.log") 2>&1
    echo "Backup started: $(date)"
    # Backup commands...
    echo "Backup completed: $(date)"

Implementing these advanced backup and recovery strategies will allow you to securely protect your Minecraft server's data and quickly recover in case of issues. It's important to regularly review and test the backup process to ensure it's always up to date.

This concludes the Minecraft 1.20.6 Paper Server Setup and Management Guide. Through this guide, we hope you'll be able to operate a stable and optimized Minecraft server. If you have any additional questions or need more detailed explanations on any part, please feel free to ask.

Leave a Reply

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다