Python FastAPI + StorageVault (S3 Object Storage)
In this tutorial, we will create a Python FastAPI application that uses Pilvio StorageVault (S3-compatible object storage) for uploading and downloading files.
What We're Building
- FastAPI REST API with file uploads
- S3-compatible connection to Pilvio StorageVault
- Pre-signed URLs for secure file sharing
Prerequisites
- Pilvio account and API token (see overview)
- Python 3.11+
- Pilvio S3 keys (access key + secret key)
Step 1: Preparing StorageVault (S3)
Obtaining S3 Keys
# S3 kasutajainfo ja võtmete pärimine
curl "https://api.pilvio.com/v1/storage/user" \
-H "apikey: SINU_PILVIO_TOKEN" \
-X GET
In the response, you will find your accessKey and secretKey values in the s3Credentials array. If there are no keys, generate a new pair:
curl "https://api.pilvio.com/v1/storage/user/keys" \
-H "apikey: SINU_PILVIO_TOKEN" \
-X POST
Creating a Bucket
curl "https://api.pilvio.com/v1/storage/bucket" \
-H "apikey: SINU_PILVIO_TOKEN" \
-X PUT \
-d "name=minu-rakendus-failid" \
-d "billing_account_id=SINU_BILLING_ID"
Note: The bucket name must be globally unique across all Pilvio users.
Step 2: Creating and Preparing the VM
# VM loomine
curl "https://api.pilvio.com/v1/user-resource/vm" \
-H "apikey: SINU_PILVIO_TOKEN" \
-X POST \
-d "name=fastapi-server" \
-d "os_name=ubuntu" \
-d "os_version=24.04" \
-d "vcpu=2" \
-d "ram=2048" \
-d "disks=20" \
-d "username=deploy" \
-d "password=TurvalineParool123!" \
-d "public_key=ssh-ed25519 AAAA... sinu@arvuti"
After creating the VM and assigning a Floating IP (see the Node.js tutorial):
ssh deploy@SINU_FLOATING_IP
# Python ja pip paigaldamine
sudo apt-get update
sudo apt-get install -y python3-pip python3-venv
# Projekti ettevalmistamine
mkdir -p ~/fastapi-app && cd ~/fastapi-app
python3 -m venv venv
source venv/bin/activate
Step 3: Creating the FastAPI Application
pip install fastapi uvicorn python-multipart boto3 python-dotenv
Create the file main.py:
import os
from datetime import datetime
from contextlib import asynccontextmanager
import boto3
from botocore.config import Config
from dotenv import load_dotenv
from fastapi import FastAPI, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
load_dotenv()
# Pilvio StorageVault (S3) klient
s3_client = boto3.client(
"s3",
endpoint_url="https://s3.pilvio.com:8080",
aws_access_key_id=os.getenv("PILVIO_S3_ACCESS_KEY"),
aws_secret_access_key=os.getenv("PILVIO_S3_SECRET_KEY"),
config=Config(signature_version="s3v4"),
region_name="eu-east-1", # Pilvio ei nõua regiooni, aga boto3 vajab
)
BUCKET_NAME = os.getenv("PILVIO_S3_BUCKET", "minu-rakendus-failid")
app = FastAPI(title="Pilvio FastAPI + StorageVault")
app.add_middleware(
CORSMiddleware,
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health")
async def health():
return {"status": "ok", "timestamp": datetime.now().isoformat()}
@app.post("/api/v1/files/upload")
async def upload_file(file: UploadFile):
"""Laadi fail üles Pilvio StorageVault'i."""
if not file.filename:
raise HTTPException(400, "Failinimi puudub")
# Genereeri unikaalne võti
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
key = f"uploads/{timestamp}-{file.filename}"
try:
s3_client.upload_fileobj(
file.file,
BUCKET_NAME,
key,
ExtraArgs={"ContentType": file.content_type or "application/octet-stream"},
)
except Exception as e:
raise HTTPException(500, f"Üleslaadimine ebaõnnestus: {str(e)}")
return {"key": key, "bucket": BUCKET_NAME, "size": file.size}
@app.get("/api/v1/files")
async def list_files(prefix: str = "uploads/"):
"""Näita faile StorageVault bucketis."""
try:
response = s3_client.list_objects_v2(Bucket=BUCKET_NAME, Prefix=prefix)
files = [
{
"key": obj["Key"],
"size": obj["Size"],
"modified": obj["LastModified"].isoformat(),
}
for obj in response.get("Contents", [])
]
return {"files": files, "count": len(files)}
except Exception as e:
raise HTTPException(500, f"Failide loetelu ebaõnnestus: {str(e)}")
@app.get("/api/v1/files/download-url/{file_key:path}")
async def get_download_url(file_key: str, expires_in: int = 3600):
"""Genereeri eelsigneeritud allalaadimis-URL (vaikimisi kehtib 1 tund)."""
try:
url = s3_client.generate_presigned_url(
"get_object",
Params={"Bucket": BUCKET_NAME, "Key": file_key},
ExpiresIn=expires_in,
)
return {"url": url, "expires_in": expires_in}
except Exception as e:
raise HTTPException(500, f"URL-i genereerimine ebaõnnestus: {str(e)}")
@app.delete("/api/v1/files/{file_key:path}")
async def delete_file(file_key: str):
"""Kustuta fail StorageVault'ist."""
try:
s3_client.delete_object(Bucket=BUCKET_NAME, Key=file_key)
return {"deleted": file_key}
except Exception as e:
raise HTTPException(500, f"Kustutamine ebaõnnestus: {str(e)}")
Create the file .env:
PILVIO_S3_ACCESS_KEY=sinu-access-key
PILVIO_S3_SECRET_KEY=sinu-secret-key
PILVIO_S3_BUCKET=minu-rakendus-failid
ALLOWED_ORIGINS=https://sinu-domeen.ee
Step 4: Running the Application
During Development
uvicorn main:app --reload --host 0.0.0.0 --port 8000
In Production (systemd)
Create the file /etc/systemd/system/fastapi.service:
[Unit]
Description=FastAPI + StorageVault
After=network.target
[Service]
User=deploy
WorkingDirectory=/home/deploy/fastapi-app
Environment="PATH=/home/deploy/fastapi-app/venv/bin"
EnvironmentFile=/home/deploy/fastapi-app/.env
ExecStart=/home/deploy/fastapi-app/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now fastapi
Step 5: Testing
# Health check
curl http://SINU_FLOATING_IP:8000/health
# Faili üleslaadimine
curl -X POST http://SINU_FLOATING_IP:8000/api/v1/files/upload \
-F "file=@dokument.pdf"
# Failide loetelu
curl http://SINU_FLOATING_IP:8000/api/v1/files
# Allalaadimis-URL
curl http://SINU_FLOATING_IP:8000/api/v1/files/download-url/uploads/20250211-120000-dokument.pdf
Using the S3 API Directly (boto3 Client or AWS CLI)
Pilvio StorageVault is S3-compatible, so AWS CLI works as well:
# Seadista AWS CLI Pilvio jaoks
aws configure set aws_access_key_id SINU_ACCESS_KEY
aws configure set aws_secret_access_key SINU_SECRET_KEY
# Failide loetelu
aws s3 ls s3://minu-rakendus-failid/ --endpoint-url https://s3.pilvio.com:8080
# Faili üleslaadimine
aws s3 cp fail.txt s3://minu-rakendus-failid/ --endpoint-url https://s3.pilvio.com:8080
StorageVault API Management
# Bucketi info
curl "https://api.pilvio.com/v1/storage/bucket?name=minu-rakendus-failid" \
-H "apikey: SINU_PILVIO_TOKEN"
# Kõik bucketid
curl "https://api.pilvio.com/v1/storage/bucket/list" \
-H "apikey: SINU_PILVIO_TOKEN"
# S3 võtmete haldamine
curl "https://api.pilvio.com/v1/storage/user/keys" \
-H "apikey: SINU_PILVIO_TOKEN"
Next steps: Combine StorageVault file storage with a React SPA frontend or add a PostgreSQL database for metadata.