FastAPI serving static files through symlinks
Asked Answered
A

2

1

I have mounted the static directory in my FastAPI app using the following code:

from fastapi.staticfiles import StaticFiles

app = FastAPI(
    title="Title of the Application",
    description="Over all description of the application")
app.mount("/public", StaticFiles(directory='public'), name='public')

If I have a symlink pointing to a path outside the app folder, e.g.

/home/xyz/app/main.py
/home/xyz/app/index.html
/home/xyz/app/public/data -> /home/xyz/static/whatever.tgz

The FastAPI application can recognize the URL xyz.com/public/index.html, but it can't recognize xyz.com/public/data.

Is this doable? Unfortunately, I cannot use FileResponse due to the blob size being too large. I want to return the file with a simple link somehow.

Abramson answered 10/1, 2022 at 12:49 Comment(0)
B
1

Update

Starlette has recently added the follow_symlink parameter in StaticFiles class, which is a boolean indicating if symbolic links for files and directories should be followed—by default, this value is set to False. One could set this to True, and hence, every symbolic link in the directory path should be followed. Example:

app.mount("/static", StaticFiles(directory="static", follow_symlink=True), name="static")

Given that there is a symlink called data in your static directory, you could then access, for instance, http://localhost:8000/static/data/image.png directly from your browser, or in your Jinja2 template, you could request files as follows:

<img src="{{ url_for('static', path='data/image.png')}}" width="50%">

Original Answer

It is doable, as long as you mount a StaticFiles instance on that specific path as well. For example:

app.mount("/static", StaticFiles(directory="static"), name="static")
app.mount("/symlink", StaticFiles(directory="static/data"), name="publicsym")

Then, in your Jinja2 template you could request files as follows:

<link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
<img src="{{ url_for('symlink', path='/image.png')}}" width="50%">

or, if there is an images sub-directory inside data:

<img src="{{ url_for('symlink', path='images/image.png')}}" width="50%">
Blight answered 11/1, 2022 at 7:4 Comment(4)
What you posted works, thanks. Is it possible to somehow generate symlinks on the fly and then mount them? This option has a small security flaw that anyone with the link can access the files.Abramson
thats... annoying. Is there a way to force it to pick up those paths or defind the second one as ("public/data", StaticFiles(...))Claudelle
^ update, this does work. Just have to define nested/deeper paths BEFORE the root one. Mount those first.Claudelle
@Claudelle Please have a look at the recent update above.Blight
C
1

It was updated in Starlette 0.24.0 (Feb 2023) that StaticFiles() has a new parameter follow_symlink=True to support symlink.

Cloudlet answered 4/4 at 21:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.