Skip to content

unveroleone/save-sync

Repository files navigation

Save Sync on PS Vita

Save Sync

Self-hosted cloud save sync for PS Vita, PPSSPP, and RetroArch, across all your devices

version Node.js Vita client Desktop client GPL-3.0

Play anywhere · Upload your save · Restore on any device
Forked from Save Cloud Vita. Baidu Cloud replaced with a self-hosted HTTP API. All strings translated to English.


What it does

One server, multiple clients. All saves go to the same place.

PS Vita app:

  • Backs up native PS Vita saves, PSP/Adrenaline saves, and RetroArch saves
  • Uploads to your server as a zip, downloads and restores on another Vita
  • Shows per-game sync status on the Cloud tab with one-tap Sync All

Note on native Vita saves: PSP and RetroArch saves transfer reliably between devices. Native PS Vita saves are encrypted with a mix of your PSN account and hardware keys, so results vary. Same PSN account on both Vitas works for many titles but is not guaranteed for all. If a save does not load after restoring, use a tool like Apollo Save Tool to resign it.

Save Sync Hub (Desktop / Android):

  • Syncs PPSSPP and RetroArch saves from macOS, Windows, Linux, and Android
  • Detects default save locations automatically per platform
  • Upload to server, download to local, or restore directly from cloud
  • Connects to the same server and same API as the Vita app

Clients at a glance

Client Runs on Emu lators / saves
Save Sync (Vita app) PS Vita, PSTV Native Vita · PSP (Adrenaline) · RetroArch
Save Sync Hub macOS · Windows · Linux · Android PPSSPP · RetroArch · Custom path

The Vita app requires HENkaku + iTLS-Enso. Save Sync Hub is a standard desktop/Android app (no jailbreak needed on the other end).


Server setup

The server is a small Node.js app. It stores save files on disk and exposes a REST API. You need to keep it running while you sync, it does not need to be on 24/7.

Pick the option that fits your situation.


Option A | Docker

If you have Docker installed (Docker Desktop for macOS/Windows, or apt install docker.io on Linux), create two files and run one command:

# docker-compose.yml
services:
  vita-save-sync:
    image: ghcr.io/unveroleone/vita-save-sync-server:latest
    container_name: vita-save-sync
    restart: unless-stopped
    ports:
      - "3099:3000"
    environment:
      - USER_TOKEN=${USER_TOKEN:?set a strong token}
      - DATA_DIR=/data
    volumes:
      - vita-save-data:/data

volumes:
  vita-save-data:
    driver: local
# .env
USER_TOKEN=change-me-to-a-long-random-string
docker compose up -d

To update later: docker compose pull && docker compose up -d

Note: docker compose restart reuses the cached environment. If you change .env, run docker compose up -d instead.

Put the server behind Nginx Proxy Manager or Cloudflare Tunnel for HTTPS. The Vita needs HTTPS with a valid certificate; iTLS-Enso provides the modern TLS roots.


Option B | Node.js directly  (quickest to get started)

You need Node.js 20 or newer. Works on macOS, Windows, and Linux.

git clone https://github.com/unveroleone/vita-save-sync.git
cd vita-save-sync/server
npm install
npm run build
USER_TOKEN=your-secret-token DATA_DIR=./data node dist/index.js

The server listens on port 3000. Add PORT=3099 to the command if you need a different port.


Option C | Raspberry Pi  (always-on home server)

Start from a fresh Raspberry Pi OS (Bookworm or newer). Ethernet is recommended for reliability, but Wi-Fi works too.

Install Node.js (LTS):

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs git

Clone and start:

git clone https://github.com/unveroleone/vita-save-sync.git
cd vita-save-sync/server
npm install
npm run build
USER_TOKEN=your-secret-token DATA_DIR=./data node dist/index.js

Auto-start on boot with systemd:

Replace pi with your actual username if it differs (run whoami to check).

sudo tee /etc/systemd/system/vita-save-sync.service << 'EOF'
[Unit]
Description=Save Sync server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/vita-save-sync/server
Environment=USER_TOKEN=your-secret-token
Environment=DATA_DIR=/home/pi/vita-save-sync/server/data
Environment=PORT=3000
ExecStart=/usr/bin/node dist/index.js
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now vita-save-sync

Check status: sudo systemctl status vita-save-sync


Option D | Background service on your laptop  (macOS / Linux / Windows)

macOS: create a launchd plist so the server starts automatically at login.

First find your Node.js path: which node (commonly /usr/local/bin/node on Intel, /opt/homebrew/bin/node on Apple Silicon).

Save this as ~/Library/LaunchAgents/com.vita-save-sync.plist, replacing the paths and token:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.vita-save-sync</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/node</string>
        <string>/Users/you/vita-save-sync/server/dist/index.js</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
        <key>USER_TOKEN</key>
        <string>your-secret-token</string>
        <key>DATA_DIR</key>
        <string>/Users/you/vita-save-sync/server/data</string>
        <key>PORT</key>
        <string>3000</string>
    </dict>
    <key>WorkingDirectory</key>
    <string>/Users/you/vita-save-sync/server</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Load it: launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.vita-save-sync.plist


