Quick overview
This guide sets up an AC Sync Server on Linux. At the end, one Sync Server process runs as a systemd service, Nginx handles the reverse proxy, Certbot provides HTTPS, and each instance has its own subdomain and content structure.
- Target system: Linux server with shell access
- Important files:
syncserver,config.yml, Nginx site and systemd service - Ports: typically
5055internally, public80and443through Nginx - Content: per instance under
/syncserver/instances/<host>/sync_root
1. Setup goal
In the end, your sync server should run on a Linux server, be accessible via subdomains and be secured via HTTPS.
The program itself runs as a binary. However, it can serve several instances at the same time. Which instance is used for a request is decided by the hostname of the request.
What are multi-instances?
Multi-instances mean: one Sync Server process serves several logically separated areas at the same time. Each area has its own subdomain and its own data folders.
Example: alpha-sync.example.com and beta-sync.example.com
run in the same service, but with separate content under
/syncserver/instances/<host>/....
What are they for?
- Separation of series, leagues or environments (for example live, test, event)
- Clean data structure per host without mixing
When do you need them?
- One instance is enough if you only operate one subdomain (one or many series can be in it)
- You need multiple instances when content/users should remain separated by subdomain
Sync Server runs locally on 127.0.0.1:5055, Nginx accepts HTTPS on port 443 and forwards it to the local Sync Server.
2. Requirements
- A Linux server or VPS
- Root access or
sudo - Eine Domain, zum Beispiel
example.com - Ein DNS-Provider, bei dem du A-Records setzen kannst
- Das Sync Server-Binary
- Die Configuration file
config.yml - Nginx and Certbot for productive operation
logs under each instance currently contains only client state files such as clients.json. No classic server logs are written there.
3. DNS and subdomains
For the domain to be reachable, the subdomains must point to the public IP of your server.
Adjust subdomains and IP live
Enter your subdomains and an example IP here. All examples in the guide are updated instantly without a reload and saved in the browser.
Storage: localStorage in the current browser.
Single instance (one subdomain)
- Set an A-Record, zum Beispiel
alpha-sync.example.com->203.0.113.10. - In
config.ymlthe same host must be listed ininstances[].hostsstand.
Multiple instances (mehrere Subdomains)
Typisches Example:
- Setze pro Instanz/Subdomain einen eigenen A-Record.
alpha-sync.example.com- A auf203.0.113.10beta-sync.example.com- A auf203.0.113.10cup-sync.example.net- A auf203.0.113.10
4. Create base paths
Create a fixed working directory on the server. In this guide that directory is
/syncserver.
sudo mkdir -p /syncserver/bin
sudo useradd --system --home /syncserver --shell /usr/sbin/nologin syncsrv || true
sudo chown -R syncsrv:syncsrv /syncserver
At first you only need the binary path and the configuration file location.
The instance subfolders under /syncserver/instances are created later by
the Sync Server itself, derived from the first hostname of each instance.
/syncserver
|-- bin
| |-- syncserver
|-- config.yml
Important: the file must be located exactly at /syncserver/config.yml.
This guide runs the service as the dedicated system user syncsrv.
5. Upload binary and config.yml
The file syncserver is the actual application, the executable program of
the Sync Server. Upload it with an FTP or SFTP tool of your choice into
/syncserver/bin.
The only important thing is that the file ends up exactly here:
/syncserver/bin/syncserver
The configuration file must be here:
/syncserver/config.yml
After uploading, permissions and ownership must be correct. Without an executable binary, systemd cannot start the Sync Server.
sudo chmod +x /syncserver/bin/syncserver
sudo chown -R syncsrv:syncsrv /syncserver
Only when the binary and config.yml are at these paths, continue with the
configuration adjustment in the next section.
On startup, the server creates the instance directories under /syncserver/instances
automatically from the hosts in the config.yml.
Example:
/syncserver/instances/alpha-sync.example.com/sync_root
/syncserver/instances/alpha-sync.example.com/sync_json
/syncserver/instances/alpha-sync.example.com/logs
6. Adjust config.yml
The configuration defines the server port, instances and storage locations. The most important part is the instance model.
Important fields
server.host- the IP the binary listens onserver.port- the port, for example5055routing.default_instance- optional fallback to a derived instance IDinstances- list of all instances withhostsinstances[].id- is automatically derived frominstances[].hosts[0](part before the first dot)instances[].hosts- hostnames/subdomains of this instance
Basic principle
When a request with hostname
alpha-sync.example.com comes in, the matching instance is used.
The code does this through HTTP host header mapping. Therefore DNS,
Nginx and config.yml must match.
The directories per instance are automatically built from the binary location:
<base>/instances/<first-host>/sync_root,
<base>/instances/<first-host>/sync_json und
<base>/instances/<first-host>/logs.
If the binary is located at
/syncserver/bin/syncserver, the base is
/syncserver. This automatically creates the instance paths under
/syncserver/instances/<first-host>/....
config.yml, set only hosts per
instance. The Sync Server always derives the id from the first hostname
part before the first dot. There is no paths block there anymore.
routing.default_instance: "". Unknown hostnames will then be rejected with
404. If you want a fallback, the value must exactly match the derived instance ID, for
example alpha-sync for alpha-sync.example.com.
Minimal example for one instance
server:
host: "127.0.0.1"
port: 5055
routing:
default_instance: ""
instances:
- hosts:
- alpha-sync.example.com
Rough config structure
7. Set up a single instance
If you operate only one domain, one instance is enough. This is the simplest entry point.
sync_root .
- Define
hostsfor your instance. - Set
server.hostto127.0.0.1, if Nginx sits in front of it. - Set
server.portto a free internal port, for example5055. - Enter exactly one instance with your subdomain in
instances. - Optional: Set
routing.default_instanceto the derived instance ID (for examplealpha-sync) or leave it at""for no fallback.
/syncserver
|-- bin
| |-- syncserver
|-- config.yml
|-- instances
|-- alpha-sync.example.com
|-- sync_root
|-- sync_json
|-- logs
server:
host: "127.0.0.1"
port: 5055
routing:
default_instance: ""
instances:
- hosts:
- alpha-sync.example.com
8. Set up multiple instances
Multiple instances are useful when you want to keep areas/environments separated per subdomain. One instance can still contain multiple series. Each instance gets:
- own hosts/subdomains
- own series folders (created automatically)
- own JSON output (created automatically)
- own client state files in the
logs-Ordner
How assignment works
The server looks at the hostname of the request. If the request comes to beta-sync.example.com the instance with this host is used.
If no host matches, routing.default_instance is used. If the value is empty (""), the request is rejected.
hosts. The instance paths are calculated automatically from the first hostname.
Example with multiple instances
/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
routing:
default_instance: ""
instances:
- hosts:
- alpha-sync.example.com
- hosts:
- beta-sync.example.com
- hosts:
- cup-sync.example.net
id). Each subdomain should occur in only one instance.
9. Nginx as reverse proxy
In practice, the Sync Server usually does not run directly on port 443. Nginx accepts the HTTPS connection and forwards it to the local Sync Server.
Why Nginx?
- HTTPS-Termination
- clean subdomain separation
- simpler SSL handling
- the Sync Server can stay internal on
127.0.0.1
Nginx template per instance
Create one separate file per subdomain, for example
/etc/nginx/sites-available/alpha-sync.example.com.conf.
This template intentionally does not use a global upstream block. This means
you can copy it for multiple instances without Nginx failing because of duplicate
upstream names.
server {
listen 80;
listen [::]:80;
server_name alpha-sync.example.com;
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 2048m;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
location = /healthz {
proxy_pass http://127.0.0.1:5055/health;
proxy_set_header Host $host;
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 ^~ /download_file/ {
proxy_pass http://127.0.0.1:5055;
proxy_set_header Host $host;
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://127.0.0.1:5055;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
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;
}
}
Enable the site
sudo ln -s /etc/nginx/sites-available/alpha-sync.example.com.conf /etc/nginx/sites-enabled/alpha-sync.example.com.conf
sudo nginx -t
sudo systemctl reload nginx
Multiple instances: how to adjust the Nginx configuration
- create one separate file in
/etc/nginx/sites-availablefor each instance - copy the full template into this new file
- change
server_name alpha-sync.example.comto the new subdomain - the header
proxy_set_header Host $hostcan stay because Nginx forwards the requested host - optionally adjust the log files so each instance gets its own Nginx logs
- enable each file separately with a symlink,
nginx -tand reload
Example for a second instance
If you also want to run beta-sync.example.com, create
a second file:
/etc/nginx/sites-available/beta-sync.example.com.conf
Copy exactly the same Nginx configuration as above into this file. Then only replace the domain and optionally the log names:
alpha-sync.example.combecomesbeta-sync.example.comalpha-sync.access.logwird optional zubeta-sync.access.logalpha-sync.error.logwird optional zubeta-sync.error.log
server.host in the Sync Server on
127.0.0.1. Then the service is not directly reachable from the internet.
Port 5055 stays the same for multiple instances when all instances
run through the same Sync Server process. The routing then happens through the
hostname of the request.
10. SSL with Certbot
The subdomains should be reachable via HTTPS. Usually this is done with Certbot and Nginx.
Install Certbot
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx
Open the firewall
Port 80 and 443 must be publicly reachable. The internal Sync Server port
5055 should not be exposed directly to the internet.
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Request certificate by scenario
Variant A: One instance with one subdomain
If you only have one instance, request the certificate exactly for that domain.
sudo certbot --nginx -d alpha-sync.example.com
Certbot then extends the Nginx file for this subdomain with HTTPS and redirect.
Variant B: Multiple instances with multiple subdomains
With multiple instances you have two clean options:
- one shared certificate with multiple
-dentries - one separate certificate per subdomain
Example for a shared certificate:
sudo certbot --nginx \
-d alpha-sync.example.com \
-d beta-sync.example.com \
-d cup-sync.example.net
Example per subdomain (run one after another):
sudo certbot --nginx -d alpha-sync.example.com
sudo certbot --nginx -d beta-sync.example.com
sudo certbot --nginx -d cup-sync.example.net
What matters here
- The DNS records must already point to the server.
- Nginx must be reachable on port 80.
- The domain must resolve, otherwise Certbot cannot validate it.
- After successful issuance, Certbot takes over the HTTPS configuration in Nginx.
11. Start as a service
To make the server start automatically after a reboot, it is best to use a systemd
service. The following variant does not run as root, but as the dedicated user
syncsrv.
Open file
sudo nano /etc/systemd/system/syncserver.service
Then copy the following service block completely into the editor and save it.
Service block
[Unit]
Description=Sync Server
After=network.target
[Service]
Type=simple
User=syncsrv
Group=syncsrv
WorkingDirectory=/syncserver
ExecStart=/syncserver/bin/syncserver --config /syncserver
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Then run
sudo systemctl daemon-reload
sudo systemctl enable --now syncserver
sudo systemctl status syncserver
Single instance vs. multiple instances
- Single instance: one service is enough.
- Multiple instances: also one service; separation happens through
config.ymland hostnames.
If you run multiple instances in the same binary, one service is enough.
All instances are loaded from the same config.yml.
12. Test and checks
When everything is set up, check the chain from the inside out:
- is the Sync Server running locally?
- does Nginx answer on port 80/443?
- do the DNS records point to the server?
- is the SSL certificate valid?
- is the correct host routed to the correct instance?
curl are optional. For local tests on
127.0.0.1, the Host header is important because the Sync Server
selects the instance through the hostname.
Optional curl tests: single instance
curl -sS -H "Host: alpha-sync.example.com" http://127.0.0.1:5055/health
curl -sS -H "Host: alpha-sync.example.com" http://127.0.0.1:5055/list_projects
curl -I https://alpha-sync.example.com
Optional curl tests: multiple instances
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
curl -I https://alpha-sync.example.com
curl -I https://beta-sync.example.com
curl -I https://cup-sync.example.net
Common mistakes
- 404 or wrong data: Hostname in Nginx or
config.ymldoes not match. - Certbot fails: DNS does not point to the server yet or port 80 is blocked.
- Page not reachable: Nginx is not running or the firewall blocks 80/443.
- Sync Server does not start: Folder permissions are missing, the binary is not executable or the port is already in use.
13. Provide content
Here you define where your actual files are located. Sync Server always reads content from sync_root of the respective instance.
Target path per instance
- Single instance:
/syncserver/instances/alpha-sync.example.com/sync_root - Multiple instances: one separate path per host
/syncserver/instances/<host>/sync_root - Upload content only to
sync_root, not tosync_jsonorlogs - If you work with Samba: the share must point to exactly this
sync_rootpath
Required structure in the series folder
Every series folder under sync_root must have a
content subfolder. Only files in this tree are indexed.
/syncserver
|-- instances
|-- alpha-sync.example.com
|-- sync_root
|-- Formula1
| |-- content
| |-- cars
| |-- tracks
|-- TouringCup_pw123_
|-- content
|-- cars
<name>_<passwort>_Example:
TouringCup_pw123_ is publicly known as
TouringCup and requires the password pw123.
Important rules
- Store only the series that belong to this host in each instance
- Avoid duplicate series names, even if only capitalization differs
- Files outside of
contentare not included in the series JSON sync_jsonis generated by the server; do not edit these files manually- Check file rights after upload: the sync server user must be able to read (typically
syncsrv:syncsrv)
Single instance: quick check after 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
Multiple instances: check per host (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
Recommended overall workflow
Procedure for an instance
- Set a DNS-A record for this one subdomain.
- Create base paths under
/syncserver(at least/syncserver/bin). - Upload
syncserverandconfig.ymlto the server. - Adjust
config.ymlwith exactly one instance (hosts). - Configure nginx site for this one subdomain.
- Run Certbot for this subdomain.
- Start Sync Server as a systemd service.
- Load content into
/syncserver/instances/<host>/sync_rootand check the structure. - Test this subdomain in the browser (
curloptional).
Process for multiple instances
- Set a DNS-A record for each subdomain.
- Create base paths under
/syncserver(at least/syncserver/bin). - Upload
syncserverandconfig.ymlto the server. - Adjust
config.ymlwith multiple instances (hosts). - Configure a separate nginx site for each subdomain.
- Certbot with multiple
-dor run individually for each subdomain. - Start Sync Server as one systemd service (one process, multiple instances).
- Load content for each instance into the matching
sync_root-path and check per host. - Test all subdomains in the browser (
curloptional).