AC Sync
Sim-Racing-Cockpit

Sync Server Wiki

Linux-Start, Instanzen, DNS und SSL.

Eine Schritt-für-Schritt-Anleitung für Installation und Betrieb des Sync Server-Backends.

1. Ziel der Einrichtung

Am Ende soll dein Sync Server auf einem Linux-Server laufen, über Subdomains erreichbar sein und per HTTPS abgesichert werden.

Das Programm selbst läuft als ein Binary. Es kann aber mehrere Instanzen gleichzeitig bedienen. Welche Instanz für eine Anfrage benutzt wird, entscheidet der Hostname der Anfrage.

Was sind Multiinstanzen?

Multiinstanzen bedeuten: Ein Sync Server-Prozess bedient mehrere logisch getrennte Bereiche gleichzeitig. Jeder Bereich hat eine eigene Subdomain und eigene Datenordner.

Beispiel: alpha-sync.example.com und beta-sync.example.com laufen im selben Dienst, aber mit getrenntem Content unter /syncserver/instances/<host>/....

Wofür sind sie?

  • Trennung von Serien, Ligen oder Umgebungen (z. B. Live, Test, Event)
  • Saubere Datenstruktur je Host ohne Vermischung

Wann braucht man sie?

  • Eine Instanz reicht, wenn du nur eine Subdomain betreibst (darin können eine oder viele Serien liegen)
  • Mehrere Instanzen brauchst du, wenn Inhalte/Benutzer je Subdomain getrennt bleiben sollen
Wenn du den Server hinter Nginx betreibst, ist die übliche Variante: Sync Server läuft lokal auf 127.0.0.1:5055, Nginx nimmt HTTPS an Port 443 an und leitet an den lokalen Sync Server weiter.

2. Voraussetzungen

  • Ein Linux-Server oder VPS
  • Root-Zugriff oder sudo
  • Eine Domain, zum Beispiel example.com
  • Ein DNS-Provider, bei dem du A-Records setzen kannst
  • Das Sync Server-Binary
  • Die Konfigurationsdatei config.yml
  • Nginx und Certbot für den Produktivbetrieb
Der Ordner logs unter jeder Instanz enthält aktuell nur Client-State-Dateien wie clients.json. Dort werden keine klassischen Server-Logs geschrieben.
Aufbau dieser Anleitung: Ab den Praxisabschnitten werden die Schritte jeweils für Einzelinstanz und mehrere Instanzen beschrieben.

3. DNS und Subdomains

Damit die Domain erreichbar ist, müssen die Subdomains auf die öffentliche IP deines Servers zeigen.

Subdomains und IP live anpassen

Trage hier deine Subdomains und eine Beispiel-IP ein. Alle Beispiele in der Anleitung werden ohne Reload sofort aktualisiert und im Browser gespeichert.

Speicherung: localStorage im aktuellen Browser.

Einzelinstanz (eine Subdomain)

  • Setze einen A-Record, zum Beispiel alpha-sync.example.com -> 203.0.113.10.
  • In config.yml muss derselbe Host in instances[].hosts stehen.

Mehrere Instanzen (mehrere Subdomains)

Typisches Beispiel:

  • Setze pro Instanz/Subdomain einen eigenen A-Record.
  • alpha-sync.example.com - A auf 203.0.113.10
  • beta-sync.example.com - A auf 203.0.113.10
  • cup-sync.example.net - A auf 203.0.113.10
Die DNS-Einträge müssen aktiv sein, bevor Certbot das SSL-Zertifikat erstellen kann. Für die HTTP-01-Prüfung muss die Domain bereits auf deinen Server zeigen.

4. Basispfade anlegen

Lege dir auf dem Server einen festen Arbeitsordner an. Bei dir ist das zum Beispiel /syncserver.

sudo mkdir -p /syncserver/bin

Zuerst brauchst du nur den Binary-Pfad und die Position der Konfigurationsdatei. Die Instanz-Unterordner unter /syncserver/instances legt der Sync Server später selbst an (pro Instanz aus dem ersten Hostnamen abgeleitet).

/syncserver
|-- bin
|   |-- syncserver
|-- config.yml

Wichtig: Die Datei muss genau unter /syncserver/config.yml liegen.

5. Binary und config.yml hochladen

Die Datei syncserver ist die eigentliche Anwendung, also das ausführbare Programm des Sync Servers. Du musst sie mit einem FTP- oder SFTP-Programm deiner Wahl in das Verzeichnis /syncserver/bin hochladen.