Linux: use the systemd unit from Option C. Same file, same commands.


Windows: run a terminal on login and keep it open, or use Task Scheduler to launch node dist/index.js at boot with USER_TOKEN and DATA_DIR set as environment variables.


HTTPS

The Vita requires HTTPS with a valid certificate. The easiest option is Cloudflare Quick Tunnel (no account or domain needed). Install and run:

Platform Install command
macOS brew install cloudflared
Linux curl -L https://pkg.cloudflare.com/install.sh | sudo bash && sudo apt install cloudflared
Windows winget install -e --id Cloudflare.cloudflared

While your server is running:

cloudflared tunnel --url http://localhost:3000

It prints a *.trycloudflare.com address. Use that as the server URL on the Vita. The tunnel closes when you close the terminal, which is fine for occasional sync sessions.

For a permanent setup with your own domain, Cloudflare Tunnel with a named tunnel is also free.


First-time setup on the Vita

Install the VPK via VitaDB Downloader (search "Save Sync") or download it from GitHub Releases and install manually via VitaShell.

  1. Install the VPK
  2. Open Save Sync
  3. Press R to switch to the Cloud tab
  4. Press Triangle to open Settings
  5. Fill in Server URL (e.g. https://vita-sync.example.com), API Token, and Device Name
  6. Select Test Connection (checks both reachability and your token)
  7. Press o to go back, or select Save && Back

Save Sync on PS Vita


Save Sync Hub (Desktop / Android)

Save Sync Hub is the companion app for PC and Android. It syncs PPSSPP and RetroArch saves using the same server and API token as the Vita app.

Download the latest release from GitHub Releases for your platform (.dmg for macOS, .exe for Windows, .AppImage for Linux, .apk for Android).

First-time setup

  1. Open Save Sync Hub
  2. In the sidebar, enter your Server URL, API Token, and Device Name (same values as on the Vita)
  3. Click Save Config
  4. Select your platform (PSP / RetroArch / Custom path)
  5. The app auto-fills the default save folder for your OS, or browse to a custom path
  6. Click Scan Saves to list your save directories

Default save paths

Platform PPSSPP RetroArch
macOS ~/Documents/PPSSPP/PSP/SAVEDATA ~/Library/Application Support/RetroArch
Windows %USERPROFILE%\Documents\PPSSPP\PSP\SAVEDATA %APPDATA%\RetroArch
Linux ~/.config/ppsspp/PSP/SAVEDATA ~/.config/retroarch
Android /storage/emulated/0/PSP/SAVEDATA /storage/emulated/0/RetroArch

These are the most common defaults. PPSSPP varies by install method — if your saves are not found, use Browse to point to the right folder. For RetroArch, the app scans for saves/ and states/ subdirectories inside the path above.

Workflow

  • Upload: zips the save folder and sends it to the server
  • Download: fetches the latest backup from the server to a local zip
  • Restore: downloads from the server and extracts directly into the save folder

Save IDs on the server use the folder name as the title ID, prefixed with PSP_ or RA_ to avoid collisions with native Vita saves.


Workflow (PS Vita)

Cloud tab (the main way to sync)

Press R to switch to the Cloud tab. Every game shows a sync status badge:

Badge Meaning
Synced In sync with server
Not Uploaded Never uploaded to server
Upload Local is newer
Download Server has a newer version
Cloud Only On server, not on this Vita
Conflict Both sides changed

X on a game uploads (if marked Upload) or downloads and restores directly (if marked Download or Cloud Only). One step.

Square runs Sync All. It uploads everything marked Upload and downloads everything marked Download. Conflicts are reported but not touched.

Triangle opens Settings.

Save Sync Cloud tab

Games tab (local saves only)

Press L to see your local saves. Select a game and press X to open the save drawer:

  • Local Backup tab (press L in the drawer) manages save slots on the Vita itself, independent of the server. Use it to keep manual snapshots or restore a previous local slot.
  • Server Backup tab (press R in the drawer) has manual Upload, Download, and Download & Restore options.

For daily use, the Cloud tab is faster. The drawer is there for the manual actions.

Save Sync save drawer

Save Sync save drawer


Server API

Method Path Auth Description
GET /api/status No Health check, server version
GET /api/manifest Bearer Cloud manifest for all games
PUT /api/save/:titleId Bearer Upload save zip
GET /api/save/:titleId Bearer Download save zip

Upload sends X-Save-Hash (SHA-256), X-Save-Timestamp, and X-Device-Id headers. The server verifies the hash before writing.


Credits

Forked from Save Cloud Vita by iamcco. Vita app uses VitaShell SQLite VFS and kernel modules, vita-rust, VitaSDK. Save Sync Hub built with Tauri v2 and Svelte 5.

Built with the help of AI

About

Save sync for modded handhelds. Self-hosted server, Rust client, cross-platform desktop app.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages