Bye bye Big-Tech — 👋 Infomaniak

Bye bye Big-Tech — 👋 Infomaniak

Nov 17, 2025

image

Photo by Alex Machado on Unsplash

Nach berechtigter Frage von Adrienne Fichter zur Nutzung von Azure für den E-Collecting Pilot und den neusten Updates für die Generic Verifier und Generic Issuer Komponenten der Public Beta Trust Infrastucture habe ich mich entschieden, beide Themen im gleichen Schritt anzugehen und die Chance nutzen, die Architektur noch etwas anzupassen.

Meine Anforderungen:

  • Installation einer Docker Umgebung in einer Schweizer Cloud

  • Neue Generic Komponenten

  • Verbesserung bei der Virtual Host Konfiguration und Firewall


The Ethical Cloud — Infomaniak

Anstatt Microsoft Azure zu verwenden, habe ich mich auf die Cloud von Infomaniak entschieden. Nicht nur der Preis ist bei Infomaniak viel besser als bei Microsoft, auch das Setup und Management ist viel einfacher und schneller.

Disclaimer: Ich werde nicht von Infomaniak gesponsored

Für meinen E-Collecting Pilot habe ich mich für die kleinste Cloud Computing Einheit entschieden: VPS Lite

und diese in den nächsten Schritten entsprechend eingerichtet. Dabei habe ich mich für Debian Trixie, dem aktuellsten LTS Release.

image

VPS lite: https://www.infomaniak.com/de/hosting/vps-lite

Installation der Beta Cloud Komponenten

1. System aktualisieren und benötigte Pakete installieren

sudo apt update
sudo apt install ca-certificates curl

2. Docker GPG-Schlüssel hinzufügen

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

3. Docker-Repository einrichten

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

4. Paketliste aktualisieren

sudo apt update

5. Docker Engine installieren

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Installation von Git & clonen der neuen Repositories

Da die bisherigen Generic Komponenten nicht mehr aktuell sind, empfiehlt sich das Update auf die neue Version. Dazu habe ich mich entschieden, eine Neuinstallation durchzuführen. Doch dazu musste ich zuerst GIT installieren:

sudo apt-get install git-all .

und anschliessend die neuen Repositories für meine 3 Komponenten laden:

Verifizieren der SWIYU E-ID

git clone https://github.com/swiyu-admin-ch/swiyu-verifier.git ./verifier-identity

Ausstellen der Quittung

git clone https://github.com/swiyu-admin-ch/swiyu-issuer.git ./issuer-receipt

Ausstellen des Stimmrechtsausweis

git clone https://github.com/swiyu-admin-ch/swiyu-issuer.git ./issuer-stimmrecht

Webserver Installation

Hier verwende ich den NGINX Server anstatt den eingebauten Apache Server. Dieser muss zudem zuerst deaktiviert werden.

NGINX Installieren:

sudo apt install nginx -y

CORS Allow-List einrichten

damit ich nur von meinem Frontend auf die Services zugreifen kann konfiguriere ich eine “Allow List”:

sudo nano /etc/nginx/conf.d/cors_map.conf

# erlaubt alle Subdomains 
map $http_origin $cors_origin {
    default "";
# explizit erlaubte Origins
    ~^https://beta\.ecollecting\.ch$                                          $http_origin;
}

Virtual Host: HTTP → HTTPS Weiterleitung konfigurieren

Als nächstes werden die Virutal Hosts eingerichtet, zunächst nur als HTTP:

sudo nano /etc/nginx/sites-available/verifier-identity

server {
    listen 80;
    server_name verifier-identity.ecollecting.ch;
#    return 308 https://$host$request_uri;
# CORS-Header auch auf 80 ausliefern (wichtig für evtl. Preflights)
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;
    location / {
        # Preflight auf 80 direkt beantworten, NICHT redirecten
        if ($request_method = OPTIONS) { return 204; }
        return 308 https://$host$request_uri;
    }
}

sudo nano /etc/nginx/sites-available/issuer-stimmrecht

server {
    listen 80;
    server_name issuer-stimmrecht.ecollecting.ch;
#    return 308 https://$host$request_uri;
# CORS-Header auch auf 80 ausliefern (wichtig für evtl. Preflights)
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;
    location / {
        # Preflight auf 80 direkt beantworten, NICHT redirecten
        if ($request_method = OPTIONS) { return 204; }
        return 308 https://$host$request_uri;
    }
}

sudo nano /etc/nginx/sites-available/issuer-receipt

server {
    listen 80;
    server_name issuer-receipt.ecollecting.ch;
#    return 308 https://$host$request_uri;
# CORS-Header auch auf 80 ausliefern (wichtig für evtl. Preflights)
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;
    location / {
        # Preflight auf 80 direkt beantworten, NICHT redirecten
        if ($request_method = OPTIONS) { return 204; }
        return 308 https://$host$request_uri;
    }
}

