Want to run your own Minecraft world for friends, build a survival realm, or host a creative-mode showcase? Self-hosting is the way to go — and it's far easier than it looks once you have a real deployment workflow behind it. This guide walks you through setting up a Minecraft Java Edition server on a Linux VPS with an [automated deployment tool](https://www.deployhq.com/features/automatic-deployments), so every plugin update, config tweak, and version bump ships from Git instead of FTP.

If you're running multiple game servers through a control panel, see our companion guide on [Pterodactyl panel deployments](https://www.deployhq.com/blog/game-panel-integration-deploy-game-server-from-git). This post focuses on a single-server, plain-VPS setup — the foundation most self-hosters start from.

## What you'll need

Before we begin, gather your tools:

- **A Linux VPS:** We recommend an Ubuntu 24.04 LTS (or Debian 12+) VPS. Ubuntu 20.04 reached end of standard support in May 2025 — don't start a new server on it. New to VPSes? Our [What is a VPS?](https://www.deployhq.com/blog/vps-101-understanding-virtual-private-servers) primer covers the basics. For Minecraft 1.21+ vanilla, plan for at least **2 vCPUs, 4 GB RAM, and 50 GB SSD**. Modded packs and Paper with many plugins need more — 8 GB RAM is a comfortable floor once you start adding plugins.
- **A [DeployHQ](https://www.deployhq.com) account:** This is where the automation lives. A free trial gets you running.
- **An SSH client:** macOS/Linux Terminal, Windows Terminal, or any SSH client you prefer.
- **A Git repository** (GitHub, GitLab, or Bitbucket) to hold your `server.properties`, `eula.txt`, plugin configs, and any datapacks. [DeployHQ](https://www.deployhq.com) pulls from there on every change.

## Step 1: Prepare your VPS

### Connect via SSH

```
ssh root@your-server-ip
```

For production, create a non-root sudo user and disable root login over SSH — but that's outside this guide's scope.

### Install Java 21 (Minecraft's current requirement)

Minecraft Java Edition 1.21 and later **requires Java 21** (Java SE 21 LTS) per the official Minecraft Wiki. Older guides recommending Java 17 are stale — 1.21 won't start on Java 17.

Ubuntu 24.04 ships OpenJDK 21 directly:

```
sudo apt update
sudo apt install -y openjdk-21-jdk
java -version
```

You should see `openjdk version "21"` in the output. If you're sticking with an older Minecraft version (1.20.x) you can substitute `openjdk-17-jdk`, but the rest of this guide assumes 1.21+.

### Create a dedicated user and directory

Running Minecraft as root is sloppy. Create a service user and a home for the server:

```
sudo adduser --system --group --home /opt/minecraft minecraft
sudo mkdir -p /opt/minecraft
sudo chown -R minecraft:minecraft /opt/minecraft
```

### Open the firewall port

Minecraft uses TCP port `25565` by default:

```
sudo ufw allow 25565/tcp
sudo ufw enable # only if the firewall isn't already on
```

## Step 2: Choose your server JAR (Vanilla vs Paper)

You have two practical options:

- **Vanilla** (official `server.jar` from minecraft.net): faithful to Mojang's release, but slower under load and no plugin support. Fine for small friend-group servers running stock gameplay.
- **Paper** (drop-in replacement): performance-tuned fork of Spigot/Bukkit. Supports thousands of plugins, runs significantly better on a constrained VPS, and is what most serious self-hosters use. PaperMC documents Java requirements per Minecraft version — 1.20-1.21.11 is recommended on Java 21.

For this guide we'll set up Paper, since the [build pipeline](https://www.deployhq.com/features/build-pipelines) story (deploying plugins and configs from Git) only becomes useful once plugins are in play. The Java install is identical for vanilla — just swap the JAR.

## Step 3: Set up your Git repository

Create a Git repo with this layout:

```
minecraft-server/
├── server.properties
├── eula.txt
├── ops.json # optional, empty array to start
├── whitelist.json # optional, empty array to start
├── plugins/ # commit any Paper plugins you trust
│ └── .gitkeep
└── README.md
```

Your `eula.txt` should contain:

```
eula=true
```

By committing `eula=true` you've already accepted Mojang's EULA — [DeployHQ](https://www.deployhq.com) will deploy it on the first push and the server will start without the manual prompt step.

**Don't commit `paper.jar` itself** — it's binary, can be large, and you'll download a fresh build directly on the server. Commit a `download-paper.sh` script alongside it instead (see the build hook in Step 5).

## Step 4: Create the DeployHQ project

1. Log in to [DeployHQ](https://www.deployhq.com) and click **New Project**.
2. Connect the Git repository you just created.
3. Once the project exists, head to **Servers** → **New Server**.
4. Fill in:

5. [DeployHQ](https://www.deployhq.com) will generate an SSH public key. Copy it and add to `/opt/minecraft/.ssh/authorized_keys` on your VPS (create the `.ssh` directory with `0700` and the file with `0600` first).

If the difference between deployment paths, build commands, and server steps is unfamiliar, our short primer on [what a deployment script does](https://www.deployhq.com/blog/what-is-a-deployment-script) is a good detour. If you've never used [DeployHQ](https://www.deployhq.com) for a VPS before, our walkthrough on [setting up Git-based deployment on a VPS](https://www.deployhq.com/blog/setting-up-git-based-deployment-on-a-virtual-private-server-vps) covers the foundational steps that apply to any project — Minecraft or otherwise.

## Step 5: Configure deployment hooks

This is where Git-based Minecraft management starts to feel like a real deployment pipeline rather than a glorified FTP push.

### Pre-deployment SSH command (stop the server cleanly)

In your [DeployHQ](https://www.deployhq.com) project's **SSH commands** section, add a **Before deployment** command:

```
sudo systemctl stop minecraft || true
```

The `|| true` keeps the deployment from failing on first run when the service doesn't exist yet.

### Build pipeline (download Paper)

If your repo doesn't ship `paper.jar`, add a build step that downloads the version your `paper-version.txt` pins to. Paper's downloads API exposes per-build URLs — replace `1.21.4` and `build` with your pinned values:

```
curl -o paper.jar -L "https://api.papermc.io/v2/projects/paper/versions/1.21.4/builds/<build>/downloads/paper-1.21.4-<build>.jar"
```

Pinning a specific build is deliberate — latest silently changing under you is how Minecraft servers crash mid-Friday-night.

### Post-deployment SSH command (start the server)

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

### The systemd unit (one-time setup on the VPS)

Modern Linux servers don't need `screen` or `tmux`. Create `/etc/systemd/system/minecraft.service` with:

```
[Unit]
Description=Minecraft Java Edition Server
After=network.target

[Service]
Type=simple
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft
ExecStart=/usr/bin/java -Xms4G -Xmx4G -jar paper.jar --nogui
Restart=on-failure
RestartSec=10
SuccessExitStatus=0 143
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
```

`Restart=on-failure` is the part `screen` can never give you — if the JVM crashes the server comes back up by itself. View logs with `journalctl -u minecraft -f`.

Adjust the `-Xms` / `-Xmx` values to match your VPS. The PaperMC docs explicitly recommend leaving 1-1.5 GB for the OS and Java overhead — a 4 GB VPS should set both flags to roughly 3 GB, not 4.

## Step 6: Run your first deployment

In [DeployHQ](https://www.deployhq.com), click **Deploy**. Watch the deployment log: it'll transfer your repo, run the build pipeline, execute the pre/post SSH hooks, and start the systemd service. SSH back in and check:

```
systemctl status minecraft
journalctl -u minecraft -n 50 --no-pager
```

You should see Paper's startup banner and an [Done] For help, typehelp"" message.

Connect from your Minecraft client (Multiplayer → Add Server → your VPS IP). Done.

## Production tuning (the parts other guides skip)

### Aikar's JVM flags

For Paper servers under any real load, the community-standard Aikar's flags tune the G1 garbage collector for the Minecraft tick loop. PaperMC publishes the canonical version at [docs.papermc.io/paper/aikars-flags](https://docs.papermc.io/paper/aikars-flags/). Replace the `ExecStart` line in your systemd unit with the full flag set from that page (it's long — quoted in their docs in full). Don't transcribe Aikar's flags from random forum posts; the canonical version evolves and PaperMC's copy is the one to trust.

### View distance and simulation distance

Memory-constrained VPSes choke on the default `view-distance=10` once a few players are online — each chunk loaded costs RAM. Edit `server.properties` and commit:

```
view-distance=8
simulation-distance=6
```

`view-distance` controls how far chunks are _sent_ to clients; `simulation-distance` controls how far entities and redstone are _ticked_. Lowering `simulation-distance` more aggressively than `view-distance` is the cheapest win — most players don't notice, and your TPS recovers significantly.

### Plugin and config updates via continuous deployment

This is the whole point of using [DeployHQ](https://www.deployhq.com) for a Minecraft server. Once your repo is wired up, the day-to-day looks like:

1. Drop a new plugin JAR into `plugins/`, or edit `server.properties`.
2. `git push`.
3. [DeployHQ](https://www.deployhq.com) stops the server, transfers files, runs your build step, and restarts.
4. If the new plugin crashes the server, [one-click rollback](https://www.deployhq.com/features/one-click-rollback) reverts to the previous known-good state — no scrambling through FTP at midnight.

If you run separate creative and survival worlds (or production and a staging test new plugins here world), our guide on [managing multiple environments with DeployHQ](https://www.deployhq.com/blog/managing-multiple-environments-with-deployhq-dev-staging-and-production) shows the pattern.

### World backups (3-2-1, game-server edition)

The 3-2-1 rule from data engineering (3 copies, 2 different media, 1 off-site) maps cleanly to Minecraft. Your world is split across three directories Paper creates next to the JAR:

- `world/` — overworld
- `world_nether/` — the Nether
- `world_the_end/` — the End

Back up all three together — restoring only the overworld will scramble linked portals. A nightly cron that pauses with `screen -S minecraft -X stuff "save-off\n"` (or `mc-send-to-console save-off` via RCON), tar-gzips the three directories, then resumes with `save-on` will get you most of the way there. For the off-site copy, push the tarball to S3, B2, or a second VPS.

### Stopping the server cleanly during deployments

Slamming a `kill` into the JVM mid-tick can corrupt a chunk. The systemd unit above already handles `SIGTERM` correctly because Paper traps it and runs a save before exit — which is why we used `SuccessExitStatus=0 143`. Combined with the right Before deployment command, this gives you [zero downtime deployments](https://www.deployhq.com/features/zero-downtime-deployments) only for the parts that don't require restart (config-only changes), and clean restarts for the parts that do.

### SSH and Agents

If you'd rather skip configuring DeployHQ's SSH hooks by hand and [deploy from your terminal](https://www.deployhq.com/agents) instead, [DeployHQ](https://www.deployhq.com) Agents wrap the same workflow with a CLI that fits in any shell pipeline — useful when you want to wire Minecraft restarts into existing infra scripts.

## Wrapping up

Self-hosting a Minecraft server doesn't have to mean SSHing into the VPS at 11 PM to fix something. With your `server.properties`, plugins, and configs in Git, [DeployHQ](https://www.deployhq.com) handling transfer + restart, and systemd keeping the JVM alive between deployments, day-two operations stop being scary.

[Sign up for DeployHQ](https://www.deployhq.com/signup) and start treating your game server like a real production system.

* * *

Questions or stuck on a step? Email **[support@deployhq.com](mailto:support@deployhq.com)** or hit us up on [X (@deployhq)](https://x.com/deployhq).

