Minecraft Bedrock Server on Oracle Cloud (Always Free)
This guide provides instructions for setting up a Minecraft Bedrock server on Oracle Cloud's Always Free tier. It covers everything from creating a virtual machine (VM) on Oracle Cloud Infrastructure to configuring the server with Docker and managing the server using common commands. After finishing this guide, you'll be able to control your server with Admincraft!
Setup a VM on Oracle Cloud
- Create a new instance with those settings:
Placement
- Availability domain: AD-1
Image and shape
- Image: Canonical Ubuntu 22.04
- Image build: 2024.06.26-0 (or any newer one)
- Shape: VM.Standard.A1.Flex
- OCPU count: 2
- Network bandwidth (Gbps): 2
- Memory (GB): 12
Primary VNIC information
- Virtual cloud network -> Choose one or create for later editing
- Subnet -> Choose one or create for later editing
Add SSH keys
Generate a key pair for me -> Download and store safely!
Boot volume
- Use in-transit encryption
-
Once created, take a note of the server IP, you will need it to connect to your server.
-
In
Networking > Virtual cloud networks > your network > Subnet Details, selectSecurity List Detailsand pressAdd Ingress Rules:
Minecraft port
- Source CIDR: 0.0.0.0/0
- IP Protocol: UDP
- Destination Port Range: 19132
- Description: Minecraft port
Admincraft WebSocket port
NOTE: Only needed if you follow the self-signed SSL alternative. The recommended Tailscale setup reaches the WebSocket over a private network, so this port stays closed to the internet.
- Source CIDR: 0.0.0.0/0
- IP Protocol: TCP
- Destination Port Range: 8080
- Description: Admincraft WebSocket port
Setup the Minecraft server
- Login via MobaXterm or the tool of your choice by using the IP, SSH Keys and username (ubuntu if you choose an Ubuntu image).
- Once connected, execute those commands to open the Minecraft port:
sudo iptables -I INPUT 6 -m state --state NEW -p udp --dport 19132 -j ACCEPT
sudo netfilter-persistent save
NOTE: Only add the WebSocket port if you follow the self-signed SSL alternative:
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 8080 -j ACCEPT
-
Edit the docker-compose.yml file:
-
Change the
services.websocket.environment.SECRET_KEYvariable for a strong password you will use to control the server with Admincraft. Generate one withopenssl rand -hex 32and keep it out of any public repository: anyone holding it can run commands on your server. -
Change any other variables you like in
services.minecraft, like theLEVEL_NAMEorLEVEL_SEED, you can see a full list here. -
Make sure to edit the backups-config/config.yml file, the
worldssetting should match the one you have introduced in the settingLEVEL_NAMEin the docker-compose.yml. You can also change the backups frequency as you like. -
Upload the docker-compose.yml file, the
backups-configfolder and the update-server.sh script to the home folder of your server. - Run
sudo docker compose up -dto start your server for the first time. - You should now be able to connect to your server with Minecraft. To connect with Admincraft, continue with the next chapter.
NOTE: If you enabled the setting
ALLOW_LIST = truein the docker-compose.yml, you will need to whitelist the users you want to be able to connect with the commandwhitelist add username.
Choosing how to connect
The WebSocket gives full control of your server, so the connection always has to be encrypted by something: either the network it travels over, or TLS. Pick the option that fits you and follow its chapter below.
| Option | App on the client | Certificate to copy | Reachable from the internet |
|---|---|---|---|
| Tailscale (recommended) | Tailscale | no | no |
| Tailscale Funnel | none | no | yes |
| Self-signed SSL | none | yes, and again on every renewal | yes |
Each one maps to a Connection Security option in Admincraft's settings: Private network, Public certificate and Self-signed certificate.
NOTE: Running Admincraft in a browser narrows the choice. Self-signed certificates cannot be loaded at all, and if the app itself is served over HTTPS the browser blocks the unencrypted
Private networkoption as mixed content. Tailscale Funnel is the option that always works in a browser.
Connect Admincraft with Tailscale (recommended)
The WebSocket gives full control of your server, so it should never be exposed to the internet without protection. Tailscale puts your phone and your server on a private encrypted network, so the WebSocket port stays invisible to everyone else. It is free for personal use, needs no certificates and nothing ever expires.
- Install Tailscale on the server:
The command prints a login link. Open it and sign in.
NOTE: Sign up with a personal account (Google, GitHub, Microsoft). Custom email domains are treated as business use and do not get the free Personal plan.
- Note the server's Tailscale address:
-
Install the Tailscale app on your phone or PC and sign in with the same account.
-
Open Admincraft and connect:
-
IP / Hostname: the Tailscale address from step 2 (for example
100.101.102.103) - Port:
8080 - Secret key: the
SECRET_KEYfrom your docker-compose.yml - Connection security:
Private network
Admincraft should connect automatically and display the server logs. If there is any issue you will be prompted with an error pop-up.
Traffic is encrypted by Tailscale itself, so no certificate is needed. Keep port 8080 closed in your cloud firewall: only your own devices can reach it.
NOTE: Tailscale must be connected on the device running Admincraft. To let someone else administer the server, invite them to your Tailscale network instead of sharing the secret key.
Alternative: Tailscale Funnel (no app on the client)
Use this if you do not want to install Tailscale on every device running Admincraft. Only the server runs Tailscale; Funnel publishes the WebSocket on a public hostname with a certificate that renews itself, so there is still nothing to copy into the app.
Follow step 1 of the Tailscale setup above to install Tailscale on the server, then:
- Funnel terminates TLS for you, so the WebSocket should speak plain HTTP and listen only on the server itself. In the docker-compose.yml, set
USE_SSL: "false"and bind the port to loopback:
Apply it with sudo docker compose up -d. Binding to 127.0.0.1 is what keeps the socket private: Funnel reaches it from the server itself, nothing else can, and the cloud firewall becomes a second layer instead of the only one.
- Publish it:
NOTE: The first run blocks and prints
Funnel is not enabled on your tailnetwith a link. Open the link to enable Funnel, then run the command again. It does not continue on its own.
status reports your public hostname, in the form machine-name.tailnet-name.ts.net. Tailscale requests and renews the certificate automatically; the public side always uses port 443.
-
Connect Admincraft with:
-
IP / Hostname: the
ts.nethostname reported bytailscale funnel status - Port:
443 - Secret key: the
SECRET_KEYfrom your docker-compose.yml - Connection security:
Public certificate
NOTE: With the port bound to
127.0.0.1, the private Tailscale option above stops working, because devices on your tailnet can no longer reach it either. To use both, add a second mapping for the server's Tailscale address, for example- 100.101.102.103:8080:8080.WARNING: Funnel makes the WebSocket reachable from the whole internet, so the
SECRET_KEYbecomes the only thing protecting your server. Use a long random value and never commit it anywhere public. The private Tailscale setup above is safer.
Alternative: public access with self-signed SSL
Use this if you cannot install Tailscale on the device running Admincraft, or you need the WebSocket reachable from anywhere. It exposes port 8080 to the internet, so SSL is mandatory and the certificate has to be copied into Admincraft by hand.
Open port 8080 first (see Setup a VM on Oracle Cloud and step 2 of the server setup), then:
- Edit the certs/makecerts.sh by changing the variable
COMMON_NAME=YOUR_IP_HEREfor your server IP. - Upload the
certsfolder to the home folder of your server. - Make the script executable, format it for Linux, and run it to generate the certificates:
-
In the docker-compose.yml file, set
services.websocket.environment.USE_SSLto"true"and uncomment the./certsvolume mount. -
The
server.crtcertificate can be downloaded directly from the server to avoid Man-in-the-Middle attacks. If using a safe network, it can download it from https://IP:8080/getcert ignoring the security warnings. -
Open Admincraft and connect:
-
IP / Hostname: your server IP
- Port:
8080 - Secret key: the
SECRET_KEYfrom your docker-compose.yml - Connection security:
Self-signed certificate, then loadserver.crt
WARNING: Do not expose port
8080withPrivate networkselected. That mode sends your secret key and every command in clear text, and is only safe inside Tailscale, a VPN or a LAN.NOTE:
makecerts.shissues certificates valid for one year. Once it expires Admincraft will refuse to connect, and you have to run the script again and reloadserver.crt. The Tailscale options avoid this entirely.
Keeping the Server Updated
There are two separate things that need updating, and confusing them will leave your server stranded on an old version:
| What | How it updates |
|---|---|
| Bedrock server binary | Re-checked against Mojang's API on every container start, so a restart is enough. |
Container images (itzg/minecraft-bedrock-server, etc.) |
Only ever update when you explicitly run docker compose pull. |
Restarting alone handles the first but never the second. That matters because the version lookup lives inside the image: when Mojang changed their download page, older images failed with Unable to find an element with attribute matcher data-platform=serverBedrockLinux and silently kept running the last version they had. Newer images query a JSON API instead. If you only ever restart, you never receive that fix.
Manual update
If the pull fails with unauthorized: your account must log in with a Personal Access Token (PAT), a stale Docker Hub credential is stored for root. Clear it and retry:
Automatic nightly update
update-server.sh warns any online players, pulls new images, recreates the stack, prunes old images, and then verifies that a fresh backup actually landed before reporting success. Upload it to your home folder and install it:
Add this line to run it every night at 04:00:
NOTE: Cron follows the host's system clock. Check yours with
timedatectlbefore assuming a time zone.
Review runs with sudo tail -n 40 /var/log/minecraft-update.log.
Because VERSION defaults to LATEST, this means Mojang decides when your world converts to a new format, and Bedrock world upgrades are one-way. The nightly backup taken immediately after each update is your safety net. If you would rather approve each version bump yourself, pin VERSION: 1.26.43.1 (or whichever build you want) in the docker-compose.yml — you will still receive image fixes automatically without surprise world conversions.
Backups
Backups are handled by the backup container and configured in backups-config/config.yml. With runInitialBackup: true, a snapshot is taken on every service start in addition to the regular interval, so each nightly update leaves a restore point behind.
Check that backups are working:
Force one immediately:
NOTE: The container's healthcheck only covers its HTTP endpoint, so it can report
healthywhile no backups are being written. Trust the timestamps in~/backupsover the container status.
Common Server Commands
See all available commands here.
Run containers in the background (detached mode)
sudo docker compose up -d
Run containers in the foreground (for debugging)
sudo docker compose up
Stop containers
sudo docker compose stop
Restart containers
sudo docker compose restart
Remove all containers (the world will not be lost)
sudo docker compose rm -fsv
Remove all containers and volumes (the world will not be lost)
sudo docker rm -vf $(sudo docker ps -aq)
Remove all images (the world will not be lost)
sudo docker rmi -f $(sudo docker images -aq)
Remove all server data (the world WILL BE LOST!)
sudo rm -rf minecraft/
See logs interactively
sudo docker compose logs -f
See X log lines
sudo docker compose logs --tail 2
See logs interactively for a specific container
Send minecraft commands from outside the container (this is exactly how Admincraft controls the server)
sudo docker exec minecraft send-command <commandname>
sudo docker exec minecraft send-command whitelist add moaibeats
sudo docker exec minecraft send-command give moaibeats coal 20
sudo docker exec minecraft send-command time set 2000
Go into the container's command line (do not exit with CTRL-C! Use CTRL-P CTRL-Q)
sudo docker attach minecraft
Some examples
Go into the container's shell
sudo docker exec -ti minecraft /bin/bash
Architecture
The system consists of three main containers running in a Docker environment:
-
Minecraft Bedrock Server (
minecraft): -
Exposes the Minecraft server to the internet through port
19132/udp. - Accepts incoming connections from Minecraft clients.
- SSH access is enabled for the backup process, and the Minecraft server data is stored in a mounted volume.
-
Server configuration is set in the
docker-compose.ymlfile, allowing for customization of settings such as world seed, level name, and gameplay modes. -
Admincraft WebSocket Server (
websocket): -
Listens on port
8080, allowing control of the Minecraft server using Admincraft. In the recommended setup this port is reached over Tailscale and stays closed to the internet; the self-signed SSL alternative exposes it publicly instead. - The WebSocket server authenticates incoming connections using JWT (JSON Web Tokens), with the
SECRET_KEYstored in environment variables. - Once authenticated, users can issue Minecraft server commands, which are executed in real time within the Minecraft container.
-
Additionally, certain Docker-level commands (like restarting the server) can be executed through the WebSocket interface, but these are restricted to predefined key commands for security reasons.
-
Backup Server (
backup): - Connects to the Minecraft server every few hours via SSH to back up world data.
- The backup server uses a mounted volume to store backup files in a dedicated folder, ensuring Minecraft server data can be restored if needed.
- Backup configurations, including the backup schedule and the target Minecraft server, are stored in the
backups-config/config.ymlfile.
Credits and sources
- https://github.com/itzg/docker-minecraft-bedrock-server
- https://github.com/Kaiede/Bedrockifier
- https://docs.oracle.com/en-us/iaas/developer-tutorials/tutorials/apache-on-ubuntu/01oci-ubuntu-apache-summary.htm