Zudem müssen noch die Sites verlinkt und der Dienst neu gestartet werden:

sudo ln -s /etc/nginx/sites-available/verifier-identity /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/issuer-receipt /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/issuer-stimmrecht /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Bevor nun die SSL Zertifikate gelöst werden, müssen noch die DNS Einträge für die 3 Hosts auf meine IP Adresse der Beta Cloud eingerichtet werden:

  • issuer-stimmrecht.ecollecting.ch

  • issuer-receipt.ecollecting.ch

  • verifier-identity.ecollecting.ch

HTTPS aktivieren:

Jetzt kann HTTPS aktiviert werden, dazu muss aber noch certbot installiert werden.

sudo apt install certbot python3-certbot-nginx -y

Certs löschen, falls vorhanden

sudo certbot certificates
sudo certbot delete - cert-name <certificate-name>

Damit anschliessend auch die swiyu Wallet und beta.ecollecting.ch auf die Services zugreifen kann, muss in der Infomaniak Cloud die Firewall entsprechend konfiguriert werden. Bitte achte darauf, dass der SSH-Port nicht standardmässig für alle IP’s offen ist.

Ich nutze einen VPN, daher gebe ich jeweils die verwendete IP-Adresse frei, bevor ich mit SSH darauf verbinde.

image

SSL Zertifikate erstellen:

Hier nutze ich den freien Dienst von EFF: https://certbot.eff.org/

sudo certbot - nginx -d verifier-identity.ecollecting.ch
sudo certbot - nginx -d issuer-stimmrecht.ecollecting.ch
sudo certbot - nginx -d issuer-receipt.ecollecting.ch

Block Management Access

Obwohl es nur eine Demo-Umgebung ist, möchte ich den Zugriff auf geschützte Serivceendpunkte unterbinden. Dazu sind folgende Einstellungen an den Virutal Hosts notwendig. In der Datei unten sind zudem auch noch die CORS & SSL Einstellungen ergänzt.

sudo nano /etc/nginx/sites-available/issuer-receipt

server {
    server_name issuer-receipt.ecollecting.ch;
    listen 443 ssl; # managed by Certbot
    
    ssl_certificate /etc/letsencrypt/live/verifier-identity.ecollecting.ch/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/verifier-identity.ecollecting.ch/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # >>> CORS-Header für ALLE Antworten (auch 4xx/5xx) <<<
    add_header Access-Control-Allow-Origin $cors_origin always;  # oder '*' wenn du keine Credentials brauchst
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;

    # >>> /management und alle Unterpfade
    location ^~ /management {
        # 1) Preflight IMMER durchlassen (204), egal von wem
        #    Browser-CORS lässt es später trotzdem nur für whitelisted Origins zu
        if ($request_method = OPTIONS) {
            return 204;
        }

        # 2) Für echte Requests (GET/POST/…) nur Whitelist-Origins zulassen
        if ($cors_origin = "") {
            return 403;
        }

        proxy_set_header Origin "";  # Backend muss sich nicht um CORS kümmern
        proxy_pass http://localhost:8081;  # /management/... bleibt als Pfad erhalten
        proxy_http_version 1.1;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }

    location / {
        proxy_set_header Origin "";   # <- Workaround
        # Preflight direkt beantworten
        if ($request_method = OPTIONS) { return 204; }
        proxy_pass http://localhost:8081;   # <-- YOUR port
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }
}

sudo nano /etc/nginx/sites-available/issuer-stimmrecht

server {
    server_name issuer-stimmrecht.ecollecting.ch;
    listen 443 ssl; # managed by Certbot
    
    ssl_certificate /etc/letsencrypt/live/verifier-identity.ecollecting.ch/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/verifier-identity.ecollecting.ch/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    # >>> CORS-Header für ALLE Antworten (auch 4xx/5xx) <<<
    add_header Access-Control-Allow-Origin $cors_origin always;  # oder '*' wenn du keine Credentials brauchst
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;

    # >>> /management und alle Unterpfade
    location ^~ /management {
        # 1) Preflight IMMER durchlassen (204), egal von wem
        #    Browser-CORS lässt es später trotzdem nur für whitelisted Origins zu
        if ($request_method = OPTIONS) {
            return 204;
        }

        # 2) Für echte Requests (GET/POST/…) nur Whitelist-Origins zulassen
        if ($cors_origin = "") {
            return 403;
        }

        proxy_set_header Origin "";  # Backend muss sich nicht um CORS kümmern
        proxy_pass http://localhost:8082;  # /management/... bleibt als Pfad erhalten
        proxy_http_version 1.1;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }

    location / {
        proxy_set_header Origin "";   # <- Workaround
        # Preflight direkt beantworten
        if ($request_method = OPTIONS) { return 204; }
        proxy_pass http://localhost:8082;   # <-- YOUR port
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }
}

