Self-hosted ftrack server location


These settings should only be used by advanced users with technical knowledge and are only available for local installations. Please contact ftrack support if you are looking to change them for a cloud hosted server.

By default, all files uploaded to the ftrack server are stored on the server and that storage is represented by the ftrack.server location. However, it is not always ideal to upload and store large files on the actual server itself since it may have limited storage space and bandwidth.

When running ftrack locally it can be useful to manage the ftrack.server location storage yourself. To do that you are required to setup a separate webserver that can act as a local file server. All files, including thumbnails and media in the web UI, are uploaded to and served from the local file server which gives better flexibility. A local file server allow you to store all files on a storage with better capacity and redundancy. It can also be used as a front to a more advanced geographical distribution of media to allow users fast access no matter what site they are working from.

How it works

When a component representing a file is created and added to the ftrack.server location either from the web UI or API, details about the file are sent to the server which responds with a put URL and headers that should be used when uploading the file. The file is then uploaded directly to that URL which can be either pointing to the main ftrack server or a local file server.

GET and REMOVE operations have their own endpoints to the server which if overridden will be redirected to the local file server instead.


Thumbnails in ftrack are regular components that are being passed through a cached on-demand image scaling service called Thumbor.

The thumbor scaling service runs together with your ftrack server.

When setting up your own local file server, Thumbor might not be able to access and convert components into thumbnails. The solution is setting up your own Thumbor service locally and configure the ftrack server to use it instead.

ftrack.thumbor_url = http://url-to-local-thumbor
ftrack.thumbor_security_key = SOME_SECRET_UUID

More information on how to setup Thumbor can be found in the Thumbor documentation.


It is important to configure the Thumbor service to use the same security key.


All requests to the local file server are signed with the ftrack service secret using a HMAC-SHA256 algorithm. This stops any unauthorized users from uploading and reading files from it.


To take advantage of the signature passed as a parameter you will need to implement logic yourself in the example below.

The signature can be calculated like this:

signature = base64.urlsafe_b64encode(


The security here is in the SERVER_SECRET which should be handled carefully and be a random secret of sufficient length.


The PUT URL needs to allow CORS (cross origin) requests due to how browsers work. The only way to work around that is to use the same domain for both the ftrack server and the overridden PUT URL which requires some kind of load balancing.

Media uploaded in the ftrack web UI will be automatically encoded if ffmpeg is installed on the server. If the ftrack.server location storage has been overridden this is no longer true and encoding would need to be handled and triggered in some other way such as listening to events.

The local file server needs to be accessible from the ftrack server for exports and annotations in review to work because those files are created on the ftrack server and needs to be sent to the local file server from there.

Example setup


This is an example. It is expected that the person setting it up have knowledge about Nginx, python and file management to be able to extend it into a production ready setup.

A webserver needs to be setup to handle the URLs and manage files in any way you want. The server should have three endpoints /put, /get and /remove. It could be a simple python server or anything you want as long as it can handle a file being uploaded and serving a file based on a component id.

Nginx can be used in front of a webserver to simplify things like CORS headers, uploads and downloads in an efficient way.

Here is an example configuration for Nginx running on port 9000 and a webserver running on port 9001. /put will write the body to a temporary file and set the header X-File to that path. The request will be proxied to the webserver on port 9001 which will look at the header and move the file to a permanent location. /get works in a similar way using headers and Nginx will take care of serving the actual file in an efficient way. All the webserver needs to do is to read the id argument, decide what file to return and set the path to that file as the X-Accel-Redirect header:

server {
    listen 9000;    location /put {        # Set headers to allow XHR requests to a different host.
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'PUT, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'content-type, content-md5, content-length, content-disposition';        if ($request_method = 'OPTIONS') {
            # Cache for 20 days.
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'PUT, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'content-type, content-md5, content-length, content-disposition';            return 204;
        }        # Temporary storage and file restrictions.
        client_body_temp_path      /path/to/temporary/folder;
        client_body_in_file_only   on;
        client_body_buffer_size    128K;
        client_max_body_size       1000M;        proxy_pass_request_headers on;
        proxy_set_header           X-File $request_body_file;
        proxy_set_body             off;
        proxy_redirect             off;
        proxy_pass       ;
    }    # Serve files using X-Accel-Redirect header in this location.
    location /path/to/storage {
        alias /path/to/storage;        # Set headers to allow XHR requests to a different host.
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET';
        add_header 'Access-Control-Allow-Headers' 'content-type, content-md5, content-length, content-disposition, ftrack-scope, X-Requested-With';
    }    # Proxy all other requests including /get
    location / {        # Set headers to allow XHR requests to a different host.
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST';
        add_header 'Access-Control-Allow-Headers' 'content-type, content-md5, content-length, content-disposition, ftrack-scope, X-Requested-With';        if ($request_method = 'OPTIONS') {
            # Cache for 20 days.
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST';
            add_header 'Access-Control-Allow-Headers' 'content-type, content-md5, content-length, content-disposition, ftrack-scope, X-Requested-With';            return 204;
        }        proxy_set_header        Host $host:$server_port;
        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_pass    ;

The Nginx configuration can be used together with the Flask example implemented here here.


This example is not complete and you are encouraged to add support for setting the correct content type etc. when retrieving files to ensure they display nicely when served to a browser.

Once the server is up and running you’ll need to update your ftrack.ini-file to include information about the media server. Do this by specifying the URL for the put, get and remove endpoints.

ftrack.component_put_url = http://some-url/put
ftrack.component_get_url = http://some-url/get
ftrack.component_remove_url = http://some-url/remove


After modifying ftrack.ini you need to restart the service to pick up the changes.


Modifying ftrack.ini is only possible for locally hosted customers. To enable this for cloud hosted customers please contact

Additional settings

You can also configure ftrack to pass additional parameters in the signed URL. This could prove useful if additional security checks are to be done on the local file server.

Currently the following parameters are available and are enabled by configuring the setting ftrack.extra_component_signature_params as a comma separated list in the ftrack.ini-file

The username of the currently logged in user or a empty string if there is no logged in user.

The review session invitee id for an open session or an empty string if not applicable.

When a ftrack user has visited a review session, both an user and invitee parameter will be present.

A utc unix timestamp, by default the timestamp will be set 24 hours in to the future relative to the current time. The Timeout can be can be controlled by setting the optionftrack.extra_component_signature_timeout in seconds.

For example, using the following configuration would include all available extra parameters with a timeout set to 10 minutes:

ftrack.extra_component_signature_timeout = 600
ftrack.extra_component_signature_params = user,invitee,timeout
Did this answer your question?