# zaneops.dev Full Documentation # Authentication All API requests require a session `Cookie`, which you get when you login to the app. For mutative requests (`DELETE`, `POST`, `PUT`, `PATCH`), you need add a `csrftoken` to the cookie header and the same value need to be sent as a header `X-CSRFToken`. ## Get a session cookie To get a session cookie, you need to login, then get the cookie in `sessionid`. ```http "sessionid=tvmt1xp0c2ep33htukqm140fb4igkz4u;" {" Here is the session cookie:":13} {5-8} ### Request POST /api/auth/login HTTP/1.1 Content-Type: application/json { "username": "", "password": "" } ### Response HTTP/1.1 201 Created Content-Type: application/json Set-Cookie: sessionid=tvmt1xp0c2ep33htukqm140fb4igkz4u; Domain=.127-0-0-1.sslip.io; expires=Wed, 24 Jul 2024 16:49:05 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax { "id": 2, "name": "New Resource Name", "description": "New Resource Description" } ``` ## Perform an authorized Request ```http {3} ### Request GET /api/auth/me HTTP/1.1 Cookie: sessionid=tvmt1xp0c2ep33htukqm140fb4igkz4u; ### Response HTTP/1.1 201 Created Content-Type: application/json { "user": { "username": "fredkiss3", "first_name": "", "last_name": "" } } ``` ## Perform a mutative request To perform a mutative request i.e `POST`, `PUT`, `PATCH`, `DELETE` requests, you need to follow 2 steps : 1. Obtain a csrf token : ```http "csrftoken=zydcEbNXQGJFxzLphKEO8Mg88VdEwi8c;" {" Here is the CSRF Token:":6} ### Request GET /api/csrf HTTP/1.1 ### Response HTTP/1.1 200 OK Set-Cookie: csrftoken=zydcEbNXQGJFxzLphKEO8Mg88VdEwi8c; expires=Wed, 09 Jul 2025 17:03:09 GMT; Max-Age=31449600; Path=/; SameSite=Lax ``` 2. Then add the `csrftoken` both in the cookie and in `X-Csrftoken` header : ```http {4-5} ### Request POST /api/projects HTTP/1.1 Content-Type: application/json Cookie: sessionid=tvmt1xp0c2ep33htukqm140fb4igkz4u; csrftoken=zydcEbNXQGJFxzLphKEO8Mg88VdEwi8c; X-Csrftoken: zydcEbNXQGJFxzLphKEO8Mg88VdEwi8c { "slug": "sandbox" } ### Response HTTP/1.1 201 Created Content-Type: application/json { "description": null, "id": "prj_GxCy6Tg35ax", "slug": "sandbox-2", "created_at": "2024-07-10T17:05:56.276194Z", "updated_at": "2024-07-10T17:05:56.276180Z" } ``` # Introduction ## Common Errors status codes ### 405 Method Not Allowed This is returned when an endpoint is called with an unexpected http method. For example, if updating a user requires a POST request and a PATCH is issued instead, this error is returned. Here's how it looks like: ```json { "type": "client_error", "errors": [ { "code": "method_not_allowed", "detail": "Method “patch” not allowed.", "attr": null } ] } ``` ### 406 Not Acceptable This is returned if the `Accept` header is submitted and contains a value other than `application/json`. Here's how the response would look: ```json { "type": "client_error", "errors": [ { "code": "not_acceptable", "detail": "Could not satisfy the request Accept header.", "attr": null } ] } ``` ### 415 Unsupported Media Type This is returned when the request content type is not json. Here's how the response would look: ```json { "type": "client_error", "errors": [ { "code": "not_acceptable", "detail": "Unsupported media type “application/xml” in request.", "attr": null } ] } ``` ### 500 Internal Server Error This is returned when the API server encounters an unexpected error. Here's how the response would look: ```json { "type": "server_error", "errors": [ { "code": "error", "detail": "A server error occurred.", "attr": null } ] } ``` # Architecture import { ASSETS_SERVER_DOMAIN } from "astro:env/client" import {Steps, Aside} from '@astrojs/starlight/components'; ZaneOps is a self-hosted PaaS platform designed to manage, deploy, and monitor services with [docker swarm](https://docs.docker.com/engine/swarm/). Each service and app deployed on ZaneOps correspond one-to-one to a [swarm service]((https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/)). ## Components Main architecture **🔌 Proxy (`caddy`)** Acts as the single entrypoint for all HTTP traffic. Routes API and service requests appropriately and serves static assets. **🧠 App (Backend + Frontend)** - **Backend**: Django + Django REST Framework - **Frontend**: Single Page App (SPA) made with React Router - Provides the user interface and the core API logic. **⚙️ Workers** - Run scheduled/background jobs. - Use the same Docker image as the main app. **🧾 Log Collector (`fluentd`)** - Aggregates all logs from running services. - Collects logs from proxy for [HTTP logs](/screenshots/#http-logs-page). **🔍 Log Searcher (`grafana/loki`)** - Stores and indexes logs for querying. **⚡️ Cache (`valkey`)** - Used for caching and session storage. **🗃️ Database (`PostgreSQL`)** - Stores all persistent application data. **📬 Task Queue (`temporal`)** - Orchestrates background tasks and worker coordination. ## Core Scenarios ### 1. Deploy a New Service Initial service deploy scenario #### Step-by-Step 1. **User Action**: `PUT /deploys/XYZ` is sent to the proxy. 2. **Routing**: The proxy forwards it to the app backend. 3. **App Logic**: App creates a new deployment record in the database with status `PENDING`. 4. **Task Queue**: App sends a `deploy_service(XYZ)` message to the task queue (Temporal). 5. **Worker Execution**: A worker picks up the task and runs the deployment logic (Docker service creation). 6. **Completion**: Worker notifies the task queue that the task is done. 7. **State Update**: Worker updates the Deployment state in the DB to `HEALTHY` or `FAILED`. 8. **Proxy Mapping**: The proxy maps `xyz.com` to the new service, e.g., `service_XYZ:3000`. ### 2. Deploy the same service again Redeploy service scenario #### Step-by-Step 1. **User Action**: `PUT /deploys/XYZ` sent again. 2. **App Processing**: The app creates a new deployment version and sends a deploy task. 3. **Worker Logic**: * Stops (removes) the previous Docker service (v1). * Starts a new one with the updated spec (v2). 4. **State Update**: DB updated accordingly (`HEALTHY` or `FAILED`). 5. **Proxy Keeps Same Mapping**: `xyz.com` still points to `service_XYZ`, which now resolves to the new container. ### 3. Access a Running Service Access service scenario #### Step-by-Step 1. **User Request**: Browser makes `GET xyz.com`. 2. **Proxy Resolution**: Proxy resolves the domain to the correct internal service (Docker alias or internal hostname). 3. **Routing**: The request is forwarded to the running container. 4. **Response**: Container sends back the HTTP response via the proxy. ### 4. Logs Collection Log collection scenario #### Step-by-Step 1. **Logs Emitted**: Each service sends logs to Fluentd over `stdout`. 2. **Collector Buffering**: Fluentd waits ~5 seconds and tags/filters logs. 3. **Forward to App**: Logs are forwarded to the API `/logs/ingest`. 4. **App Preprocessing**: Enriches logs (adds metadata like service/deployment IDs). 5. **Send to Loki**: App sends structured logs to Loki. ### 5. Logs Search Log search scenario #### Step-by-Step 1. **User Request**: `GET /search/logs` hits the proxy. 2. **Routing**: Proxy forwards to the app backend. 3. **Query Execution**: App translates filters and queries Loki. 4. **Return**: Logs are returned to the frontend (paginated, filtered, etc.). # ZaneOps v1.0 27 Feb 2025 by [**Fred KISSIE**](https://github.com/Fredkiss3) ZaneOps v1.0 is finally here! ZaneOps is a beautiful, self-hosted, open-source platform for hosting static sites, web apps, databases, services (like **Umami**, **WordPress**, **Supabase**), workers, or anything else you need—whether you’re launching a startup or managing an enterprise. Today, ZaneOps is stable and production-ready. ## Install ZaneOps Installation steps are detailled on the [installation page](/installation), but here is the TLDR: ```shell # create directory to install zaneops mkdir -p /var/www/zaneops && cd /var/www/zaneops # download zaneops CLI curl https://cdn.zaneops.dev/makefile > Makefile # setup zaneops make setup # start zaneops app make deploy ``` ## Why ZaneOps exists ? The goal of ZaneOps is to bring together the best features we could ~~steal~~ take inspiration from popular platforms like **Vercel**, **Railway**, and **Render**, while giving you full ownership of your data and complete control over your server costs. ## Features ### Deploying Services from Docker Images