FastAPI+Svelte
This example assumes you have already created your own Territory. If you have not, please refer to this guide.
In this tutorial we will be deploying our example application to CitadelHosts. We will upload the images that define our application to our Smart Image Registry. Then we will define our custom application in CitadelHosts. Finally, we will deploy that application to our own Territory instance.
Our Example Application
This example application features a FastAPI backend, a Svelte frontend, and a super light LLM, Qwen3.5-0.8B packaged in a llama.cpp image. The application allows you to point the backend to any OpenAI compatible inference API. The Qwen3.5-0.8B model is packaged in the example to highlight the fact that very basic inference can be run even on under 2GB of RAM on the CPU. The model will run under this resource constraint but it will run very slowly still with just a single server CPU running the inference and is not really the recommended way to interact with an LLM on this platform.
The application is available on GitHub at: https://github.com/LiamJFitzpatrick/citadel-fastapi-svelte-example
Uploading Custom Images To Your Smart Registry
The example application consists of three custom images that need to be uploaded to the Smart Image Registry. The first image is the FastAPI backend defined at ./backend/Dockerfile. The second is the Svelte frontend defined at ./frontend/Dockerfile. The third image for the Qwen3.5 model is defined at ./Dockerfile.qwen3.5-08b.
Using GitHub Actions
An example deploy workflow is provided below. This will build the necessary images and upload them to your CitadelHosts account. You can clone the example repository and then push the code to your own GitHub repository. Whenever changes are pushed to your GitHub repository they will be automatically sent to your CitadelHosts registry. This is great to be able to enable automatic deployments.
.github/workflows/deploy.yml
name: Build and Push Container Images
on:
push:
branches:
- develop
- main
- master
tags:
- 'v*'
env:
REGISTRY: registry.citadelhosts.com
SVELTE_IMAGE_NAME: ${{ secrets.SVELTE_IMAGE_NAME }}
FASTAPI_IMAGE_NAME: ${{ secrets.FASTAPI_IMAGE_NAME }}
LLM_IMAGE_NAME: ${{ secrets.LLM_IMAGE_NAME }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to private registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata for Svelte app
id: svelte-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.SVELTE_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Extract metadata for FastAPI
id: fastapi-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.FASTAPI_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Extract metadata for LLM
id: llm-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.LLM_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Svelte app image
uses: docker/build-push-action@v6
with:
context: .
file: ./frontend/Dockerfile
push: true
tags: ${{ steps.svelte-meta.outputs.tags }}
labels: ${{ steps.svelte-meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push FastAPI image
uses: docker/build-push-action@v6
with:
context: .
file: ./backend/Dockerfile
push: true
tags: ${{ steps.fastapi-meta.outputs.tags }}
labels: ${{ steps.fastapi-meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push LLM image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.qwen3.5-0.8b
push: true
tags: ${{ steps.llm-meta.outputs.tags }}
labels: ${{ steps.llm-meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
This deploy workflow requires the following secrets in your repository:
- SVELTE_IMAGE_NAME: This is the name that the Svelte frontend will have in your CitadelHosts registry.
- FASTAPI_IMAGE_NAME: This is the name that the FastAPI backend will have in your CitadelHosts registry.
- LLM_IMAGE_NAME: This is the name that the llama.cpp server will have in your CitadelHosts registry.
- REGISTRY_USERNAME: This is your CitadelHosts username.
- REGISTRY_PASSWORD: This is your CitadelHosts password.
Using Docker CLI
Getting and Building The Application
After you have cloned the repository, navigate into the newly created folder.
git clone https://github.com/LiamJFitzpatrick/citadel-fastapi-svelte-example.git
cd citadel-fastapi-svelte-example
Build the FastAPI backend image, the Svelte frontend image, and the llama.cpp bundle with Qwen3.5-08B image.
docker build -t registry.citadelhosts.com/fastapi-example-backend:latest ./backend/
docker build -t registry.citadelhosts.com/svelte-example-frontend:latest ./frontend/
docker build -t registry.citadelhosts.com/llm-example:latest -f ./Dockerfile.qwen3.5-0.8b ./
Authenticate your Docker CLI with the CitadelHosts.com Smart Image Registry. You will login using the same credentials you use to login to CitadelHosts.com.
docker login registry.citadelhosts.com
Push your newly built images to your registry.
docker push registry.citadelhosts.com/fastapi-example-backend:latest
docker push registry.citadelhosts.com/svelte-example-frontend:latest
docker push registry.citadelhosts.com/llm-example:latest
Congrats! You have successfully uploaded the example application to your CitadelHosts account!
Defining Custom Applications
To define a custom application navigate to the Apps page and scroll down to the Create Application section (or click this link: https://citadelhosts.com/dashboard/apps#create-application).
This form allows you to define custom application configurations.
Step 1: Application Definition
The first step is to define the application. The table below shows suggested input values for our example.
| Label | Value | Description |
|---|---|---|
| Name | FastAPI+Svelte Example | This is the name of your application and will appear in your App Library |
| Description | An example LLM chat interface built with FastAPI and Svelte. | A description for your custom application. |
Step 2: Container Definition
The second step is to define the containers that will make up our application. Our example application consists of 3 containers, so you can hit Add Container for 3 containers. The suggested inputs are summarized in the tables below.
Container 1 Definition: FastAPI Backend
| Label | Value |
|---|---|
| Name: | backend |
| Start Order: | 2 |
| Image: | fastapi-example-backend:latest |
Container 2 Definition: Svelte Frontend
| Label | Value |
|---|---|
| Name: | frontend |
| Start Order: | 3 |
| Image: | svelte-example-frontend:latest |
Container 3 Definition: Llama.cpp Server
| Label | Value |
|---|---|
| Name: | llama |
| Start Order: | 1 |
| Image: | llm-example:latest |
Step 3: Container Configuration
The final step in defining your custom application is going to be to configure ports, volumes, and environment variables for each of the containers that make up your application. The necessary configuration for our example application is summarized in the sections below.
frontend Configuration
| Ports | |
|---|---|
| Container Port: | 80 |
Environment Variables:
| Key | Value |
|---|---|
| BACKEND_URL | http://127.0.0.1:8000 |
Finishing Up
Now that you have defined your application in the form, you just need to hit Create. You have succesfully defined your own custom LLM chat interface application on CitadelHosts! This application is available just to your account and can be deployed to any Territory of your choosing.
Deploying Custom Applications
Deploying custom applications is just as easy as deploying pre-configured applications. All one has to do is select the Territory you would like to deploy the application on and hit Deploy! Start the app up and navigate to your access link to view your own custom application. Great work!