Add Eden Smash Ultimate VPS room deployment scripts.
Provides install/update systemd workflow for git-based deploys to Ubuntu VPS. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Secrets — never commit
|
||||||
|
.env
|
||||||
|
*.token
|
||||||
|
token
|
||||||
|
|
||||||
|
# Runtime / local state
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
banlist.txt.bak
|
||||||
|
|
||||||
|
# Downloaded binary (fetched by install.sh)
|
||||||
|
bin/eden-room
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# eden-room
|
||||||
|
|
||||||
|
Deploy a dedicated [Eden](https://eden-emu.dev/) multiplayer lobby on an Ubuntu VPS. Designed for git-based deploys (`git clone` / `git pull`).
|
||||||
|
|
||||||
|
Default game: **Super Smash Bros. Ultimate** (`01006A800016E000`).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Ubuntu VPS with a public IP
|
||||||
|
- Port **24872** open (TCP + UDP) in cloud firewall and UFW
|
||||||
|
- Eden token from your PC (`~/.config/eden/qt-config.ini` → `eden_token`)
|
||||||
|
- Optional: DNS A record (grey cloud / DNS-only in Cloudflare) pointing at the VPS
|
||||||
|
|
||||||
|
> Cloudflare **proxied** (orange cloud) records do **not** work for game traffic. Use DNS-only.
|
||||||
|
|
||||||
|
## Quick start (VPS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt install -y git curl
|
||||||
|
|
||||||
|
sudo git clone https://your-gitea.example.com/you/eden-room.git /opt/eden-room
|
||||||
|
cd /opt/eden-room
|
||||||
|
|
||||||
|
cp env.example .env
|
||||||
|
chmod 600 .env
|
||||||
|
nano .env # set EDEN_TOKEN, ROOM_NAME, etc.
|
||||||
|
|
||||||
|
sudo ./scripts/install.sh
|
||||||
|
sudo systemctl start eden-room
|
||||||
|
sudo journalctl -u eden-room -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deploy updates
|
||||||
|
|
||||||
|
On the VPS after pushing changes to Gitea:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/eden-room
|
||||||
|
sudo ./scripts/update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Re-download the `eden-room` binary when Eden releases a new version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# bump EDEN_RELEASE_VERSION in .env first, then:
|
||||||
|
sudo UPDATE_BINARY=1 ./scripts/update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration (`.env`)
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `EDEN_TOKEN` | From Eden config on your PC (required for public listing) |
|
||||||
|
| `ROOM_NAME` | 4–20 characters, shown in public lobby browser |
|
||||||
|
| `ROOM_DESCRIPTION` | Optional lobby description |
|
||||||
|
| `PREFERRED_GAME` | Display name for the lobby |
|
||||||
|
| `PREFERRED_GAME_ID` | Hex title ID (`01006A800016E000` for Smash Ultimate) |
|
||||||
|
| `PORT` | Room port (default `24872`) |
|
||||||
|
| `MAX_MEMBERS` | 2–16 players |
|
||||||
|
| `PASSWORD` | Optional room password |
|
||||||
|
| `WEB_API_URL` | Metaserver URL (default `https://api.ynet-fun.xyz`) |
|
||||||
|
| `EDEN_RELEASE_VERSION` | Eden release tag for binary download |
|
||||||
|
| `EDEN_ROOM_ARCH` | `x86_64-unknown-linux-musl` or `aarch64-unknown-linux-musl` |
|
||||||
|
|
||||||
|
## How players connect
|
||||||
|
|
||||||
|
**Public lobby:** Eden → Multiplayer → Browse Public Game Lobby
|
||||||
|
|
||||||
|
**Direct connect:** Eden → Multiplayer → Direct Connect
|
||||||
|
|
||||||
|
- Server: your domain or VPS IP
|
||||||
|
- Port: `24872` (or whatever you set in `.env`)
|
||||||
|
|
||||||
|
In-game, use **local wireless / LDN** — not Nintendo Online.
|
||||||
|
|
||||||
|
## Verify public listing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s https://api.ynet-fun.xyz/lobby | jq '.rooms[] | select(.name == "YOUR_ROOM_NAME")'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Service won't start**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo journalctl -u eden-room -n 50 --no-pager
|
||||||
|
cat /opt/eden-room/logs/eden-room.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**Public listing fails but room works**
|
||||||
|
|
||||||
|
Some VPS hosts hit JWT registration errors. Players can still Direct Connect. If the lobby browser doesn't load, add to `/etc/hosts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
28.165.181.135 api.ynet-fun.xyz
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check port is listening**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ss -tulnp | grep 24872
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
|
|
||||||
|
```
|
||||||
|
eden-room/
|
||||||
|
├── env.example # copy to .env (gitignored)
|
||||||
|
├── banlist.txt # room ban list (persisted)
|
||||||
|
├── scripts/
|
||||||
|
│ ├── install.sh # first-time VPS setup
|
||||||
|
│ ├── update.sh # git pull + restart
|
||||||
|
│ └── start-room.sh # invoked by systemd
|
||||||
|
├── systemd/
|
||||||
|
│ └── eden-room.service # reference unit file
|
||||||
|
└── bin/
|
||||||
|
└── eden-room # downloaded by install.sh (gitignored)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Push to Gitea
|
||||||
|
|
||||||
|
On your dev machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd eden-room
|
||||||
|
git remote add origin https://your-gitea.example.com/you/eden-room.git
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Never commit `.env` — it contains your Eden token.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
YuzuRoom-BanList-1
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
# Copy this file to .env and fill in your values:
|
||||||
|
# cp env.example .env && chmod 600 .env && nano .env
|
||||||
|
|
||||||
|
# Required for public lobby listing (from ~/.config/eden/qt-config.ini on your PC)
|
||||||
|
EDEN_TOKEN=
|
||||||
|
|
||||||
|
# Room settings (room name must be 4–20 characters)
|
||||||
|
ROOM_NAME=SmashLobby
|
||||||
|
ROOM_DESCRIPTION=Super Smash Bros Ultimate public lobby
|
||||||
|
PREFERRED_GAME=Super Smash Bros. Ultimate
|
||||||
|
PREFERRED_GAME_ID=01006A800016E000
|
||||||
|
|
||||||
|
# Network
|
||||||
|
PORT=24872
|
||||||
|
MAX_MEMBERS=8
|
||||||
|
BIND_ADDRESS=0.0.0.0
|
||||||
|
# Leave empty for no password
|
||||||
|
PASSWORD=
|
||||||
|
|
||||||
|
# Metaserver (public listing)
|
||||||
|
WEB_API_URL=https://api.ynet-fun.xyz
|
||||||
|
|
||||||
|
# eden-room binary download (change when updating Eden)
|
||||||
|
EDEN_RELEASE_VERSION=v0.2.0-rc2
|
||||||
|
EDEN_ROOM_ARCH=x86_64-unknown-linux-musl
|
||||||
|
# EDEN_ROOM_ARCH=aarch64-unknown-linux-musl # use on ARM VPS
|
||||||
Executable
+151
@@ -0,0 +1,151 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${REPO_DIR}/.env"
|
||||||
|
ENV_EXAMPLE="${REPO_DIR}/env.example"
|
||||||
|
BINARY_DIR="${REPO_DIR}/bin"
|
||||||
|
BINARY="${BINARY_DIR}/eden-room"
|
||||||
|
SERVICE_NAME="eden-room"
|
||||||
|
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
EDEN_USER="eden"
|
||||||
|
EDEN_GROUP="eden"
|
||||||
|
|
||||||
|
BASE_URL="https://git.eden-emu.dev/eden-emu/eden/releases/download"
|
||||||
|
|
||||||
|
require_root() {
|
||||||
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
|
echo "Run as root: sudo $0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
load_env() {
|
||||||
|
if [[ -f "${ENV_FILE}" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "${ENV_FILE}"
|
||||||
|
elif [[ -f "${ENV_EXAMPLE}" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "${ENV_EXAMPLE}"
|
||||||
|
fi
|
||||||
|
: "${EDEN_RELEASE_VERSION:=v0.2.0-rc2}"
|
||||||
|
: "${EDEN_ROOM_ARCH:=x86_64-unknown-linux-musl}"
|
||||||
|
: "${PORT:=24872}"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_user() {
|
||||||
|
if ! id "${EDEN_USER}" &>/dev/null; then
|
||||||
|
useradd -r -s /usr/sbin/nologin -d "${REPO_DIR}" "${EDEN_USER}"
|
||||||
|
echo "Created system user: ${EDEN_USER}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_env() {
|
||||||
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||||
|
cp "${ENV_EXAMPLE}" "${ENV_FILE}"
|
||||||
|
chmod 600 "${ENV_FILE}"
|
||||||
|
echo "Created ${ENV_FILE} from env.example — edit it before starting the service."
|
||||||
|
else
|
||||||
|
echo "Using existing ${ENV_FILE}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
download_binary() {
|
||||||
|
mkdir -p "${BINARY_DIR}"
|
||||||
|
local url="${BASE_URL}/${EDEN_RELEASE_VERSION}/eden-room-${EDEN_ROOM_ARCH}"
|
||||||
|
echo "Downloading eden-room ${EDEN_RELEASE_VERSION} (${EDEN_ROOM_ARCH})..."
|
||||||
|
curl -fsSL "${url}" -o "${BINARY}.tmp"
|
||||||
|
chmod +x "${BINARY}.tmp"
|
||||||
|
mv "${BINARY}.tmp" "${BINARY}"
|
||||||
|
echo "Installed ${BINARY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_firewall() {
|
||||||
|
if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
|
||||||
|
ufw allow "${PORT}/tcp" comment "eden-room"
|
||||||
|
ufw allow "${PORT}/udp" comment "eden-room"
|
||||||
|
echo "UFW rules added for port ${PORT} (tcp/udp)"
|
||||||
|
else
|
||||||
|
echo "UFW not active — open port ${PORT}/tcp and ${PORT}/udp in your cloud firewall manually."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_systemd() {
|
||||||
|
cat > "${SERVICE_FILE}" <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Eden Multiplayer Room (${SERVICE_NAME})
|
||||||
|
Documentation=https://github.com/eden-emulator/mirror/blob/master/docs/user/Multiplayer.md
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=${EDEN_USER}
|
||||||
|
Group=${EDEN_GROUP}
|
||||||
|
WorkingDirectory=${REPO_DIR}
|
||||||
|
ExecStart=${REPO_DIR}/scripts/start-room.sh
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
# Hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=${REPO_DIR}
|
||||||
|
PrivateTmp=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable "${SERVICE_NAME}"
|
||||||
|
echo "Installed and enabled ${SERVICE_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fix_permissions() {
|
||||||
|
chown -R "${EDEN_USER}:${EDEN_GROUP}" "${REPO_DIR}"
|
||||||
|
chmod 700 "${REPO_DIR}/scripts/"*.sh
|
||||||
|
chmod 600 "${ENV_FILE}" 2>/dev/null || true
|
||||||
|
chmod +x "${BINARY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
metaserver_hosts_hint() {
|
||||||
|
if ! grep -q 'api.ynet-fun.xyz' /etc/hosts 2>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo "Tip: if public lobby registration fails, add to /etc/hosts:"
|
||||||
|
echo " 28.165.181.135 api.ynet-fun.xyz"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_only() {
|
||||||
|
require_root
|
||||||
|
load_env
|
||||||
|
download_binary
|
||||||
|
fix_permissions
|
||||||
|
echo "Binary updated at ${BINARY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if [[ "${1:-}" == "--binary-only" ]]; then
|
||||||
|
binary_only
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_root
|
||||||
|
load_env
|
||||||
|
create_user
|
||||||
|
setup_env
|
||||||
|
download_binary
|
||||||
|
setup_firewall
|
||||||
|
install_systemd
|
||||||
|
fix_permissions
|
||||||
|
metaserver_hosts_hint
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Install complete."
|
||||||
|
echo " 1. Edit ${ENV_FILE} (set EDEN_TOKEN and ROOM_NAME)"
|
||||||
|
echo " 2. sudo systemctl start ${SERVICE_NAME}"
|
||||||
|
echo " 3. sudo journalctl -u eden-room -f"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Executable
+55
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${REPO_DIR}/.env"
|
||||||
|
BINARY="${REPO_DIR}/bin/eden-room"
|
||||||
|
BANLIST="${REPO_DIR}/banlist.txt"
|
||||||
|
LOG_FILE="${REPO_DIR}/logs/eden-room.log"
|
||||||
|
|
||||||
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||||
|
echo "Missing ${ENV_FILE}. Copy env.example to .env and configure it." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "${ENV_FILE}"
|
||||||
|
|
||||||
|
: "${ROOM_NAME:?ROOM_NAME is required in .env}"
|
||||||
|
: "${PREFERRED_GAME:?PREFERRED_GAME is required in .env}"
|
||||||
|
: "${PREFERRED_GAME_ID:?PREFERRED_GAME_ID is required in .env}"
|
||||||
|
: "${PORT:=24872}"
|
||||||
|
: "${MAX_MEMBERS:=8}"
|
||||||
|
: "${BIND_ADDRESS:=0.0.0.0}"
|
||||||
|
: "${WEB_API_URL:=https://api.ynet-fun.xyz}"
|
||||||
|
|
||||||
|
if [[ ! -x "${BINARY}" ]]; then
|
||||||
|
echo "Missing ${BINARY}. Run scripts/install.sh first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${REPO_DIR}/logs"
|
||||||
|
|
||||||
|
ARGS=(
|
||||||
|
--room-name "${ROOM_NAME}"
|
||||||
|
--room-description "${ROOM_DESCRIPTION:-Smash Ultimate lobby}"
|
||||||
|
--preferred-game "${PREFERRED_GAME}"
|
||||||
|
--preferred-game-id "${PREFERRED_GAME_ID}"
|
||||||
|
--port "${PORT}"
|
||||||
|
--max-members "${MAX_MEMBERS}"
|
||||||
|
--bind-address "${BIND_ADDRESS}"
|
||||||
|
--ban-list-file "${BANLIST}"
|
||||||
|
--log-file "${LOG_FILE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ -n "${PASSWORD:-}" ]]; then
|
||||||
|
ARGS+=(--password "${PASSWORD}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${EDEN_TOKEN:-}" ]]; then
|
||||||
|
ARGS+=(--token "${EDEN_TOKEN}" --web-api-url "${WEB_API_URL}")
|
||||||
|
else
|
||||||
|
echo "Warning: EDEN_TOKEN is empty — hosting as unlisted/private room." >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "${BINARY}" "${ARGS[@]}"
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
SERVICE_NAME="eden-room"
|
||||||
|
UPDATE_BINARY="${UPDATE_BINARY:-0}"
|
||||||
|
|
||||||
|
require_root() {
|
||||||
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
|
echo "Run as root: sudo $0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_root
|
||||||
|
|
||||||
|
echo "Pulling latest config from git..."
|
||||||
|
git -C "${REPO_DIR}" pull --ff-only
|
||||||
|
|
||||||
|
if [[ "${UPDATE_BINARY}" == "1" ]]; then
|
||||||
|
echo "Re-downloading eden-room binary..."
|
||||||
|
"${REPO_DIR}/scripts/install.sh" --binary-only
|
||||||
|
else
|
||||||
|
chown -R eden:eden "${REPO_DIR}"
|
||||||
|
chmod 700 "${REPO_DIR}/scripts/"*.sh
|
||||||
|
chmod 600 "${REPO_DIR}/.env" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl restart "${SERVICE_NAME}"
|
||||||
|
echo "Updated and restarted ${SERVICE_NAME}."
|
||||||
|
systemctl status "${SERVICE_NAME}" --no-pager
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Reference unit file — install.sh writes /etc/systemd/system/eden-room.service
|
||||||
|
# with paths adjusted to your clone location (default: /opt/eden-room).
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Eden Multiplayer Room
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=eden
|
||||||
|
Group=eden
|
||||||
|
WorkingDirectory=/opt/eden-room
|
||||||
|
ExecStart=/opt/eden-room/scripts/start-room.sh
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=/opt/eden-room
|
||||||
|
PrivateTmp=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Reference in New Issue
Block a user