Wichtig ist nur, dass die Datei am Ende genau hier liegt:

/syncserver/bin/syncserver

Die Konfigurationsdatei muss hier liegen:

/syncserver/config.yml

Erst wenn Binary und config.yml an diesen Pfaden liegen, gehst du zur Konfigurationsanpassung im nächsten Abschnitt.

Beim Start erzeugt der Server die Instanzverzeichnisse unter /syncserver/instances automatisch aus den Hosts in der config.yml.

Beispiel:

/syncserver/instances/alpha-sync.example.com/sync_root
/syncserver/instances/alpha-sync.example.com/sync_json
/syncserver/instances/alpha-sync.example.com/logs

6. config.yml anpassen

Die Konfiguration entscheidet über Serverport, Instanzen und die Speicherorte. Der wichtigste Teil ist das Instanzmodell.

Wichtige Felder

  • server.host - die IP, an der das Binary lauscht
  • server.port - der Port, zum Beispiel 5055
  • routing.default_instance - optionaler Fallback auf eine abgeleitete Instanz-ID
  • instances - Liste aller Instanzen mit hosts
  • instances[].id - wird automatisch aus instances[].hosts[0] abgeleitet (Teil vor dem ersten Punkt)
  • instances[].hosts - Hostnamen/Subdomains dieser Instanz

Grundprinzip

Wenn eine Anfrage mit Hostname alpha-sync.example.com reinkommt, wird die passende Instanz benutzt.

Der Code macht das über das HTTP-Host-Header-Mapping. Deshalb müssen DNS, Nginx und config.yml zueinander passen.

Die Verzeichnisse pro Instanz werden automatisch aus dem Binary-Ort gebildet: <base>/instances/<erster-host>/sync_root, <base>/instances/<erster-host>/sync_json und <base>/instances/<erster-host>/logs.

Pfadlogik:
Wenn das Binary unter /syncserver/bin/syncserver liegt, ist die Base /syncserver. Daraus entstehen automatisch die Instanzpfade unter /syncserver/instances/<erster-host>/....
Wichtig: In der config.yml setzt du pro Instanz nur hosts. Die id leitet der Sync Server immer aus dem ersten Hostteil vor dem ersten Punkt ab. Einen paths-Block gibt es dort nicht mehr.

Wie die Config grob aufgebaut ist

config.yml |-- server |-- routing |-- instances |-- <instanz> |-- hosts
Ordner / Abschnitt Datei / Wert Konfigurationsdatei

7. Einzelne Instanz einrichten

Wenn du nur eine Domain betreibst, reicht eine Instanz. Das ist der einfachste Einstieg.

Auch bei einer einzelnen Instanz sind mehrere Serienordner unter sync_root möglich.
  1. Lege hosts für deine Instanz fest.
  2. Setze server.host auf 127.0.0.1, wenn Nginx davor sitzt.
  3. Setze server.port auf einen freien internen Port, zum Beispiel 5055.
  4. Trage in instances genau eine Instanz mit deiner Subdomain ein.
  5. Optional: Setze routing.default_instance auf die abgeleitete Instanz-ID (z. B. alpha-sync) oder lasse es auf "" für keinen Fallback.
/syncserver
|-- bin
|   |-- syncserver
|-- config.yml
|-- instances
    |-- alpha-sync.example.com
        |-- sync_root
        |-- sync_json
        |-- logs
Ordner Datei / Binary Konfigurationsdatei
server:
  host: "127.0.0.1"
  port: 5055

routing:
  default_instance: ""

instances:
  - hosts:
      - alpha-sync.example.com

8. Mehrere Instanzen einrichten

Mehrere Instanzen sind sinnvoll, wenn du Bereiche/Umgebungen je Subdomain getrennt halten willst. Eine Instanz kann trotzdem mehrere Serien enthalten. Jede Instanz bekommt:

  • eigene Hosts/Subdomains
  • eigene Serienordner (automatisch erzeugt)
  • eigene JSON-Ausgabe (automatisch erzeugt)
  • eigene Client-State-Dateien im logs-Ordner

So funktioniert die Zuordnung

Der Server schaut auf den Hostnamen der Anfrage. Wenn die Anfrage auf beta-sync.example.com kommt, wird die Instanz mit diesem Host verwendet.

Wenn kein Host passt, wird routing.default_instance verwendet. Ist der Wert leer (""), wird die Anfrage abgewiesen.

