Download Deployment Options
Note
Because the backend uses Flask, which is a synchronous framework, the default deployment setup cannot handle a large number of simultaneous downloads when thread count is limited. The following deployment suggestions are provided for users who need to improve download performance.
Single-host Deployment
NGINX X-Accel-Redirect
nginx is a well-known high-performance HTTP server that supports reverse proxying, load balancing, and more. By using the X-Accel-Redirect feature, the backend can return a special response header that tells nginx to serve the file directly from a specified path. This greatly improves download throughput and concurrency. Meanwhile, other requests are also forwarded to nginx.
If all requests are proxied through nginx, nginx should listen on port 80 and the backend should use a different port to avoid conflicts. If you need SSL/TLS, refer to nginx documentation and use port 443 or another appropriate port.
class Config:
HOST = '0.0.0.0'
PORT = 81
# USE_CORS = True
USE_PROXY_FIX = True
# DEPLOY_MODE = 'waitress'
DOWNLOAD_LINK_PREFIX = '' # http(s)://host(:port)/download/
BUNDLE_DOWNLOAD_LINK_PREFIX = '' # http(s)://host(:port)/bundle_download/
DOWNLOAD_USE_NGINX_X_ACCEL_REDIRECT = True
NGINX_X_ACCEL_REDIRECT_PREFIX = '/nginx_download/'
BUNDLE_NGINX_X_ACCEL_REDIRECT_PREFIX = '/nginx_bundle_download/'Tips
If USE_PROXY_FIX is enabled and nginx is configured accordingly, DOWNLOAD_LINK_PREFIX and BUNDLE_DOWNLOAD_LINK_PREFIX do not need to be set manually; the address and port can be detected automatically. Otherwise, configure them explicitly.
It is highly recommended to enable DEPLOY_MODE to achieve better performance.
The backend configuration above is followed by an nginx example configuration for Windows:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:81;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /;
}
location /nginx_download/ {
internal;
alias "E:/arcaea_server/database/songs/"; # change to your actual path
# NOTE: slash at the end of alias is important
}
location /nginx_bundle_download/ {
internal;
alias "E:/arcaea_server/database/bundle/"; # change to your actual path
# NOTE: slash at the end of alias is important
}
}Tips
In the example above, the alias path must be changed to your actual path, and it must end with a slash /. The alias directive replaces the request path /nginx_download/ with the specified directory.
Remote Deployment
Remote deployment means the main server and the download server are not on the same machine. This is useful when you need to offload download traffic or when the main server has limited uplink bandwidth. Currently, the client is redirected to the remote URL with a 302 redirect, and compatibility may vary.
NGINX secure_link
nginx is a high-performance HTTP server that supports reverse proxying, load balancing, and more. Using the secure_link feature, the backend can generate a signed download URL and redirect the client to nginx for download via 302. This method works for both remote and single-host deployments. For more details, refer to the ngx_http_secure_link_module documentation.
On the main server, configure the backend as follows. Adjust download_link_host and bundle_download_link_host to match your download server address and port:
class Config:
HOST = '0.0.0.0'
PORT = 81
# USE_CORS = True
# USE_PROXY_FIX = True
DEPLOY_MODE = 'waitress'
REMOTE_DOWNLOAD_MODE = 'nginx'
REMOTE_DOWNLOAD_OPTIONS = {
'nginx': {
# nginx secure_link
'download_link_host': 'http(s)://<host>:<port>', # change to your actual address
'download_link_prefix': '/arcaea_server_download',
'bundle_download_link_host': 'http(s)://<host>:<port>', # change to your actual address
'bundle_download_link_prefix': '/arcaea_server_bundle_download',
'secret_key': 'nginx_secure_link_md5_secret_key',
}
}Although nginx is not required on the main server for this mode, it is still recommended. The main server nginx configuration is omitted here; below is an example nginx configuration for the download server:
server {
listen 80;
server_name _;
# ......
location /arcaea_server_download/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires|$uri nginx_secure_link_md5_secret_key";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
alias "E:/arcaea_server/v0.updating/database/songs/"; # change to your actual path
# NOTE: slash at the end of alias is important
}
location /arcaea_server_bundle_download/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires|$uri nginx_secure_link_md5_secret_key";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
alias "E:/arcaea_server/v0.updating/database/bundle/"; # change to your actual path
# NOTE: slash at the end of alias is important
}
}Tips
In the example above, the alias path must be changed to your actual path, and it must end with a slash /. The alias directive replaces the request path /arcaea_server_download/ with the specified directory.
For security reasons, in production it is recommended to change secret_key to a random and sufficiently strong string, and synchronize the same value into the download server nginx configuration at nginx_secure_link_md5_secret_key so the generated download links can be verified correctly.
S3 Presigned URL
If you do not want to maintain a separate download server, you can also store song files and content bundles in S3 or S3 API-compatible object storage, such as AWS S3, Cloudflare R2, MinIO, or S3-compatible services provided by other cloud vendors. The backend first validates the download token, download count, and expiration time using the existing logic, then generates a temporary S3 presigned URL and redirects the client to the object storage with a 302 response.
In this mode, the client will not receive your Access Key, and the bucket does not need public read access. The actual file traffic is handled by object storage. However, the main server still needs to keep local database/songs and database/bundle files, because the backend still depends on these local files to scan songs, calculate MD5 hashes, read content bundle metadata, and generate download lists.
Install the extra S3 dependency before enabling this mode:
pip install boto3The file paths in object storage must match the relative paths generated by the backend. Assume the configuration is:
'song_file_key_prefix': 'songs/',
'bundle_file_key_prefix': 'bundles/',The corresponding paths are:
| Local file | Object storage key |
|---|---|
database/songs/<song_id>/<file> | songs/<song_id>/<file> |
database/bundle/<relative_path> | bundles/<relative_path> |
For example, database/songs/dement/3.aff should be uploaded as songs/dement/3.aff. The .json, .cb, and split .cb files in content bundles also need to keep the same relative directory structure.
You can use AWS CLI or a compatible tool to synchronize files, so mismatches between the two sides are less likely to cause problems.
On the main server, configure the backend as follows:
class Config:
HOST = '0.0.0.0'
PORT = 81
DEPLOY_MODE = 'waitress'
REMOTE_DOWNLOAD_MODE = 's3'
REMOTE_DOWNLOAD_OPTIONS = {
's3': {
'endpoint_url': 'https://s3.your-cloud.com',
'aws_access_key_id': 'your_aws_access_key_id',
'aws_secret_access_key': 'your_aws_secret_access_key',
'config': {
'signature_version': 's3v4',
's3': {
'addressing_style': 'path'
}
},
'region_name': 'us-east-1',
'song_bucket_name': 'arcaea-resource',
'bundle_bucket_name': 'arcaea-resource',
'song_file_key_prefix': 'songs/',
'bundle_file_key_prefix': 'bundles/',
}
}Tips
song_bucket_name and bundle_bucket_name can be the same bucket, or they can point to two separate buckets. song_file_key_prefix and bundle_file_key_prefix can be changed as needed, but the actual object storage keys must be adjusted accordingly.
For AWS S3 or S3-compatible services, configure read-only permissions in the console. The bucket does not need to be publicly accessible unless your object storage service does not support presigned URLs.
DOWNLOAD_TIME_GAP_LIMIT and BUNDLE_DOWNLOAD_TIME_GAP_LIMIT affect both the backend token and the S3 presigned URL expiration time. If the time is too short, the client may receive an expired link under poor network conditions or while downloads are queued. If the time is too long, a leaked temporary link remains usable for longer. It is recommended to start with the default values and adjust them only after confirming that client downloads are stable.
Warning
Some S3-compatible services have different requirements for addressing_style, region name, or signature version. If downloads return 403, signature mismatch, or object-not-found errors, first check endpoint_url, region_name, addressing_style, bucket names, and whether the object key exactly matches the table above.