HyOS
Deployment

TrueNAS Deployment

Deploy HyOS on TrueNAS SCALE using Docker Compose or the native app catalog

Two deployment methods are available for TrueNAS SCALE: a Custom App using a compose file (recommended) or the Native TrueNAS App from the catalog.

Table of Contents


Custom App (Compose)

Deploy HyOS by pasting a compose file directly into TrueNAS. This gives you full control over every setting.

Requirements

  • TrueNAS SCALE 24.10.2.2 or later
  • 8 GB RAM minimum (12 GB+ recommended)
  • 4+ CPU cores
  • x86_64/amd64 architecture

Step 1 — Create a Dataset

  1. Open the TrueNAS web UI and go to Datasets
  2. Select your pool (e.g. tank) and click Add Dataset
  3. Name it hytale (the full path will be something like tank/apps/hytale)
  4. Click Save
  5. Select the new hytale dataset and click Edit under Permissions
  6. Set User to 568 and Group to 568
  7. Check Apply User and Apply Group
  8. Check Apply permissions recursively
  9. Click Save

TrueNAS SCALE uses UID/GID 568 as the default for app containers. The Hytale server container drops privileges to this user, so your dataset ownership must match.

Step 2 — Create the Custom App

  1. Go to Apps in the sidebar
  2. Click Discover Apps in the top-right
  3. Click Custom App
  4. Select Install via YAML
  5. Paste the full compose file below into the editor
  6. Before deploying, update these two values:
    • Volume path — replace /mnt/tank/apps/hytale with the path to your dataset (on both services)
    • API password — replace changeme123 with a secure password (on the x-api-config line)
  7. Click Save

Full Compose File

# =============================================================================
# HyOS - Hytale Server + Manager - TrueNAS SCALE Custom App
# =============================================================================
# ACCESS:
# - Game Server: UDP port 30380
# - Management UI: http://your-truenas-ip:30382
#
# PORT CONVENTION:
# Host ports use the 30xxx range to avoid conflicts with other TrueNAS apps.
# The Hytale server default is UDP 5520 — if you are not running other apps
# that conflict, you can change the host ports back (e.g., "5520:5520/udp").
# Internal container ports (5520, 30381, 3000) match the host ports.
# =============================================================================

# ---------------------------------------------------------------------------
# Shared configuration - SET YOUR PASSWORD HERE
# ---------------------------------------------------------------------------
x-api-config: &api-config
  API_CLIENT_SECRET: changeme123
  API_CLIENT_ID: hyos-manager

services:
  hyos-server:
    image: ghcr.io/editmysave/hyos/server:latest
    pull_policy: always
    container_name: hyos-server
    user: "568:568"
    restart: unless-stopped
    stdin_open: true
    tty: true

    environment:
      <<: *api-config

      # --- User Settings ---
      PUID: 568
      PGID: 568
      UMASK: "002"
      TZ: UTC

      # --- JVM Memory ---
      JAVA_XMS: 1G
      JAVA_XMX: 3G
      USE_ZGC: "false"
      G1_MAX_PAUSE: "200"

      # --- Server Settings ---
      SERVER_PORT: "5520"
      PATCHLINE: release
      ENABLE_AOT: "true"
      SKIP_CONFIG_GENERATION: "false"
      SERVER_NAME: "Hytale Server"
      SERVER_MOTD: ""
      SERVER_PASSWORD: ""
      MAX_PLAYERS: "100"
      MAX_VIEW_RADIUS: "32"
      DEFAULT_WORLD: default
      DEFAULT_GAMEMODE: Adventure
      LOCAL_COMPRESSION: "false"
      DISPLAY_TMP_TAGS: "false"
      PLAYER_STORAGE_TYPE: Hytale

      # --- Auto-Update ---
      AUTO_UPDATE: "false"
      VERSION_CHECK_ENABLED: "true"
      VERSION_CHECK_INTERVAL: "3600"

      # --- Whitelist ---
      WHITELIST_ENABLED: "false"

      # --- Hytale Options ---
      HYTALE_ACCEPT_EARLY_PLUGINS: "false"
      HYTALE_ALLOW_OP: "false"
      HYTALE_BACKUP: "true"
      HYTALE_BACKUP_FREQUENCY: "30"
      HYTALE_DISABLE_SENTRY: "false"

      # --- REST API Plugin ---
      API_ENABLED: "true"
      API_PORT: "30381"
      API_WEBSOCKET_ENABLED: "true"
      API_WEBSOCKET_STATUS_INTERVAL: "1"
      API_REGENERATE_CONFIG: "true"

      # --- Debug ---
      DEBUG: "false"
      NO_COLOR: "false"

    ports:
      - "30380:5520/udp"    # Game traffic (QUIC)
      - "30381:30381/tcp"    # REST API

    # UPDATE THIS PATH to your dataset
    volumes:
      - /mnt/tank/apps/hytale:/data:rw

    stop_grace_period: 30s

    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "3"

    security_opt:
      - no-new-privileges:true

  # =========================================================================
  # Server Manager (Web UI)
  # =========================================================================
  hyos-manager:
    image: ghcr.io/editmysave/hyos/manager:latest
    pull_policy: always
    container_name: hyos-manager
    user: "568:568"
    group_add:
      - "0"
    restart: unless-stopped

    environment:
      <<: *api-config
      REST_API_CLIENT_SECRET: changeme123
      REST_API_CLIENT_ID: hyos-manager
      ADAPTER_TYPE: rest
      HYTALE_CONTAINER_NAME: hyos-server
      HYTALE_STATE_DIR: /data/.state
      HYTALE_SERVER_HOST: hyos-server
      HYTALE_SERVER_PORT: "30381"
      NODE_ENV: production
      COOKIE_SECURE: "false"

    ports:
      - "30382:3000"        # Web UI

    # UPDATE THIS PATH to your dataset (must match the server)
    volumes:
      - /mnt/tank/apps/hytale:/data:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro

    depends_on:
      - hyos-server

    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

    security_opt:
      - no-new-privileges:true

