Projects

What runs on my platform, or is coming next. Every application runs in its own containers and is reachable only through Traefik.

  • 2026in progress

    odabas.ch

    This site: built statically with Astro, served from an nginx container and published through Traefik. Every push to main builds and deploys it automatically.

    • Astro
    • Docker
    • nginx
    • Traefik
    • GitHub Actions
  • 2026running

    VPS platform

    Docker, Traefik, Certbot and shared databases on my own server, versioned as infrastructure as code.

    • Docker
    • Traefik
    • nginx
    • MariaDB
  • 2026planned

    Spring Boot + Angular

    A full-stack application with a REST API and a single-page frontend, in separate containers behind the same reverse proxy.

    • Java
    • Spring Boot
    • Angular
    • PostgreSQL
  • 2026planned

    Python app

    A second language on the same platform: one container per app and routing through Traefik are not tied to Java.

    • Python
    • Docker
    • PostgreSQL

The platform behind it

One VPS, Docker with one container per service, and Traefik as the single entry point. Certbot runs directly on the host.

Platform architectureA browser calls Traefik, the single entry point. On the VPS, Docker runs one container per service, all connected over the traefik_proxy network. For odabas.ch and waverider52.com, Traefik only passes TLS through unencrypted to their own nginx containers, which terminate it themselves: nginx-odabas on port 8081, nginx-waverider on port 8082 — both receive their certificates directly from Certbot via mount, not through Traefik. nginx-odabas has served the static Astro files since the cutover, the former WordPress container is stopped, not removed. Plus a planned Spring Boot application with an Angular frontend (its own PostgreSQL database) and a planned Python application (uses the same shared MariaDB as odabas.ch and waverider52.com). Certbot has to briefly stop and restart Traefik on every certificate renewal so it can bind port 80 for its own check. Both WordPress databases run in a shared MariaDB whose data lives on a bind mount (./data/db-shared, a mounted host folder, not a named Docker volume). The planned applications are meant to use a shared PostgreSQL database with its own named volume. Certbot runs directly on the host via cron, renews the certificates and restarts Traefik in the process. Outside of Traefik, two Portainer containers run for management, published directly on host ports: the current one on port 9000, plus an old, nine-month-old container from an earlier test stack on port 9001 that still needs cleaning up.BrowserVPSCertbothost, via cronCertificatesstop/start during renewalDocker: every box is a containernetwork: traefik_proxyTraefiksingle entry point, ports 80/443:8082:8081TLS-Passthroughwaverider52.comnginxWeb serverWordPressPHPodabas.chnginxPortfolioWordPressstoppedSpring Boot + AngularSpring BootBackendAngularFrontendPythonPython-AppplannedMariaDBsharedPostgreSQLshared, plannedbind mount: ./data/db-sharedVolumeAdmin, not through Traefik: published directly on host portsPortainercurrent, host port 9000Portainerold, host port 9001Cleanup pendingrunningplanned, stopped, or replacedCleanup pending

How odabas.ch gets deployed

A push to main automatically builds a new image and rolls it out on the existing nginx-odabas container.

Deployment pipeline for odabas.chA push to main in the odabas-portfolio repository triggers GitHub Actions, which builds a Docker image and publishes it to ghcr.io. On the server, only the image of the existing nginx-odabas container changes to this new image; name, port 8081, TLS passthrough and Traefik labels stay unchanged. nginx-odabas serves the built Astro files directly, with no database or app container at all. waverider52.com keeps running unchanged with nginx-waverider and WordPress. A future application from Etappe 7 or 8 would take the same path: its own, isolated nginx and app container. waverider52.com and the future application use the shared MariaDB instance with a bind mount for the data; odabas.ch needs no connection to it.GitHub: odabas-portfoliogit push (main)GitHub Actionsbuild-and-deploy:builds imageghcr.ioodabas-portfolio:latestSame pattern planned for Etappe 12 (Python/Spring Boot)InternetTraefik edge router (80/443)TLS passthrough, host-based routingodabas.chnginx-odabasImage: ghcr.io/…/odabas-portfolioserves Astro dist/directly (static)Port 8081,no app/DB containerNo database — static sitewaverider52.comnginx-waveriderTLS: 8082 · Redirect: 18082wordpress-waveriderNetworks: wpnet+ traefik_proxyFurther app(Python / Spring Boot,Etappe 7/8)nginx (isolated)App containerMariaDB (Python) orown Postgres (Spring)Shared database instance(mariadb-shared)Bind mount ./data/db-shared — separate database per appodabas.ch: static, shipped as a CI/CD image, no database — other apps: shared MariaDB instance