Proof of conceptScaleway fr-parSeptember–October 2026

LocalChat on Scaleway

A self-hosted RAG application, stood up on a European cloud from nothing, verified end to end, and torn down again — six times, for about two and a quarter euros.

€2.25total cost
4commands to deploy
6build-and-destroy cycles
2.99 GBapplication image

Why this exists

Scaleway is a European cloud provider — French-owned, operating data centres in Paris, Amsterdam and Warsaw under EU jurisdiction. For organisations whose sovereignty requirements demand a European infrastructure provider, that makes it one of the few alternatives to hosting everything themselves. Self-hosting is the safe answer to those requirements and also the expensive one: hardware, patching, backups, and someone on call. The question this proof of concept asks is whether a sovereign cloud can carry that load instead. It tests three things: how far deployment can be automated, how billing behaves, and how easy the platform is to work with.

The application under test is LocalChat — a self-hosted RAG application that had only ever run on a workstation and in Docker. Running it there says nothing about running it on someone else's infrastructure. So the test is not whether it can be made to run on Scaleway once, by hand, but whether the entire stack can be deployed automatically, from nothing, by scripts, and taken down the same way.

The answer is yes, with conditions. The stack — application container, PostgreSQL with pgvector, and a model host on a private network — has been built from an empty project and destroyed again six times, each cycle scripted end to end, for about two and a quarter euros in total. What it needed to get there:

The strong points

Idle costs little: the container is pinned to one instance, and the cheapest database option scales to zero — though the current version of the application needs the managed one, which bills by the hour (see below). Nothing in the product was rewritten to fit the platform. The cheap part of the stack — everything but a GPU — is cents per hour, so a mistake costs a rebuild, not a bill. And what the scripts encode is now reusable: the same commands, with prefixed and defaulted settings, would stand the stack up in another account.

The attention points

Nothing stops spend automatically; a budget alert lags the invoice, so the brake is discipline plus a script. Encryption to the database is structural — an unencrypted connection cannot even name its target. The managed environment exposes assumptions a workstation covers: a health check that never checked, a retrieval path that silently stores nothing without its model host. Diagnosis on a managed instance needs preparation — console and key — before the failure, not after. And the one expensive component, a GPU, was scarce on the day it was checked; a plan that assumes it is available on demand is a plan that waits.

The rest of this page is the summary of those cycles. The two pages behind it are the evidence: the log of every session, and the scripts exactly as they run.

What was built

LocalChat lets people upload documents and ask questions about them, with retrieval over a vector database and a locally hosted language model. This proof of concept answers one question: can it run on managed cloud infrastructure without changing what the product is?

It can. The stack is a Serverless Container running the application, a managed PostgreSQL database with pgvector for retrieval, and a small Instance serving the models over a private network. No component was rewritten to fit the platform.

The first five cycles used Scaleway's Serverless SQL Database. The sixth, on 6 October, found that the current version cannot run on it any more: the application now enforces workspace isolation inside the database, which needs a database role that the serverless offering does not allow its users to create. Scaleway's managed PostgreSQL allows it — and now supports pgvector, which it did not when the serverless option was chosen.

ComponentServiceNotes
ApplicationServerless Container3 GB, one instance, no autoscaling
DatabaseManaged PostgreSQL 16 (DB-DEV-S)pgvector 0.8.2, bills hourly. Serverless SQL served cycles one to five
EmbeddingsCPU Instance running OllamaReachable only over a private network
Text generationCPU Instance, same host as embeddingsWorks, slowly: a 1B model answers in 24–36 s. A GPU is the open decision

How to deploy it

Four commands. All of them are idempotent: running one twice does nothing the second time. They were written after deploying once by hand, so they encode what actually worked rather than what the documentation predicted.

bash   scripts/scaleway/provision.sh          # project, database, scoped credentials
bash   scripts/scaleway/deploy_container.sh   # the application
python scripts/scaleway/verify_deployment.py <endpoint>
bash   scripts/scaleway/deploy_embeddings.sh  # the embedding model host