Auch bei mehreren Instanzen setzt du in der Config nur hosts. Die Instanzpfade werden automatisch aus dem ersten Hostnamen berechnet.

Beispiel mit mehreren Instanzen

/syncserver
|-- bin
|   |-- syncserver
|-- config.yml
|-- instances
    |-- alpha-sync.example.com
    |   |-- sync_root
    |   |-- sync_json
    |   |-- logs
    |-- beta-sync.example.com
    |   |-- sync_root
    |   |-- sync_json
    |   |-- logs
    |-- cup-sync.example.net
        |-- sync_root
        |-- sync_json
        |-- logs
Ordner Datei / Binary Konfigurationsdatei
routing:
  default_instance: ""

instances:
  - hosts:
      - alpha-sync.example.com

  - hosts:
      - beta-sync.example.com

  - hosts:
      - cup-sync.example.net
Wichtig: Der erste Hostteil vor dem ersten Punkt muss je Instanz eindeutig sein (daraus entsteht die id). Jede Subdomain sollte nur bei einer Instanz vorkommen.

9. Nginx als Reverse Proxy

In der Praxis läuft der Sync Server meist nicht direkt auf Port 443. Nginx nimmt die HTTPS-Verbindung an und leitet an den lokalen Sync Server weiter.

Warum Nginx?

  • HTTPS-Termination
  • saubere Subdomain-Trennung
  • einfacheres SSL-Handling
  • der Sync Server kann intern auf 127.0.0.1 bleiben

Einzelinstanz: Nginx-Vorlage pro Instanz

Das folgende Muster ist die vereinheitlichte Vorlage für eine einzelne Instanz. Nimm dafür pro Instanz eine eigene Nginx-Datei, zum Beispiel /etc/nginx/sites-available/alpha-sync.example.com.conf, und passe nur die Domain im server_name und im Host-Header an. Diese Vorlage läuft zuerst über Port 80. HTTPS und der SSL-Zertifikatsteil werden im nächsten Schritt durch Certbot ergänzt.

upstream sync_backend {
    server 127.0.0.1:5055;
    keepalive 128;
}

server {
    listen 80;
    server_name alpha-sync.example.com;

    proxy_http_version 1.1;
    proxy_set_header Connection "";

    access_log /var/log/nginx/alpha-sync.access.log;
    error_log  /var/log/nginx/alpha-sync.error.log;

    gzip on;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml
        application/xml+rss
        text/javascript
        application/octet-stream;
    gzip_min_length 512;
    gzip_comp_level 5;
    gzip_vary on;
    gzip_proxied any;
    gzip_disable "msie6";

    client_max_body_size 1024m;
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;

    location = /health {
        proxy_pass http://sync_backend;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        proxy_buffering off;
        add_header Cache-Control "no-store" always;
    }

    location = /healthz {
        proxy_pass http://sync_backend/health;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        proxy_buffering off;
        add_header Cache-Control "no-store" always;
    }

    location = /list_projects {
        proxy_pass http://sync_backend;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Accept-Encoding "";
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        add_header Cache-Control "no-store, must-revalidate, max-age=0" always;
    }

    location ^~ /file_list/ {
        proxy_pass http://sync_backend;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Accept-Encoding "";
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        add_header Cache-Control "no-store, must-revalidate, max-age=0" always;
    }

    location ^~ /download_file/ {
        proxy_pass http://sync_backend;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        proxy_request_buffering off;
        proxy_buffering off;
        proxy_max_temp_file_size 0;
        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
    }

    location / {
        proxy_pass http://sync_backend;
        proxy_set_header Host alpha-sync.example.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Accept-Encoding "";
        proxy_cache off;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
        proxy_buffering on;
        proxy_buffers 32 64k;
        proxy_busy_buffers_size 256k;
        proxy_max_temp_file_size 1024m;
    }

}

Mehrere Instanzen: so passt du die Nginx-Konfiguration an

  • lege für jede Instanz eine eigene Datei in /etc/nginx/sites-available an
  • kopiere den Inhalt der Vorlage vollständig in diese neue Datei
  • ändere server_name alpha-sync.example.com auf die neue Subdomain
  • ändere jeden proxy_set_header Host alpha-sync.example.com auf dieselbe neue Subdomain
  • passe optional die Logdateien an, damit jede Instanz eigene Nginx-Logs bekommt
  • nutze pro Instanz möglichst eine eigene Konfigurationsdatei, damit Änderungen sauber getrennt bleiben

Beispiel für eine zweite Instanz