networks:
  default:
    driver: bridge

Important: The REST_API_CLIENT_SECRET value on the manager must match the API_CLIENT_SECRET on the server. If you change the password in x-api-config, update the manager's REST_API_CLIENT_SECRET to match.

Step 3 — Complete OAuth Authentication

  1. Go to Apps and click on the hyos-server app
  2. Open the container Logs (or click the shell/logs icon)
  3. Look for the OAuth device code prompt — it will display a URL and a code
  4. Open the URL in your browser and enter the code
  5. Complete authentication within 15 minutes
  6. The server will download game files and start automatically

Step 4 — Access the Manager UI

Once both containers are running, open your browser to:

http://your-truenas-ip:30382

The Manager UI provides server control, console access, and configuration management.

Common Settings to Customize

SettingEnvironment VariableDefaultNotes
Server nameSERVER_NAMEHytale ServerShown in the server list
Max playersMAX_PLAYERS100Concurrent player limit
GamemodeDEFAULT_GAMEMODEAdventureAdventure, Creative, or Survival
Heap memoryJAVA_XMX3GSet to 50-75% of total system RAM
TimezoneTZUTCe.g. America/New_York
Auto-updateAUTO_UPDATEfalseCheck for updates at startup
Game portHost port mapping30380Change the left side of 30380:5520/udp

Tips

  • Set container memory limits at least 2 GB higher than JAVA_XMX to account for JVM overhead. Example: JAVA_XMX=3G needs ~4 GB container memory.
  • The Manager container needs Docker socket access (/var/run/docker.sock) to start/stop the server. It's mounted read-only.
  • Both containers log to json-file with size limits to prevent filling your ZFS pool.

Native TrueNAS App

The native app integrates with the TrueNAS SCALE app catalog and provides a guided UI for all configuration options — no compose file editing required.

How It Works

The app is defined by the following files in the truenas-app/ directory:

FilePurpose
app.yamlApp metadata: name, version, capabilities, icon, requirements
questions.yamlDefines the TrueNAS UI configuration form (all settings groups)
ix_values.yamlDefault values and container image references
templates/docker-compose.yamlJinja2 template that generates the actual Docker Compose from user inputs
templates/test_values/basic-values.yamlTest fixture for CI validation of the Jinja2 template
item.yamlCatalog item metadata (train, categories)
icon.pngApp icon displayed in the TrueNAS catalog

Installation

  1. Go to Apps in the sidebar
  2. Click Discover Apps
  3. Search for HyOS in the catalog
  4. Click Install and walk through the configuration groups

Configuration Groups

The TrueNAS UI presents settings in organized groups:

1. Hytale Server Configuration

SettingDefaultDescription
TZ TimezoneEtc/UTCTimezone for logs and scheduled tasks (e.g., America/New_York)
Server NameHytale ServerDisplay name in the server list
Server MOTDMessage of the day
Server PasswordLeave empty for a public server
Max Players100Maximum concurrent players
Default GamemodeAdventureAdventure, Creative, or Survival
PatchlinereleaseVersion channel: release, staging, nightly

2. JVM & Memory

SettingDefaultDescription
Initial Heap (XMS)1GStarting heap size
Max Heap (XMX)3GMaximum heap size — set to 50–75% of allocated RAM
Use ZGCfalseZGC for low-latency (needs more RAM)
G1 Max Pause200G1GC max pause time in ms (when not using ZGC)

3. Auto-Update

SettingDefaultDescription
Enable Auto-UpdatefalseCheck for updates at container startup
Check Interval3600Seconds between checks (background mode)
Update TimeSpecific time to check (HH:MM format)
Auto-RestarttrueRestart server after applying an update
Backup Before UpdatetrueCreate a backup before applying updates

4. API Configuration

SettingDefaultDescription
Enable REST APItrueRequired for the Manager UI
Client SecretRequired — password for API authentication
Client IDhyos-managerClient identifier
Enable WebSockettrueReal-time updates to the Manager

5. Manager (Web UI)

SettingDefaultDescription
Enable ManagertrueDeploy the HyOS Manager web UI alongside the server

When enabled, a second container (hyos-manager) is deployed with access to shared state files and the Docker socket.

6. Advanced Configuration

Toggle Show Advanced Options to reveal:

  • Auth Modeauthenticated or offline
  • AOT Cache — Ahead-of-Time compilation for faster startup
  • Disable Sentry — Turn off error reporting
  • Debug Logging — Verbose entrypoint script output
  • Hytale Backups — In-game backup frequency and retention
  • Whitelist — Enable and configure player whitelist
  • Skip Broken Mods — Auto-quarantine failing mods
  • Max View Radius — Chunk view distance
  • Additional Environment Variables — Pass-through for any HYTALE_* option

7. User and Group Configuration

SettingDefaultDescription
User ID568Must match dataset ownership
Group ID568Must match dataset ownership

Minimum value is 568. TrueNAS uses UID/GID 568 by default for app containers.

8. Network Configuration

PortProtocolDefaultDescription
Game PortUDP30380Hytale QUIC game traffic
API PortTCP30381REST API for the Manager
Manager PortTCP30382Web UI

Each port supports bind modes: published (accessible from host), exposed (container-only), or none.

9. Storage Configuration

Primary data storage — choose one:

TypeDescription
ixVolume (default)TrueNAS-managed volume with automatic dataset creation
Host PathMap to an existing ZFS dataset (e.g., /mnt/tank/apps/hytale)

Additional storage — mount extra paths using host paths, ixVolume, SMB/CIFS, or NFS.

10. Labels Configuration

Apply custom Docker labels to containers. Each label has a key, value, and target container selection (hytale-server and/or hytale-manager).

11. Resources

SettingDefaultDescription
CPUs4CPU core limit
Memory (MB)4096Memory limit — should be at least 2 GB more than JAVA_XMX

Post-Installation

  1. Go to Apps and click on the HyOS app
  2. Check container logs for the OAuth authentication prompt
  3. Complete the device code flow within 15 minutes
  4. The server will download game files and start automatically
  5. Access the Manager UI at http://your-truenas-ip:30382

TrueNAS-Specific Considerations

Why UID 568?

TrueNAS SCALE uses UID/GID 568 as the default for app containers. The Hytale server container uses su-exec to drop privileges from root to this user. All files written to /data are owned by 568:568.

If you use a different UID/GID:

  • Set PUID and PGID environment variables to match
  • Set user: in the compose file to match
  • Ensure the dataset is owned by the same UID/GID

ZFS Dataset Setup

# Create a dedicated dataset
zfs create tank/apps/hytale

# Set ownership
chown -R 568:568 /mnt/tank/apps/hytale

# Optional: Set ACLs if using ACL-enabled datasets
# TrueNAS UI: Datasets > Edit Permissions > Set UID 568, GID 568

For ACL-enabled datasets, ensure the hytale user (UID 568) has full control.

Host Path vs ixVolume Storage

FeatureHost PathixVolume
Dataset controlFull — you create and manage the datasetTrueNAS auto-creates
Backup visibilityDirect access at known pathManaged by TrueNAS
PortabilityEasy to migrateTied to TrueNAS app lifecycle
Recommended forProduction, manual managementQuick setup, testing

Docker Socket Access

The Manager container needs read-only access to the Docker socket for container control (start/stop/restart):

volumes:
  - /var/run/docker.sock:/var/run/docker.sock:ro
group_add:
  - "0"  # Root group for socket access

The socket is mounted read-only. The container runs as UID 568 but is added to GID 0 (root group) to read the socket (which has 0:0 ownership with 660 permissions on TrueNAS).

Resource Limits

Set container memory limits at least 2 GB higher than JAVA_XMX to account for:

  • JVM metaspace and off-heap memory
  • Operating system overhead
  • The entrypoint scripts and helper processes

Example: JAVA_XMX=3G → container memory limit = 4096 MB (4 GB).

Log Management

Both containers use the json-file logging driver with size limits:

logging:
  driver: json-file
  options:
    max-size: "50m"   # Server (larger due to game logs)
    max-file: "3"
logging:
  driver: json-file
  options:
    max-size: "10m"   # Manager
    max-file: "3"

This prevents log files from consuming unlimited disk space on the ZFS pool.

On this page