# Apollo Apollo is a self-hosted desktop streaming host designed for the Artemis (Moonlight Noir) client. It provides low-latency cloud gaming server capabilities with hardware-accelerated encoding support for AMD, Intel, and NVIDIA GPUs. Apollo distinguishes itself with built-in virtual display functionality including HDR support that automatically matches client resolution and framerate. The platform features a comprehensive permission system for client management, clipboard synchronization, and customizable commands for client connection/disconnection events. The project offers a web-based UI for configuration and client pairing accessible via HTTPS. Apollo supports multiple platforms including Windows, Linux, and macOS, with virtual display functionality currently available on Windows. Key differentiators from similar solutions include native client resolution matching, per-client display mode persistence, and granular permission controls that allow administrators to restrict specific inputs or actions on a per-device basis. ## REST API Reference Apollo provides a RESTful API for managing applications, clients, and server configuration. All API endpoints require authentication using basic authentication with admin credentials or session cookies. ### GET /api/apps - List Applications Retrieves the list of configured applications available for streaming, along with the currently running app and host information. ```bash # Get list of all configured applications curl -k -X GET "https://localhost:47990/api/apps" \ -H "Cookie: auth=your_session_cookie" # Response example: { "apps": [ { "name": "Desktop", "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "image-path": "desktop.png", "cmd": "", "prep-cmd": [], "detached": [] }, { "name": "Steam Big Picture", "uuid": "b2c3d4e5-f6a7-8901-bcde-f23456789012", "image-path": "steam.png", "cmd": "", "detached": ["steam://open/bigpicture"] } ], "current_app": "", "host_uuid": "host-unique-identifier", "host_name": "MyGamingPC" } ``` ### POST /api/apps - Save Application Creates a new application or updates an existing one. To create a new application, omit the UUID field. To update, provide the existing UUID. ```bash # Create a new Steam game application curl -k -X POST "https://localhost:47990/api/apps" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{ "name": "Cyberpunk 2077", "output": "", "cmd": "", "exclude-global-prep-cmd": false, "elevated": false, "auto-detach": true, "wait-all": true, "exit-timeout": 5, "prep-cmd": [ { "do": "nvidia-settings -a CurrentMetaMode=\"HDMI-1: nvidia-auto-select\"", "undo": "nvidia-settings -a CurrentMetaMode=\"HDMI-1: 2560x1440+0+0\"", "elevated": false } ], "detached": ["steam://rungameid/1091500"], "image-path": "/path/to/cyberpunk.png" }' # Response: {"status": true} ``` ### POST /api/apps/close - Close Running Application Terminates the currently running application and ends the streaming session. ```bash # Close the current application curl -k -X POST "https://localhost:47990/api/apps/close" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{}' # Response: {"status": true} ``` ### DELETE /api/apps/{index} - Delete Application Removes an application from the configuration by its index in the apps array. ```bash # Delete the application at index 2 curl -k -X DELETE "https://localhost:47990/api/apps/2" \ -H "Cookie: auth=your_session_cookie" # Response: {"status": true} ``` ### POST /api/apps/reorder - Reorder Applications Changes the display order of applications in the client app list. ```bash # Reorder applications by UUID curl -k -X POST "https://localhost:47990/api/apps/reorder" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{ "order": [ "b2c3d4e5-f6a7-8901-bcde-f23456789012", "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ] }' # Response: {"status": true} ``` ### GET /api/clients/list - List Paired Clients Retrieves all clients that have been paired with the Apollo server, including their permissions and configuration. ```bash # Get list of paired clients curl -k -X GET "https://localhost:47990/api/clients/list" \ -H "Cookie: auth=your_session_cookie" # Response example: { "clients": [ { "uuid": "client-uuid-1234", "name": "Living Room TV", "permissions": { "list_apps": true, "view_streams": true, "launch_apps": true, "mouse_input": true, "keyboard_input": true, "controller_input": true, "clipboard_set": true, "clipboard_read": true, "server_command": true }, "display_mode_override": "3840x2160x59.94" } ] } ``` ### POST /api/clients/unpair - Unpair Client Removes a specific client's pairing with the server. ```bash # Unpair a specific client by UUID curl -k -X POST "https://localhost:47990/api/clients/unpair" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{"uuid": "client-uuid-1234"}' # Response: {"status": true} ``` ### POST /api/clients/unpair-all - Unpair All Clients Removes all client pairings from the server. ```bash # Unpair all clients curl -k -X POST "https://localhost:47990/api/clients/unpair-all" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{}' # Response: {"status": true} ``` ### GET /api/config - Get Server Configuration Retrieves the current server configuration settings. ```bash # Get current configuration curl -k -X GET "https://localhost:47990/api/config" \ -H "Cookie: auth=your_session_cookie" # Response example: { "sunshine_name": "MyGamingPC", "min_log_level": "info", "port": 47989, "encoder": "nvenc", "capture": "ddx", "adapter_name": "NVIDIA GeForce RTX 3080", "output_name": "", "audio_sink": "Speakers (High Definition Audio Device)", "virtual_sink": "Steam Streaming Speakers", "gamepad": "auto", "lan_encryption_mode": 0, "wan_encryption_mode": 1 } ``` ### POST /api/config - Save Server Configuration Updates the server configuration with new settings. ```bash # Update server configuration curl -k -X POST "https://localhost:47990/api/config" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{ "sunshine_name": "GamingRig", "min_log_level": "info", "encoder": "nvenc", "nvenc_preset": 1, "nvenc_twopass": "quarter_res", "hevc_mode": 3, "av1_mode": 0, "adapter_name": "NVIDIA GeForce RTX 3080", "audio_sink": "Speakers (High Definition Audio Device)", "virtual_sink": "Steam Streaming Speakers", "fec_percentage": 20, "qp": 28, "lan_encryption_mode": 0, "wan_encryption_mode": 1 }' # Response: {"status": true} ``` ### POST /api/pin - Submit Pairing PIN Submits a PIN code for client pairing when a Moonlight/Artemis client requests to pair. ```bash # Submit pairing PIN curl -k -X POST "https://localhost:47990/api/pin" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{"pin": "1234"}' # Response: {"status": true} ``` ### POST /api/password - Update Admin Password Changes the web UI admin password. ```bash # Update admin password curl -k -X POST "https://localhost:47990/api/password" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{ "currentUsername": "admin", "currentPassword": "oldpassword", "newUsername": "admin", "newPassword": "newsecurepassword", "confirmNewPassword": "newsecurepassword" }' # Response: {"status": true} ``` ### GET /api/logs - Get Server Logs Retrieves the server log contents for troubleshooting. ```bash # Get server logs curl -k -X GET "https://localhost:47990/api/logs" \ -H "Cookie: auth=your_session_cookie" # Response: { "logs": "[2024-01-15 10:30:00] Info: Starting Apollo...\n[2024-01-15 10:30:01] Info: Web UI available at https://localhost:47990\n..." } ``` ### POST /api/restart - Restart Server Restarts the Apollo server service. ```bash # Restart the server curl -k -X POST "https://localhost:47990/api/restart" \ -H "Content-Type: application/json" \ -H "Cookie: auth=your_session_cookie" \ -d '{}' # Response: {"status": true} ``` ### POST /api/covers/upload - Upload Application Cover Image Uploads a cover image for an application. ```bash # Upload cover image (multipart form data) curl -k -X POST "https://localhost:47990/api/covers/upload" \ -H "Cookie: auth=your_session_cookie" \ -F "cover=@/path/to/game-cover.png" # Response: { "status": true, "path": "/path/to/stored/cover.png" } ``` ## Configuration Options ### Basic Configuration File Apollo configuration is stored in a `.conf` file that can be specified at startup or uses the default location. ```bash # Start Apollo with custom config file sunshine ~/my_sunshine_config.conf # Default config locations by OS: # Linux/macOS: ~/.config/sunshine/sunshine.conf # Windows: %ProgramFiles%\Sunshine\config\sunshine.conf # Docker: /config/sunshine.conf ``` ### Encoder Configuration Configure hardware encoding settings for optimal streaming performance. ```ini # NVIDIA NVENC Configuration encoder = nvenc nvenc_preset = 1 nvenc_twopass = quarter_res nvenc_spatial_aq = disabled nvenc_vbv_increase = 0 nvenc_realtime_hags = enabled nvenc_latency_over_power = enabled nvenc_opengl_vulkan_on_dxgi = enabled # Intel QuickSync Configuration encoder = quicksync qsv_preset = medium qsv_coder = auto # AMD AMF Configuration encoder = amdvce amd_usage = ultralowlatency amd_rc = vbr_latency amd_quality = balanced amd_vbaq = enabled # Software Encoding (CPU) encoder = software sw_preset = superfast sw_tune = zerolatency min_threads = 2 ``` ### Audio Configuration Configure audio streaming with virtual sinks for muted host audio. ```ini # Audio configuration audio_sink = Speakers (High Definition Audio Device) virtual_sink = Steam Streaming Speakers stream_audio = enabled install_steam_audio_drivers = enabled # Linux PulseAudio example audio_sink = alsa_output.pci-0000_09_00.3.analog-stereo # macOS with BlackHole audio_sink = BlackHole 2ch ``` ### Display Configuration Configure display capture and virtual display settings. ```ini # Display settings adapter_name = NVIDIA GeForce RTX 3080 output_name = {device-id-guid} # Display device configuration (Windows) dd_configuration_option = ensure_only_display dd_resolution_option = auto dd_refresh_rate_option = auto dd_hdr_option = auto dd_config_revert_delay = 3000 # Virtual display isolation isolated_virtual_display_option = disabled # Mode remapping for specific resolutions dd_mode_remapping = { "mixed": [ { "requested_fps": "60", "final_refresh_rate": "119.95", "requested_resolution": "1920x1080", "final_resolution": "2560x1440" } ] } ``` ### Network Configuration Configure network settings including ports, encryption, and UPnP. ```ini # Network settings port = 47989 address_family = ipv4 upnp = disabled external_ip = 123.456.789.12 origin_web_ui_allowed = lan # Encryption settings lan_encryption_mode = 0 wan_encryption_mode = 1 # Connection timeout ping_timeout = 10000 ``` ### Input Configuration Configure gamepad, keyboard, and mouse input handling. ```ini # Gamepad configuration controller = enabled gamepad = auto motion_as_ds4 = enabled touchpad_as_ds4 = enabled back_button_timeout = -1 # Keyboard configuration keyboard = enabled key_repeat_delay = 500 key_repeat_frequency = 24.9 always_send_scancodes = enabled key_rightalt_to_key_win = disabled # Mouse configuration mouse = enabled high_resolution_scrolling = enabled native_pen_touch = enabled # Custom keybindings (hex virtual key codes) keybindings = [ 0x10, 0xA0, 0x11, 0xA2, 0x12, 0xA4 ] ``` ## Application Configuration ### apps.json Structure Applications are configured in a JSON file that defines how games and programs are launched. ```json { "env": { "PATH": "$(PATH);C:\\Program Files\\Custom" }, "apps": [ { "name": "Desktop", "uuid": "auto-generated-uuid", "image-path": "desktop.png", "cmd": "", "output": "", "prep-cmd": [], "detached": [], "exclude-global-prep-cmd": false, "elevated": false, "auto-detach": true, "wait-all": true, "exit-timeout": 5 }, { "name": "Steam Big Picture", "uuid": "another-uuid", "image-path": "steam.png", "cmd": "", "output": "", "prep-cmd": [ { "do": "", "undo": "steam://close/bigpicture", "elevated": false } ], "detached": ["steam://open/bigpicture"], "exclude-global-prep-cmd": false, "elevated": false }, { "name": "Game With AntiCheat", "uuid": "game-uuid", "image-path": "game.png", "cmd": "C:\\Games\\Game.exe", "output": "C:\\Logs\\game.log", "prep-cmd": [ { "do": "powershell.exe -command \"Start-Streaming\"", "undo": "powershell.exe -command \"Stop-Streaming\"", "elevated": true } ], "detached": [], "exclude-global-prep-cmd": false, "elevated": true } ] } ``` ### Prep Commands for Resolution Switching Configure automatic resolution and refresh rate changes when streaming starts. ```json { "name": "4K Gaming", "prep-cmd": [ { "do": "cmd /C \"C:\\Tools\\qres.exe /x:%SUNSHINE_CLIENT_WIDTH% /y:%SUNSHINE_CLIENT_HEIGHT% /r:%SUNSHINE_CLIENT_FPS%\"", "undo": "C:\\Tools\\qres.exe /x:3840 /y:2160 /r:120", "elevated": false } ] } ``` ```bash # Linux X11 resolution switching # Do command: sh -c "xrandr --output HDMI-1 --mode ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --rate ${SUNSHINE_CLIENT_FPS}" # Undo command: xrandr --output HDMI-1 --mode 3840x2160 --rate 120 # Linux KDE Plasma (Wayland) # Do command: sh -c "kscreen-doctor output.HDMI-A-1.mode.${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}@${SUNSHINE_CLIENT_FPS}" # Undo command: kscreen-doctor output.HDMI-A-1.mode.3840x2160@120 ``` ## Server Commands Server commands are customizable actions that can be executed from the client's back menu. ```json { "server_commands": [ { "name": "Sleep Computer", "cmd": "rundll32.exe powrprof.dll,SetSuspendState 0,1,0", "elevated": false }, { "name": "Shutdown", "cmd": "shutdown /s /f /t 0", "elevated": true }, { "name": "Restart", "cmd": "shutdown /r /f /t 0", "elevated": true }, { "name": "Lock Computer", "cmd": "rundll32.exe user32.dll, LockWorkStation", "elevated": false }, { "name": "Open Task Manager", "cmd": "C:\\Windows\\System32\\Taskmgr.exe", "elevated": true }, { "name": "Run AutoHotKey Script", "cmd": "C:\\Scripts\\automation.ahk", "elevated": false } ] } ``` ## Client Commands Client commands execute when a specific client connects or disconnects, enabling automatic game pause/resume. ```powershell # standby.ps1 - Put computer to sleep on client disconnect Add-Type -AssemblyName System.Windows.Forms function Wait-And-Abort-On-Keypress { $timeout = 2 Write-Host "Press any key to abort in $timeout seconds..." -ForegroundColor Yellow $startTime = Get-Date while ((Get-Date) -lt $startTime.AddSeconds($timeout)) { if ([System.Console]::KeyAvailable) { Write-Host "Key press detected. Aborting script." return $true } Start-Sleep -Milliseconds 100 } return $false } if (Wait-And-Abort-On-Keypress) { exit } [System.Windows.Forms.Application]::SetSuspendState([System.Windows.Forms.PowerState]::Suspend, $false, $false) ``` ```ini # Client disconnect command configuration client_disconnect_cmd = powershell -ExecutionPolicy Bypass -File "D:\scripts\standby.ps1" ``` ## Building from Source ### Clone and Build ```bash # Clone repository with submodules git clone https://github.com/ClassicOldSong/Apollo.git --recurse-submodules cd Apollo mkdir build # Configure and build cmake -B build -G Ninja -S . ninja -C build # Package for distribution # Linux DEB: cpack -G DEB --config ./build/CPackConfig.cmake # Linux RPM: cpack -G RPM --config ./build/CPackConfig.cmake # Windows Installer: cpack -G NSIS --config ./build/CPackConfig.cmake # Windows Portable: cpack -G ZIP --config ./build/CPackConfig.cmake # macOS: cpack -G DragNDrop --config ./build/CPackConfig.cmake ``` ### Install Dependencies (Linux) ```bash # Ubuntu/Debian dependencies sudo apt install \ cmake ninja-build \ libboost-all-dev \ libssl-dev libcurl4-openssl-dev \ libopus-dev libpulse-dev \ libva-dev libdrm-dev \ libwayland-dev libx11-dev libxrandr-dev \ libminiupnpc-dev \ nodejs npm # Fedora dependencies sudo dnf install \ cmake ninja-build \ boost-devel \ openssl-devel libcurl-devel \ opus-devel pulseaudio-libs-devel \ libva-devel libdrm-devel \ wayland-devel libX11-devel libXrandr-devel \ miniupnpc-devel \ nodejs npm ``` ### Install Dependencies (Windows MSYS2) ```bash # Update MSYS2 packages pacman -Syu # Install build dependencies pacman -S git \ mingw-w64-ucrt-x86_64-cmake \ mingw-w64-ucrt-x86_64-ninja \ mingw-w64-ucrt-x86_64-toolchain \ mingw-w64-ucrt-x86_64-boost \ mingw-w64-ucrt-x86_64-openssl \ mingw-w64-ucrt-x86_64-opus \ mingw-w64-ucrt-x86_64-miniupnpc \ mingw-w64-ucrt-x86_64-nodejs \ mingw-w64-ucrt-x86_64-nsis ``` ## Permission System Apollo's permission system allows granular control over what each client can do. | Category | Permissions | |----------|-------------| | Action | List Apps, View Streams, Launch Apps | | Operation | Clipboard Set, Clipboard Read, Server Command | | Input | Controller Input, Touch Input, Pen Input, Mouse Input, Keyboard Input | ```json { "client_permissions": { "client-uuid-1234": { "list_apps": true, "view_streams": true, "launch_apps": true, "mouse_input": true, "keyboard_input": true, "controller_input": true, "touch_input": true, "pen_input": true, "clipboard_set": true, "clipboard_read": false, "server_command": false } } } ``` ## Summary Apollo serves as a comprehensive game streaming solution for users who need low-latency remote desktop and gaming capabilities. Its primary use cases include streaming games from a powerful desktop to mobile devices, tablets, or TVs via the Artemis client, hosting multiplayer gaming sessions with multiple simultaneous streams, and providing remote access to a workstation with full input support. The built-in virtual display functionality eliminates the need for dummy HDMI plugs and automatically configures resolution and refresh rates to match client capabilities. Integration patterns typically involve configuring Apollo as a system service that starts automatically, setting up applications through the web UI or direct JSON configuration, and using prep commands to handle resolution switching and game-specific setup. Advanced users can leverage client commands for automatic game pause/resume functionality, server commands for quick system actions, and the permission system to create restricted access profiles for shared gaming scenarios. The REST API enables programmatic control for integration with home automation systems or custom launcher applications.