Wenn du zusätzlich beta-sync.example.com betreiben möchtest, legst du eine zweite Datei an:

/etc/nginx/sites-available/beta-sync.example.com.conf

In diese Datei kopierst du exakt dieselbe Nginx-Konfiguration wie oben. Danach ersetzt du nur die Domain:

  • alpha-sync.example.com wird zu beta-sync.example.com
  • <id>.access.log und <id>.error.log als Schema verwenden
  • alpha-sync.access.log wird optional zu beta-sync.access.log
  • alpha-sync.error.log wird optional zu beta-sync.error.log
Wenn du Nginx nutzt, lasse server.host im Sync Server auf 127.0.0.1. Dann ist der Dienst nicht direkt aus dem Internet erreichbar. Der Port 5055 bleibt für mehrere Instanzen gleich, wenn alle Instanzen über denselben Sync Server-Prozess laufen. Die Zuordnung passiert dann über den Hostnamen aus der Anfrage.

10. SSL mit Certbot

Die Subdomains sollten per HTTPS erreichbar sein. Dafür nutzt man in der Regel Certbot mit Nginx.

Certbot installieren

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx

Zertifikat anfordern je Szenario

Variante A: Eine Instanz mit einer Subdomain

Wenn du nur eine Instanz hast, fordere das Zertifikat genau für diese eine Domain an.

sudo certbot --nginx -d alpha-sync.example.com

Certbot erweitert danach die Nginx-Datei dieser Subdomain um HTTPS und Redirect.

Variante B: Mehrere Instanzen mit mehreren Subdomains

Bei mehreren Instanzen hast du zwei saubere Optionen:

  1. ein gemeinsames Zertifikat mit mehreren -d-Einträgen
  2. pro Subdomain ein eigenes Zertifikat

Beispiel für ein gemeinsames Zertifikat:

sudo certbot --nginx \
  -d alpha-sync.example.com \
  -d beta-sync.example.com \
  -d cup-sync.example.net

Beispiel pro Subdomain (nacheinander ausführen):

sudo certbot --nginx -d alpha-sync.example.com
sudo certbot --nginx -d beta-sync.example.com
sudo certbot --nginx -d cup-sync.example.net

Was dabei wichtig ist

  1. Die DNS-Records müssen schon auf den Server zeigen.
  2. Nginx muss auf Port 80 erreichbar sein.
  3. Die Domain muss auflösbar sein, sonst kann Certbot nicht prüfen.
  4. Nach erfolgreicher Ausstellung übernimmt Certbot die HTTPS-Konfiguration in Nginx.

11. Als Dienst starten

Damit der Server nach einem Neustart automatisch startet, nimmst du am besten einen systemd-Service.

Datei öffnen

sudo nano /etc/systemd/system/syncserver.service

Danach den folgenden Service-Block komplett in den Editor kopieren und speichern.

Service-Block

[Unit]
Description=Sync Server
After=network.target

[Service]
WorkingDirectory=/syncserver
ExecStart=/syncserver/bin/syncserver --config /syncserver
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Danach ausführen

sudo systemctl daemon-reload
sudo systemctl enable --now syncserver
sudo systemctl status syncserver

Einzelinstanz vs. mehrere Instanzen

  • Einzelinstanz: ein Service reicht.
  • Mehrere Instanzen: ebenfalls ein Service; die Trennung passiert über config.yml und Hostnamen.

Wenn du mehrere Instanzen im selben Binary betreibst, reicht ein Service. Alle Instanzen werden aus derselben config.yml geladen.

12. Test und Kontrolle

Wenn alles eingerichtet ist, prüfe die Kette von innen nach außen:

  1. läuft der Sync Server lokal?
  2. antwortet Nginx auf Port 80/443?
  3. zeigen die DNS-Records auf den Server?
  4. ist das SSL-Zertifikat gültig?
  5. wird der richtige Host auf die richtige Instanz geroutet?
Tests mit curl sind optional. Die Kernprüfung bleibt der Browser-Test.

Optionale curl-Tests: Einzelinstanz

curl -I http://127.0.0.1:5055
curl -I https://alpha-sync.example.com

Optionale curl-Tests: Mehrere Instanzen

curl -I http://127.0.0.1:5055
curl -I https://alpha-sync.example.com
curl -I https://beta-sync.example.com
curl -I https://cup-sync.example.net
Wenn die Domain per HTTPS antwortet und die richtige Instanz ausgeliefert wird, ist die Einrichtung fertig.