Every step talks to Scaleway through its official command-line tool, the Scaleway CLI (scw): no console clicks and no Terraform state to keep. A script that is just CLI calls can be read top to bottom as the procedure it performs, and run against a fake scw in the test suite, which is how its decisions are checked without a live account. The scripts are in the public repository, under scripts/scaleway.

The third command is a gate rather than a checklist. It signs in, confirms the deployed image is the version you think it is, ingests a document and retrieves it with a query that shares no words with the text — so a passing result can only come from the vector search actually working. It exits non-zero on failure.

Stopping the costs

The platform has no spend cap at any level, so the teardown is a script rather than a habit:

PROJECT_ID=<project> bash scripts/scaleway/panic_teardown.sh                  # shows what would go
PROJECT_ID=<project> CONFIRM=DESTROY bash scripts/scaleway/panic_teardown.sh  # stops it

It deletes rather than stops, because a stopped machine keeps billing for its disks and its reserved address. It refuses to touch anything outside the project it was given.

What the deployment disproved

Four things the plan believed turned out to be wrong, and finding them is most of the value of running a proof of concept at all.

Retrieval does not work without the model host

The plan assumed a first pass without any language model would still validate document upload and search. It does not: every document chunk is embedded through the model host, so with none reachable nothing is stored at all. The fix was not an expensive GPU — embeddings alone run acceptably on a small CPU machine, at roughly two cents an hour.

Encryption to the database is structural, not optional

The managed database selects which database you reach from the encrypted handshake itself. An unencrypted connection cannot name its target, so it fails with a confusing error rather than a security warning. The application had never made this setting explicit; it does now.

A health check that never checked

The application's health endpoint reported the database as healthy for the life of the process, because it echoed a flag recorded at startup rather than asking the database anything. On a server that is always running, this behaves like correct code indefinitely. On a database that scales to zero, it reports green while every request fails.

This was a latent defect, not a platform requirement — the cloud only made it visible. That is the most transferable lesson here: when moving to managed infrastructure, look for the assumptions an always-present environment was quietly covering.

A security layer that only worked for an administrator

Workspace isolation inside the database switches every request into a restricted role. On a workstation and in the test pipeline the application connects as the database's administrator, who may switch into any role without being granted it — so every test passed. On the managed database the application is an ordinary user, and the grant that should have let it switch did not. Found by deploying, fixed the same day; the same lesson as the health check, one layer further down.

What it cost

About two and a quarter euros for the entire exercise — database, application container, model host, private networking, stood up and torn down six times. The sixth cycle, on a managed database, cost 24 cents. Most of it went to one stack that was left standing for two days between sessions. The figure matters less than the shape behind it:

The sequencing that made this cheap: prove the plumbing on a two-cent machine, so that when an expensive one is finally switched on it has exactly one question left to answer.

Where it stands

The document path — upload, embed, store, retrieve — works on this infrastructure and has been verified on every cycle. Text generation has been run on the CPU host: the answer is correct and cites the source, but at half a minute to the first word. On 6 October the stack was handed over for hands-on testing, and that settled it: on a CPU it is too slow to test the product properly.

The next cycle runs on a GPU. A GPU instance beside the CPU host, at €0.787 per hour while it runs, built for a two-hour session, measured — under five seconds to the first word, with an answer that uses its source — and torn down. Before it, the provisioning script moves from the serverless database to the managed one. The alternative, a hosted model API, is cheaper to run and a change to what the product is rather than to how it is deployed.

The stack is currently torn down. It rebuilds from the four commands above.

The record and the code

This page is the summary. The two behind it are the evidence: every session's log entry as kept in the repository, and the scripts exactly as they run — written with prefixed, defaulted settings and no account-specific values, so they can be adapted to another account or another project without rewriting them. All of it — the application, the scripts, their tests and the full deployment guide — is public at github.com/jwvanderstam/LocalChat.