sudo nano /etc/nginx/sites-available/verifier-identity

server {
    server_name verifier-identity.ecollecting.ch;
    listen 443 ssl; # managed by Certbot

    ssl_certificate /etc/letsencrypt/live/verifier-identity.ecollecting.ch/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/verifier-identity.ecollecting.ch/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # >>> CORS-Header für ALLE Antworten (auch 4xx/5xx) <<<
    add_header Access-Control-Allow-Origin $cors_origin always;  # oder '*' wenn du keine Credentials brauchst
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept" always;
    add_header Access-Control-Max-Age 86400 always;
    add_header Vary "Origin" always;

    # >>> /management und alle Unterpfade
    location ^~ /management {
        # 1) Preflight IMMER durchlassen (204), egal von wem
        #    Browser-CORS lässt es später trotzdem nur für whitelisted Origins zu
        if ($request_method = OPTIONS) {
            return 204;
        }

        # 2) Für echte Requests (GET/POST/…) nur Whitelist-Origins zulassen
        if ($cors_origin = "") {
            return 403;
        }

        proxy_set_header Origin "";  # Backend muss sich nicht um CORS kümmern
        proxy_pass http://localhost:8080;  # /management/... bleibt als Pfad erhalten
        proxy_http_version 1.1;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }

    location / {
        proxy_set_header Origin "";   # <- Workaround
        # Preflight direkt beantworten
        if ($request_method = OPTIONS) { return 204; }
        proxy_pass http://localhost:8080;   # <-- YOUR port
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }
}

System-Service einreichten

Damit die Beta Cloud auch nach einem Neustart wieder einwandfrei funktioniert, bspw. wenn ein Update eingespielt werden muss, wurde folgender Service eingerichtet:

Docker script: sudo nano /etc/systemd/system/docker-up.service

[Unit]
Description=Start multiple docker compose projects at boot
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/home/debian/docker-up.sh
RemainAfterExit=yes
User=debian
WorkingDirectory=/home/debian
[Install]
WantedBy=multi-user.target

sudo nano docker-up.sh

#!/bin/bash
set -e  # Falls ein Befehl fehlschlägt, Skript beenden
# SWIYU
cd /home/debian/verifier-identity
sudo docker compose up -d
# Quittung
cd /home/debian/issuer-receipt
sudo docker compose up -d
# Stimmrecht Gemeinde
cd /home/debian/issuer-stimmrecht
sudo docker compose up -d

So kann der Dienst anschliessend gestartet werden:

sudo systemctl enable docker-up.service

Swagger UI

Die Services können nun unter folgenden URLs getestet werden:

https://issuer-stimmrecht.ecollecting.ch/swagger-ui/index.html#

https://issuer-receipt.ecollecting.ch/swagger-ui/index.html#

https://verifier-identity.ecollecting.ch/swagger-ui/index.html#


Changelog

Für eine einfache Verwendung der Generic Issuer / Verifier Komponenten hat sich nicht viel geändert.

Bei Issuer und Verifier sollten die neuen Ports für die DB und die Services beachtet werden. Vorallem, da mit den neuen Komponenten die Services für Management und den Wallet Service unter dem gleichen Endpoint laufen:

Verifier:

  • Statt zwei Container (…-management und …-oid4vp) gibt es jetzt nur einen: verifier-service.

  • Neues Image: ghcr.io/swiyu-admin-ch/swiyu-verifier:latest ersetzt beide alten Images.

  • Port: Alt: 8082 (Management) + 8083 (OID4VP). Neu: nur noch 8083.

  • Neue Metadata Config für die VP-Formate.

Issuer:

  • Aus 2 Containern (issuer-agent-management + issuer-agent-oid4vci) wird 1 Container: swiyu-issuer-service.

  • Neues kombiniertes Image: ghcr.io/swiyu-admin-ch/swiyu-issuer:latest.

  • Port: Alt: 8080 (Management) + 8081 (OID4VCI) / Neu: nur 8080 für alles.

Token-Endpoint-Pfad geändert:

  • Alt: /api/v1/token

  • Neu: /oid4vci/api/token → d. h. dein Client muss den neuen Pfad verwenden.

Credential Endpoint Analoger Pfadwechsel wie beim Token-Endpoint:

  • Alt: /api/v1/credential

  • Neu: /oid4vci/api/credential

cryptographic_binding_methods_supported: → Der Eintrag wurde von “did:jwk” auf “jwk” geändert.

  • Das kann Auswirkungen auf Wallets/Clients haben, die auf den exakten Binding-Method-Namen achten.

Ti piace questo post?

Offri un pizza a Digital Democracy Hub Schweiz

Altro da Digital Democracy Hub Schweiz

PrivacyTerminiRapporto