Häufige Fehler

  • 404 oder falsche Daten: Hostname in Nginx oder config.yml passt nicht.
  • Certbot scheitert: DNS zeigt noch nicht auf den Server oder Port 80 ist blockiert.
  • Seite nicht erreichbar: Nginx läuft nicht oder Firewall blockiert 80/443.
  • Sync Server startet nicht: Rechte auf den Ordnern fehlen oder der Port ist belegt.

13. Content bereitstellen

Hier legst du fest, wo deine eigentlichen Dateien liegen. Der Sync Server liest Content immer aus sync_root der jeweiligen Instanz.

Zielpfad je Instanz

  • Einzelinstanz: /syncserver/instances/alpha-sync.example.com/sync_root
  • Mehrere Instanzen: pro Host ein eigener Pfad /syncserver/instances/<host>/sync_root
  • Lade den Content nur nach sync_root, nicht nach sync_json oder logs
  • Wenn du per Samba arbeitest: der Share muss auf genau diesen sync_root-Pfad zeigen

Pflichtstruktur im Serienordner

Jeder Serienordner unter sync_root muss einen content-Unterordner haben. Nur Dateien in diesem Baum werden indexiert.

/syncserver
|-- instances
    |-- alpha-sync.example.com
        |-- sync_root
            |-- Formula1
            |   |-- content
            |       |-- cars
            |       |-- tracks
            |-- TouringCup_pw123_
                |-- content
                    |-- cars
Optionaler Passwortschutz pro Serienordner: <name>_<passwort>_
Beispiel: TouringCup_pw123_ wird öffentlich als TouringCup angezeigt und benötigt das Passwort pw123.

Wichtige Regeln

  • Lege pro Instanz nur die Serien ab, die zu diesem Host gehören
  • Vermeide doppelte Seriennamen (auch nur in anderer Groß-/Kleinschreibung)
  • Dateien außerhalb von content werden nicht in die Serien-JSON aufgenommen
  • sync_json wird vom Server erzeugt; diese Dateien nicht manuell bearbeiten
  • Prüfe Dateirechte nach Upload: der Sync Server-User muss lesen können (typisch syncsrv:syncsrv)

Einzelinstanz: schneller Check nach Upload (curl optional)

ls -la /syncserver/instances/alpha-sync.example.com/sync_root
curl -sS -H "Host: alpha-sync.example.com" http://127.0.0.1:5055/list_projects
curl -sS -H "Host: alpha-sync.example.com" http://127.0.0.1:5055/file_list/Formula1.json | head

Mehrere Instanzen: pro Host prüfen (curl optional)

curl -sS -H "Host: alpha-sync.example.com" http://127.0.0.1:5055/list_projects
curl -sS -H "Host: beta-sync.example.com"  http://127.0.0.1:5055/list_projects
curl -sS -H "Host: cup-sync.example.net"   http://127.0.0.1:5055/list_projects
Wenn pro Host nur die erwarteten Serien erscheinen, liegt der Content im richtigen Instanzpfad und das Host-Routing ist korrekt.

Empfohlener Gesamtablauf

Ablauf für eine Instanz

  1. DNS-A-Record für diese eine Subdomain setzen.
  2. Basispfade unter /syncserver anlegen (mindestens /syncserver/bin).
  3. syncserver und config.yml auf den Server hochladen.
  4. config.yml mit genau einer Instanz (hosts) anpassen.
  5. Nginx-Site für diese eine Subdomain konfigurieren.
  6. Certbot für diese eine Subdomain ausführen.
  7. Sync Server als systemd-Dienst starten.
  8. Content nach /syncserver/instances/<host>/sync_root laden und Struktur prüfen.
  9. Diese Subdomain im Browser testen (curl optional).

Ablauf für mehrere Instanzen

  1. Für jede Subdomain einen DNS-A-Record setzen.
  2. Basispfade unter /syncserver anlegen (mindestens /syncserver/bin).
  3. syncserver und config.yml auf den Server hochladen.
  4. config.yml mit mehreren Instanzen (hosts) anpassen.
  5. Für jede Subdomain eine eigene Nginx-Site konfigurieren.
  6. Certbot mit mehreren -d oder je Subdomain einzeln ausführen.
  7. Sync Server als einen systemd-Dienst starten (ein Prozess, mehrere Instanzen).
  8. Content je Instanz in den passenden sync_root-Pfad laden und je Host prüfen.
  9. Alle Subdomains im Browser testen (curl optional).