File Storage Providers¶
Apilane supports four file storage providers for uploaded files. Files can be stored on the local server file system or in cloud object storage.
The provider is a setting of the API server (FileStorage): it applies to every application on that server, and the files of an application are kept apart by its token ({applicationToken}/files/{fileUID}). Changing the provider does not move existing files (see Migration).
Delete and Rebuild
Deleting or rebuilding an application removes only the files in the API server's own FilesPath folder. Objects in a cloud bucket or container stay: delete the {applicationToken}/ prefix yourself.
What Apilane manages
Apilane handles file upload, download, deletion, and metadata tracking through the Files system entity. The choice of storage provider determines where file binaries are physically stored.
Local File System¶
Best for: Getting started, prototyping, single-server deployments.
No additional configuration is required beyond the FilesPath setting, which every API server needs. Apilane stores uploaded files directly on the API server's file system, in {FilesPath}/{applicationToken}/files/.
Configuration:
"FileStorage": {
"Provider": "LocalFileSystem"
}
| Pros | Cons |
|---|---|
| Zero cloud account setup | Requires persistent volumes in Docker/Kubernetes |
| No additional cost | Not suitable for multi-region deployments |
| Simple deployment | Limited scalability |
Docker/Kubernetes deployments
You must mount a persistent volume that contains the FilesPath directory to prevent file loss when containers restart. The compose file in Deployment sets FilesPath=/etc/apilanewebapi/Files and mounts the volume at /etc/apilanewebapi; see it for volume mapping guidance.
Google Cloud Storage (GCS)¶
Best for: Applications deployed on Google Cloud Platform, scalable cloud storage.
Stores files in a Google Cloud Storage bucket. Requires a service account with Storage Object Admin permissions.
Configuration:
"FileStorage": {
"Provider": "GoogleCloudStorage",
"ConnectionString": "/run/secrets/gcs-sa.json",
"BucketName": "my-app-files-bucket"
}
| Parameter | Description |
|---|---|
ConnectionString |
Path to service account JSON file (absolute path inside the container) |
BucketName |
GCS bucket name (must already exist) |
Setup Steps¶
- Create a GCS bucket in your Google Cloud project
- Create a service account with
Storage Object Adminrole on the bucket - Download the service account JSON key
- Mount the JSON file as a secret in Docker/Kubernetes:
# Kubernetes Secret example
apiVersion: v1
kind: Secret
metadata:
name: gcs-credentials
type: Opaque
stringData:
gcs-sa.json: |
{
"type": "service_account",
"project_id": "my-project",
"private_key_id": "...",
...
}
---
# Mount in Deployment
volumes:
- name: gcs-secret
secret:
secretName: gcs-credentials
volumeMounts:
- name: gcs-secret
mountPath: /run/secrets
readOnly: true
Service account file required
The provider reads the service account JSON file named in ConnectionString: Workload Identity and application default credentials are not supported. Mount the key as a secret, as above.
AWS S3¶
Best for: Applications deployed on AWS, S3-compatible storage (Backblaze B2, MinIO).
Stores files in an Amazon S3 bucket or S3-compatible storage.
Configuration:
"FileStorage": {
"Provider": "AwsS3",
"ConnectionString": "accessKeyId=AKIA...;secretAccessKey=...;region=us-east-1",
"BucketName": "my-app-files-bucket"
}
| Parameter | Description |
|---|---|
ConnectionString |
Format: accessKeyId={key};secretAccessKey={secret};region={region}, or accessKeyId={key};secretAccessKey={secret};endpoint={host} for S3-compatible storage. The names are not case-sensitive and both keys are required |
BucketName |
S3 bucket name (must already exist) |
Setup Steps¶
- Create an S3 bucket in your AWS account
- Create an IAM user with
s3:PutObject,s3:GetObject,s3:DeleteObjectpermissions on the bucket - Generate access keys for that user
- Set connection string via environment variables or appsettings
# Docker environment variable example (the other settings every API server needs, Url, PortalUrl, FilesPath and InstallationKey, are left out)
docker run -e "FileStorage__ConnectionString=accessKeyId=AKIA...;secretAccessKey=...;region=us-east-1" \
-e "FileStorage__BucketName=my-app-files-bucket" \
-e "FileStorage__Provider=AwsS3" \
raptis/apilane:api-{version}
Access keys required
Both keys are required: IAM roles of EC2/EKS are not supported. Create an IAM user limited to the bucket and keep its keys in a secret.
S3-Compatible Storage (Backblaze B2, MinIO)¶
For S3-compatible providers, use the endpoint parameter with the host name only (no https://). The connection always uses HTTPS and path-style addresses, so a MinIO server needs TLS:
"ConnectionString": "accessKeyId=...;secretAccessKey=...;endpoint=s3.us-west-004.backblazeb2.com"
Azure Blob Storage¶
Best for: Applications deployed on Microsoft Azure.
Stores files in an Azure Blob Storage container.
Configuration:
"FileStorage": {
"Provider": "AzureBlobStorage",
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=...;EndpointSuffix=core.windows.net",
"BucketName": "my-container-name"
}
| Parameter | Description |
|---|---|
ConnectionString |
Azure Storage Account connection string |
BucketName |
Azure Blob container name (must already exist) |
Setup Steps¶
- Create an Azure Storage Account
- Create a Blob container in the storage account
- Copy the connection string from the Azure Portal (Access Keys section)
- Set connection string via environment variables or appsettings
# Docker environment variable example (the other settings every API server needs, Url, PortalUrl, FilesPath and InstallationKey, are left out)
docker run -e "FileStorage__ConnectionString=DefaultEndpointsProtocol=https;AccountName=...;AccountKey=..." \
-e "FileStorage__BucketName=my-container-name" \
-e "FileStorage__Provider=AzureBlobStorage" \
raptis/apilane:api-{version}
Connection string required
The storage account connection string is required: Managed Identity is not supported. Keep the connection string in a secret.
Choosing a Provider¶
| Criteria | LocalFileSystem | GoogleCloudStorage | AwsS3 | AzureBlobStorage |
|---|---|---|---|---|
| Setup complexity | None | Moderate | Moderate | Moderate |
| Cost | Free (uses server disk) | Pay per GB stored + requests | Pay per GB stored + requests | Pay per GB stored + requests |
| Scalability | Limited | High | High | High |
| Multi-region | No | Yes | Yes | Yes |
| Best for | Dev / Small apps / Single server | Google Cloud deployments | AWS deployments / S3-compatible storage | Azure deployments |
Security Considerations¶
- Never commit credentials to source control. Use environment variables, Docker secrets, or Kubernetes secrets.
- Static credentials only: the providers take an access key pair, a service account JSON file or a connection string. Managed identities (IAM roles, Workload Identity, Azure Managed Identity) are not supported, so scope each credential to the one bucket or container.
- Bucket/container permissions: Restrict access to only the API service account. Do not make buckets public unless required.
- Rotate credentials regularly and use least-privilege IAM policies.
See Security Considerations for more details on credential management.
Migration¶
To migrate from LocalFileSystem to a cloud provider:
- Upload existing files: copy the content of
{FilesPath}/{applicationToken}/files/of each application to the key prefix{applicationToken}/files/in your bucket or container, using the provider's CLI or SDK. Leave out the SQLite database file ({applicationToken}.db) that sits next to that folder - Preserve the file structure:
{applicationToken}/files/{fileUID} - Update
FileStorageconfiguration to point to the cloud provider - Restart the API service
- Verify file downloads still work
Migration is manual
Apilane does not provide an automated migration tool. You must manually transfer files to maintain the same file structure ({appToken}/files/{fileUID}).