<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Server Archives - Nerd Corner</title>
	<atom:link href="https://nerd-corner.com/de/tag/server/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerd-corner.com/de/tag/server/</link>
	<description>Craft your dreams!</description>
	<lastBuildDate>Sun, 16 Mar 2025 18:36:35 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>

<image>
	<url>https://nerd-corner.com/wp-content/uploads/2019/10/cropped-LogoNerdCorner-2-32x32.png</url>
	<title>Server Archives - Nerd Corner</title>
	<link>https://nerd-corner.com/de/tag/server/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Deployment einer WebApp mit Kubernetes und Caddy</title>
		<link>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/</link>
					<comments>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 16 Feb 2025 17:20:29 +0000</pubDate>
				<category><![CDATA[Angular-DE]]></category>
		<category><![CDATA[App Entwicklung]]></category>
		<category><![CDATA[Software-DE]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Caddy]]></category>
		<category><![CDATA[Caddy Server]]></category>
		<category><![CDATA[Cluster]]></category>
		<category><![CDATA[ClusterIP]]></category>
		<category><![CDATA[ConfigMap]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Registrierung]]></category>
		<category><![CDATA[Hetzner]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Ingress]]></category>
		<category><![CDATA[Ingress Controller]]></category>
		<category><![CDATA[IP Adresse]]></category>
		<category><![CDATA[K3s]]></category>
		<category><![CDATA[Kubectl]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LoadBalancer]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Node Port]]></category>
		<category><![CDATA[Pods]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[Schritt für Schritt Anweisung]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Service]]></category>
		<category><![CDATA[Traefik]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1687</guid>

					<description><![CDATA[<p>Nachdem im letzten Beitrag beschrieben wurde, wie man produktionsreife Docker-Images erstellt und auf Docker Hub hochlädt, geht es nun darum, diese Images auf einem Server &#8230; </p>
<p>The post <a href="https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/">Deployment einer WebApp mit Kubernetes und Caddy</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Nachdem im letzten Beitrag beschrieben wurde, wie man produktionsreife Docker-Images erstellt und auf Docker Hub hochlädt, geht es nun darum, diese Images auf einem Server bereitzustellen. Ziel ist es, die Webanwendung über eine eigene Domain für alle zugänglich zu machen. Dafür nutzen wir einen Virtual Private Server (VPS) von Hetzner und setzen Kubernetes (<span style="font-size: 1.125rem;">k3s) </span><span style="font-size: 1.125rem;">mit Caddy als Reverse Proxy ein.</span></p>
<p><em><strong>Das könnte dich ebenfalls interessieren: </strong><a href="https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/">Docker Images erstellen und auf Dockerhub hochladen</a></em></p>
<h2>Einen VPS bei Hetzner einrichten</h2>
<p>Hetzner bietet oft Empfehlungslinks mit Guthaben-Vorteilen für Neukunden. Selbstverständlich kann man auch andere Anbieter nutzen, aber Hetzner ist preislich attraktiv und bietet solide Leistungen.</p>
<h3>Was ist ein VPS?</h3>
<p>Ein Virtual Private Server (VPS) ist ein virtueller Server, der auf einer physischen Maschine betrieben wird und als eigenständiger Server agiert. Er bietet mehr Kontrolle als klassisches Shared Hosting und ist eine kostengünstige Alternative zu dedizierten Servern. Der Zugriff erfolgt in der Regel per SSH (Secure Shell), wodurch wir den Server über die Kommandozeile steuern können.</p>
<h3>SSH-Zugriff auf den VPS</h3>
<p data-start="1137" data-end="1384">Nach dem Erstellen eines VPS erfolgt die Verwaltung meist über eine <strong data-start="1205" data-end="1227">Secure Shell (SSH)</strong>. SSH ist ein Protokoll, das verschlüsselte Verbindungen zu entfernten Servern ermöglicht. Um sich mit dem Server zu verbinden, nutzt man folgenden Befehl:</p>
<p data-start="1137" data-end="1384"><span style="background-color: #e9ebec; color: #222222; font-family: Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace; font-size: 15px;">ssh root@&lt;IP-Adresse-des-Servers&gt;</span></p>
<p data-start="1430" data-end="1582">Falls ein SSH-Schlüssel hinterlegt wurde, kann die Authentifizierung per <strong data-start="1503" data-end="1535">Public-Key-Authentifizierung</strong> erfolgen, was sicherer als ein Passwort ist.</p>
<h3>Server bei Hetzner erstellen</h3>
<ol>
<li>Nach der Anmeldung in der Hetzner Cloud navigieren wir zu „Projekte“ und erstellen ein neues Projekt.</li>
<li>Danach wählen wir „Server hinzufügen“ und können eine Instanz konfigurieren.</li>
<li>Für den Anfang reicht oft das günstigste Modell aus. Ich empfehle jedoch, die Option für eine IPv4-Adresse zu aktivieren, da rein IPv6-basierte Setups oft Kompatibilitätsprobleme verursachen.</li>
</ol>
<h2>Domain einrichten</h2>
<p>Um die Anwendung später unter einer eigenen Domain zu erreichen, muss man eine Domain registrieren und mit dem Server verknüpfen.</p>
<h3>Domain bei Hetzner beantragen</h3>
<ol>
<li>In der Hetzner ConsoleH eine neue Domain registrieren oder eine bestehende Domain hinzufügen.</li>
<li>Um DNS-Einträge zu verwalten, müssen wir den DNS-Zugriff aktivieren.</li>
</ol>
<h3>Nameserver setzen</h3>
<p>Folgende Nameserver sollten genutzt werden:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">helium.ns.hetzner.de. 
hydrogen.ns.hetzner.com. 
oxygen.ns.hetzner.com.</pre>
<p>Diese neuen Nameserver bieten bessere Performance und Flexibilität im Vergleich zu den alten Hetzner-Nameservern:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">ns1.first-ns.de.
robotns2.second-ns.de.
robotns3.second-ns.com.</pre>
<p>Beide Nameserver Varianten sind aber möglich! Die DNS Änderungen brauchen etwas Zeit. Mit Tools wie <a href="https://mxtoolbox.com/">MXToolbox</a> können wir aber überprüfen, ob die Änderungen bereits stattgefunden haben.</p>
<h3>Domain mit dem Server verbinden</h3>
<p data-start="3155" data-end="3229">Nun muss die <strong data-start="3168" data-end="3219">IP-Adresse des Servers mit der Domain verknüpft</strong> werden:</p>
<ol data-start="3231" data-end="3512">
<li data-start="3231" data-end="3283">In der Hetzner Cloud zu <strong data-start="3258" data-end="3271">DNS-Zonen</strong> wechseln.</li>
<li data-start="3284" data-end="3323">Die registrierte Domain auswählen.</li>
<li data-start="3324" data-end="3411">Einen neuen <strong data-start="3339" data-end="3351">A-Record</strong> erstellen und die <strong data-start="3370" data-end="3386">IPv4-Adresse</strong> des Servers eintragen.</li>
<li data-start="3412" data-end="3512">Falls vorhanden, den <strong data-start="3436" data-end="3458">IPv6-Record (AAAA)</strong> entfernen, um Kompatibilitätsprobleme zu vermeiden.</li>
</ol>
<p data-start="3514" data-end="3621">Mit <a href="https://mxtoolbox.com/" target="_blank" rel="noopener" data-start="3518" data-end="3553">MXToolbox</a> kann man auch hier prüfen, ob die DNS-Änderungen bereits übernommen wurden.</p>
<h2>Kubernetes einrichten</h2>
<p>Kubernetes ist ein leistungsfähiges Orchestrierungstool für Container. Ich verwende <strong data-start="3756" data-end="3763">k3s</strong>, eine schlanke Kubernetes-Variante, die sich besonders gut für kleinere Umgebungen eignet.</p>
<h3 data-start="3858" data-end="3902">K3s auf dem Server installieren</h3>
<p data-start="3903" data-end="3980">Per SSH auf den Server verbinden und k3s mit folgendem Befehl installieren:</p>
<pre><code class="language-sh">curl -sfL https://get.k3s.io | sh - </code></pre>
<p><span style="font-size: 1.125rem;">Das Skript installiert k3s und startet den Kubernetes-Dienst. </span>Nach der Installation kann k3s mit folgendem Befehl überprüft werden:</p>
<pre><code class="language-sh">kubectl get nodes
</code></pre>
<p>k3s bringt eine eigene <code>kubectl</code>-Version mit, sodass keine separate Installation nötig ist.</p>
<h3>YAML-Files für FE, BE, MySQL und Redis erstellen</h3>
<p>Für das Deployment unserer Anwendung brauchen wir YAML-Dateien für:</p>
<ul>
<li>Frontend (Angular)</li>
<li>Backend (NestJS)</li>
<li>Datenbank (MySQL)</li>
<li>Session-Management (Redis)</li>
</ul>
<p>Eine <strong data-start="4641" data-end="4661">Deployment-Datei</strong> für das Backend könnte so aussehen:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
        - name: backend
          image: dockerhub-user/backend:latest
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP
</pre>
<h2>Was sind Deployments und Services?</h2>
<ul>
<li><strong>Deployments</strong> verwalten die Bereitstellung und Skalierung von Containern.</li>
<li><strong>Services</strong> sorgen für eine stabile Netzwerkverbindung zwischen Containern.</li>
<li>ClusterIP bedeutet, dass der Service nur innerhalb des Kubernetes-Clusters erreichbar ist.</li>
</ul>
<h2>Caddy als Reverse Proxy einrichten</h2>
<p>Damit eingehender Traffic richtig verteilt wird, wird ein Reverse Proxy benötigt. K3s bringt standardmäßig <strong>Traefik</strong> mit, allerdings habe ich mich für eine einfachere Lösung entschieden: <strong>Caddy</strong>. Ich war echt erstaunt wie wenig Anleitungen bzw. Dokumentation es zu Caddy in Kombination mit Kubernetes gibt.</p>
<h3>Warum Kubernetes mit Caddy?</h3>
<ul>
<li>Automatische Let’s Encrypt SSL-Zertifikate</li>
<li>Einfache Konfiguration per <code>Caddyfile</code></li>
<li>Built-in Load Balancer</li>
</ul>
<h3>Traefik entfernen</h3>
<pre><code class="language-sh">kubectl delete helmrelease traefik -n kube-system
</code></pre>
<h3>Caddy Deployment erstellen</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: caddy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: caddy
  template:
    metadata:
      labels:
        app: caddy
    spec:
      containers:
        - name: caddy
          image: caddy
          volumeMounts:
            - name: caddy-config
              mountPath: /etc/caddy/Caddyfile
      volumes:
        - name: caddy-config
          configMap:
            name: caddy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: caddy-config
data:
  Caddyfile: |

    example.com {
        reverse_proxy backend-service:3000
    }

---
apiVersion: v1
kind: Service
metadata:
  name: caddy-service
spec:
  type: LoadBalancer
  selector:
    app: caddy
  ports:
    - port: 80
      targetPort: 80
    - port: 443
      targetPort: 443</pre>
<p>Wichtig: Da Let’s Encrypt ein Rate-Limit hat, sollten Tests zunächst mit Staging-Zertifikaten erfolgen!</p>
<h2>Fazit</h2>
<p>Nach diesen Schritten läuft die Anwendung nun in einem Kubernetes-Cluster auf einem Hetzner VPS und ist über eine eigene Domain erreichbar. Als nächstes würde es sich anbieten eine automatische CI/CD-Pipeline einzurichten, um neue Versionen ohne manuellen Aufwand zu deployen.</p>
<p>The post <a href="https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/">Deployment einer WebApp mit Kubernetes und Caddy</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Erfahrungen aus der Praxis: NestJS auf Vercel hosten</title>
		<link>https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/</link>
					<comments>https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Thu, 14 Nov 2024 07:55:27 +0000</pubDate>
				<category><![CDATA[Software-DE]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Anleitung]]></category>
		<category><![CDATA[cookie-sessions]]></category>
		<category><![CDATA[CORS Fehler]]></category>
		<category><![CDATA[Cors Fehler nest]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[Datenbank hosten]]></category>
		<category><![CDATA[Datenbank konfigurieren]]></category>
		<category><![CDATA[Einstellungen]]></category>
		<category><![CDATA[Erfahrungsbericht]]></category>
		<category><![CDATA[express]]></category>
		<category><![CDATA[express-sessions]]></category>
		<category><![CDATA[express.js]]></category>
		<category><![CDATA[google cloud]]></category>
		<category><![CDATA[google cloud mysql]]></category>
		<category><![CDATA[Hosten]]></category>
		<category><![CDATA[internal Server Fehler Vercel]]></category>
		<category><![CDATA[Internal Server Fehler Vercel nest]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest]]></category>
		<category><![CDATA[NestJs]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[redis session management]]></category>
		<category><![CDATA[redis session management nest.js]]></category>
		<category><![CDATA[Schritt für Schritt Anweisung]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Session Mamagement]]></category>
		<category><![CDATA[session management]]></category>
		<category><![CDATA[typescript]]></category>
		<category><![CDATA[Vercel]]></category>
		<category><![CDATA[vercel.json]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1632</guid>

					<description><![CDATA[<p>Nachdem ich Stunden damit verbracht habe, meine NestJS-App auf Vercel zu hosten und es nicht zum Laufen brachte, dachte ich mir, dass es an der &#8230; </p>
<p>The post <a href="https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/">Erfahrungen aus der Praxis: NestJS auf Vercel hosten</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Nachdem ich Stunden damit verbracht habe, meine NestJS-App auf Vercel zu hosten und es nicht zum Laufen brachte, dachte ich mir, dass es an der Zeit ist, zu dokumentieren, was ich gelernt habe &#8211; nicht nur, um mir in Zukunft Zeit zu sparen, sondern hoffentlich auch, um anderen zu helfen, einige der Fallstricke zu vermeiden, in die ich geraten bin. Hier ist eine Aufschlüsselung dessen, was funktioniert hat, was nicht, und wie ich es schließlich geschafft habe, dass alles reibungslos läuft.</p>
<p><em><strong>Das könnte dich ebenfalls interessieren:</strong> <a href="https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/" target="_blank" rel="noopener">Swagger zu Node Server hinzufügen</a></em></p>
<h3>Schritt 1: NestJS auf Vercel hosten</h3>
<p>Das Wichtigste zuerst: Die Grundeinstellungen für die Bereitstellung auf Vercel. Vercel ist großartig für Serverless, aber die Arbeit mit NestJS benötigt ein paar Anpassungen. Die Hauptsache ist, eine vercel.json-Konfigurationsdatei einzurichten, die Vercel genau sagt, wie die App zu behandeln ist.</p>
<p>Hier ist die Endkonfiguration:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="beyond">{
  "version": 2,
  "builds": [
    {
      "src": "src/main.ts",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "src/main.ts",
      "methods": [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "OPTIONS",
        "DELETE",
        "HEAD",
        "CONNECT",
        "TRACE"
      ]
    }
  ]
}
</pre>
<p>Ich habe daraufhin in Vercel folgende Fehlermeldung erhalten:</p>
<pre>This Serverless Function has crashed. Your connection is working correctly. 
Vercel is working correctly. 500: INTERNAL_SERVER_ERROR 
Code: FUNCTION_INVOCATION_FAILED ID: bom1::sgk4v-1711014022883-1e9ed54f4c37</pre>
<p>Bei einem Blick in die Logs stellte ich fest, dass die Datenbankverbindung ein Problem darstellte und außerdem die folgende Logmeldung angezeigt wurde:</p>
<pre>No exports found in module "/var/task/app-name/src/main.js".
Did you forget to export a function or a server?</pre>
<p>Es stellte sich heraus, dass ich den zweiten Teil der Fehlermeldung ignorieren und mich nur auf die Datenbankverbindung konzentrieren musste.</p>
<h3>Schritt 2: Konfigurieren der Datenbank</h3>
<p>Für meine Anwendung habe ich eine mysql-Datenbank mit mehreren Schemata verwendet. Ich habe mehrere kostenlose Angebote ausprobiert, aber sie waren nicht mit dem Ansatz mehrerer Schemata kompatibel. Daher habe ich mich für das Hosting bei Google Cloud entschieden. Ich habe es auf einen Preis von 0,01 $ pro Stunde heruntergeschraubt und das 300 $-Einsteigerangebot genutzt.</p>
<p>Um Vercel eine Verbindung zu ermöglichen, musste in der Konfiguration von Google Cloud die IP-Adresse auf <strong>0.0.0.0/0</strong> gesetzt werden, so dass die Datenbank von jeder IP-Adresse aus zugänglich war.</p>
<h3>Schritt 3: Umgang mit CORS</h3>
<p>Die CORS Fehler haben auch für einige Kopfschmerzen gesorgt. Stelle sicher, dass OPTIONS für CORS Preflight-Anfragen zugelassen wird, da Vercel eine explizite Erlaubnis für Cross-Origin-Anfragen benötigt. Am Ende musste ich eine Menge Header hinzufügen, um sicherzustellen, dass die Anfragen erlaubt waren:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">app.enableCors({
    origin: 'domain-name',
    credentials: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
    ],
  });</pre>
<h3>Schritt 4: Umstellung auf express-session und Redis für die Sitzungsverwaltung</h3>
<p>Einer der kniffligsten Teile war die Sessions zum Laufen zu bringen. Ich begann mit der <em>cookie-session</em> Bibliothek, aber Vercel ignoriert sie komplett. Nach einem Blick in die Dokumentation und einigem Ausprobieren wechselte ich zur <em>express-session</em> Bibliothek, da sie populärer ist und besser mit Vercels serverloser Umgebung funktioniert.</p>
<p>Aus irgendeinem Grund muss die Import-Syntax genau so aussehen:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">import session = require('express-session');</pre>
<p>Außerdem musste ich die Sitzungsmiddleware mit aktiviertem Vertrauensproxy konfigurieren, da Vercel Anfragen proxifiziert. So sieht die Einstellung aus:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);</pre>
<p>Auch die Einstellung secure: true und sameSite: &#8217;none&#8216; war wichtig, um sicherzustellen, dass Cookies über HTTPS und verschiedene Domainanfragen funktionieren!</p>
<p>Beachten, dass mit Vercel mehrere serverlose Instanzen Anfragen bearbeiten können, was bei parallelen Anfragen leider zu Sitzungskonflikten führt. Um dies zu beheben, habe ich meinen Sitzungsspeicher mit einer Redis-Instanz verbunden. Glücklicherweise war das super einfach.</p>
<p><a href="https://redis.io/">Redis</a> hält die Sitzungsdaten konsistent und vermeidet Konflikte zwischen Anfragen, insbesondere unter Last. Hier der Code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="beyond">const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);

const redisClient = createClient({
    password: process.env.REDIS_PASSWORD,
    socket: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT, 10),
    },
  });

  redisClient
    .connect()
    .catch((err) =&gt;
      console.log('Could not establish a connection with Redis: ' + err),
    );

  redisClient.on('error', (err) =&gt; console.log('Redis error: ' + err));
  redisClient.on('connect', () =&gt;
    console.log('Connected to Redis successfully'),
  );

  app.use(
    session({
      store: new RedisStore({ client: redisClient }),
      secret: process.env.COOKIE_SECRET,
      cookie: {
        secure: process.env.NODE_ENV !== 'development',
        sameSite: process.env.NODE_ENV === 'development' ? 'lax' : 'none',
        maxAge: 86400000,
      },
    }),
  );</pre>
<h3>Schritt 5: Hinzufügen von withCredentials im Frontend</h3>
<p>Dieser Schritt ist nur eine Randnotiz: Damit Session-Cookies zwischen Frontend und Backend funktionieren, muss withCredentials in den HTTP-Anfragen meines Frontends auf true gesetzt werden. Dies ermöglicht die Einbeziehung von Cookies in herkunftsübergreifende Anfragen, was wichtig ist, wenn das Frontend und das Backend getrennt gehostet werden. Ich musste sicherstellen, dass der HTTP-Client von Angular diese Einstellung aktiviert hat.</p>
<h3>Schritt 6: Schriftart hinzufügen</h3>
<p>Um Schriftdateien in Ihr NestJS-Projekt einzubinden, muss man die CompilerOptions in der nest-cli.json-Datei verwenden, um Assets für die Build-Ausgabe zu definieren, z. B. durch die Angabe von „include“: „**/*.ttf“ und ‚outDir‘: „dist/src“.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-title="nest-cli.json" data-enlighter-theme="beyond">{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      {
        "include": "**/*.ttf",
        "outDir": "dist/src"
      }
    ],
    "deleteOutDir": true
  }
}</pre>
<p>Anschließend kann man nach dem Build die Schriftarten im Code mit path.resolve referenzieren, z. B. path.resolve(__dirname, &#8218;../fonts/Roboto-Regular.ttf&#8216;). Auf diese Weise wird sichergestellt, dass die Schriftartendateien mit dem Build gebündelt werden und während der Laufzeit zugänglich sind.</p>
<h3>Schlussgedanken zum Thema NestJS auf Vercel hosten</h3>
<p>Das Deployment meiner NestJS-App auf Vercel war eine wahre Achterbahnfahrt. Manchmal hatte ich das Gefühl, dass ich kurz davor war, alles perfekt zum Laufen zu bringen, nur um dann mit neuen Fehlern konfrontiert zu werden, die mich zurück in den Fehlersuch-Modus schickten. Es gab Momente der Frustration &#8211; vor allem im Zusammenhang mit der Sessionverarbeitung und CORS-Problemen. Aber jede Lösung brachte ein neues Hoch, und jeder behobene Fehler fühlte sich wie ein kleiner Sieg an.</p>
<p>Jetzt, wo endlich alles reibungslos funktioniert, kann ich sagen, dass es ein großartiges Gefühl ist. Wenn ich sehe, dass meine Anwendung so funktioniert, wie ich es mir vorgestellt habe, ist das all die Kopfschmerzen wert. Es ist eine große Erleichterung, aber noch mehr freut es mich, zu wissen, dass ich jede Hürde überwunden habe und auf das, was ich gelernt habe, zurückblicken kann. Ich hoffe, dieser Leitfaden kann anderen einige dieser Schwierigkeiten ersparen und helfen, diesen „Es funktioniert einfach“-Moment etwas schneller zu erreichen!</p>
<p>The post <a href="https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/">Erfahrungen aus der Praxis: NestJS auf Vercel hosten</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Swagger Api Doku zu Node Server hinzufügen</title>
		<link>https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/</link>
					<comments>https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Wed, 26 Oct 2022 17:07:59 +0000</pubDate>
				<category><![CDATA[Software-DE]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Api]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Backend mit Swagger]]></category>
		<category><![CDATA[Backend Server]]></category>
		<category><![CDATA[CRUD]]></category>
		<category><![CDATA[Endpoints]]></category>
		<category><![CDATA[Endpunkte]]></category>
		<category><![CDATA[express.js]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[Informatik]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Node]]></category>
		<category><![CDATA[Node mit Swagger und Typescript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Schritt für Schritt Anweisung]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Swagger]]></category>
		<category><![CDATA[Swagger dokumentation]]></category>
		<category><![CDATA[Swagger express]]></category>
		<category><![CDATA[Swagger.json]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1266</guid>

					<description><![CDATA[<p>Ich habe vor kurzem einen Node Server mit express.js in Typescript programmiert. Das ist eine typische Kombination für Backend Entwicklung. Das ist besonders vorteilhaft wenn &#8230; </p>
<p>The post <a href="https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/">Swagger Api Doku zu Node Server hinzufügen</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Ich habe vor kurzem einen Node Server mit express.js in Typescript programmiert. Das ist eine typische Kombination für Backend Entwicklung. Das ist besonders vorteilhaft wenn bereits Erfahrung mit Frontend Entwicklung in Typescript vorhanden ist. Generell würde ich sowohl im Frontend als auch im Backend empfehlen lieber Typescript anstelle von Javascript zu nutzen. Typescript nutzt Javascript ist aber typbasiert und daher nicht so fehleranfällig!</p>
<p>Auch sollte der Fokus stehts auf clean Code legen und dieser ordentlich dokumentiert sein, besonders wenn ein Projekt größer wird zahlt sich ordentlich dokumentierte Arbeit aus. Um beispielsweise REST Endpunkte zu dokumentieren empfiehlt es sich Swagger zu benutzen. Die Swagger API Dokumentation bietet eine Übersicht über alle Endpunkte und sogar die Möglichkeit mit diesen zu interagieren.</p>
<p><strong><em>Das könnte Sie auch interessieren: </em></strong><em><a href="https://nerd-corner.com/de/wie-man-eine-reactive-angular-form-svg-mit-klickbaren-elementen-erstellt/" target="_blank" rel="noopener">Angular Form SVG mit clickbaren Elementen</a></em></p>
<h2>Liste der Komponenten</h2>
<ul>
<li>Entwicklungsumgebung (z.B. VS Code)</li>
<li>Node.js</li>
</ul>
<h2>Dokumentation mit Swagger</h2>
<p>Obwohl Swagger recht bekannt ist, konnte ich keine detaillierte Anleitung für die Implementation finden. Ich möchte daher 2 Wege zur Implementierung von Swagger in einen bestehenden Node Server erklären. Die erste Möglichkeit besteht darin direkt zu jedem Endpunkt Swagger Parameter hinzuzufügen. Das ist wohl die schnellere Variante, kann allerdings abhängig von der Anzahl der Endpunkte unübersichtlich werden. In der zweiten Variante wird eine „swagger.json“ Datei erstellt, die die  Parameter der Endpunkte zusammenfasst.</p>
<p>Um Swagger nutzen zu können wird folgende Bibliothek bzw. deren Typerweiterung genutzt:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install --save  swagger-ui-express
npm install --save-dev @types/swagger-ui-express</pre>
<p>Swagger erstellt eine Dokumentation der Endpunkte:</p>
<p><img fetchpriority="high" decoding="async" class="zoooom aligncenter wp-image-1271" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu.jpg" alt="Example Swagger Docu" width="1647" height="853" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu.jpg 1847w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-300x155.jpg 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-1024x531.jpg 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-768x398.jpg 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerDocu-1536x796.jpg 1536w" sizes="(max-width: 1647px) 100vw, 1647px" /></p>
<p>Diese können geöffnet werden und man sieht einen beispielhaften Request und einen beispielhaften Response:</p>
<p><img decoding="async" class="aligncenter wp-image-1273 zoooom" style="font-size: 1.125rem;" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint.jpg" alt="Example Swagger Endpoint 1" width="1657" height="840" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint.jpg 1757w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-300x152.jpg 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-1024x519.jpg 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-768x389.jpg 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint-1536x779.jpg 1536w" sizes="(max-width: 1657px) 100vw, 1657px" /><img decoding="async" class="aligncenter wp-image-1272 zoooom" src="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2.png" alt="Example Swagger Endpoint 2" width="1657" height="803" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2.png 1757w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-300x145.png 300w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-1024x496.png 1024w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-768x372.png 768w, https://nerd-corner.com/wp-content/uploads/2022/10/exampleSwaggerEndpoint2-1536x744.png 1536w" sizes="(max-width: 1657px) 100vw, 1657px" /></p>
<p>Über den Button &#8222;Try it out&#8220; kann direkt mit dem Endpunkt interagiert werden.</p>
<h2>Swagger API Dokumentation mit Parametern</h2>
<p>Diese Variante empfiehlt sich eher für kleinere Projekte. Zunächst müssen diese beiden Swagger Bibliotheken in das Projekt eingebunden werden:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install --save-dev @types/swagger-jsdoc 
npm install --save swagger-jsdoc</pre>
<p>Die Bibliotheken werden in app.ts bzw. für nicht Typescript Nutzer app.js konfiguriert. Aufgrund der hier festgelegten Konfiguration befindet sich die Dokumentation unter „/api-docs“:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="app.ts">import express from "express";
import bodyParser from "body-parser";
import exampleRoutes from "./routes/example-route";
import swaggerJSDoc from "swagger-jsdoc";
import swaggerUi from "swagger-ui-express";

const app = express();

const options = {
  definition: {
    openapi: "3.0.1",
    info: {
      title: "REST API for Swagger Documentation",
      version: "1.0.0",
    },
    schemes: ["http", "https"],
    servers: [{ url: "http://localhost:3000/" }],
  },
  apis: [
    `${__dirname}/routes/example-route.ts`,
    "./dist/routes/example-route.js",
  ],
};

const swaggerSpec = swaggerJSDoc(options);

app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.use(bodyParser.json());
app.use(exampleRoutes);

app.listen(3000);</pre>
<p>Der Endpunkt wird mit den Parametern folgendermaßen beschrieben:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="example-route.ts">import { Router } from "express";
import { exampleFunction } from "../controller/example";

const router = Router();

/**
 * @swagger
 * /example:
 *      post:
 *          summary: Send the text to the server
 *          tags:
 *              - ExampleEndpoints
 *          description: Send a message to the server and get a response added to the original text.
 *          requestBody:
 *              required: true
 *              content:
 *                  application/json:
 *                      schema:
 *                          type: object
 *                          properties:
 *                              responseText:
 *                                  type: string
 *                                  example: This is some example string! This is an endpoint
 *          responses:
 *              201:
 *                  description: Success
 *                  content:
 *                      application/json:
 *                          schema:
 *                              type: object
 *                              properties:
 *                                  text:
 *                                      type: string
 *                                      example: This is some example string!
 *              404:
 *                  description: Not found
 *              500:
 *                  description: Internal server error
 */
router.post("/example", exampleFunction);

export default router;
</pre>
<h2>Swagger API Dokumentation mit swagger.json</h2>
<p>Um eine bessere Übersicht zu haben und um die Dokumentation nicht mit dem eigentlichen Code zu vermischen empfiehlt sich die Nutzung einer, oder gar mehrerer json Dateien. Bei der Nutzung von TypeScript muss die Swagger.json Datei in die rootDirectory:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1276 zoooom" src="https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson.jpg" alt="Foulder Structure with Swagger.json" width="170" height="344" srcset="https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson.jpg 199w, https://nerd-corner.com/wp-content/uploads/2022/10/foulderStructureOfSwaggerJson-148x300.jpg 148w" sizes="auto, (max-width: 170px) 100vw, 170px" /></p>
<p>Auch hier wirdzunächst die Konfiguration in app.ts bzw. für nicht Typescript Nutzer in app.js festgelegt. Hier wird ebenfalls der Domainpfad „/api-docs“ für die Dokumentation gewählt:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-title="app.ts">import express from "express";
import bodyParser from "body-parser";
import exampleRoutes from "./routes/example-route";
import swaggerUi from "swagger-ui-express";

import * as swaggerDocument from "./swagger.json";

const app = express();

app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.use(bodyParser.json());

app.use(exampleRoutes);

app.listen(3000);</pre>
<p>Wichtiger Hinweis: Um JSON Dateien in ein Typescript Projekt zu importieren muss dies in der tsconfig.json erlaubt werden. Außerdem muss die JSON Datei sich in der root directory befinden:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-title="tsconfig.json">{
  "compilerOptions": {
    "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
    "module": "commonjs" /* Specify what module code is generated. */,
    "rootDir": "./src" /* Specify the root folder within your source files. */,
    "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
    "resolveJsonModule": true /* Enable importing .json files. */,
    "outDir": "./dist" /* Specify an output folder for all emitted files. */,
    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
    "strict": true /* Enable all strict type-checking options. */,
    "skipLibCheck": true /* Skip type checking all .d.ts files. */
  }
}</pre>
<p>Die vorherige Swagger Dokumentation mit Parametern würde somit in der swagger.json folgendermaßen aussehen:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "openapi": "3.0.1",
  "info": {
    "title": "REST API for Swagger Documentation",
    "version": "1.0.0"
  },
  "schemes": ["http"],
  "servers": [{ "url": "http://localhost:3000/" }],
  "paths": {
    "/example": {
      "post": {
        "tags": ["ExampleEndpoints"],
        "summary": "Send a text to the server",
        "description": "Send a message to the server and get a response added to the original text.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExampleSchemaHeader"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExampleSchemaBody"
                }
              }
            }
          },
          "404": { "description": "Not found" },
          "500": { "description": "Internal server error" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ExampleSchemaBody": {
        "properties": {
          "responseText": {
            "type": "string",
            "example": "This is some example string! This is an endpoint"
          }
        }
      },
      "ExampleSchemaHeader": {
        "required": ["text"],
        "properties": {
          "text": {
            "type": "string",
            "example": "This is some example string!"
          }
        }
      }
    }
  }
}
</pre>
<h2>Dateien zum Herunterladen</h2>
<ul>
<li><a href="https://github.com/hanneslim/Node-with-swagger-params" target="_blank" rel="noopener">Github Beispielprojekt für swagger Parameter</a></li>
<li><a href="https://github.com/hanneslim/node-with-swagger-json" target="_blank" rel="noopener">Github Beispielprojekt für swagger.json</a></li>
</ul>
<p>The post <a href="https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/">Swagger Api Doku zu Node Server hinzufügen</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/de/swagger-api-doku-zu-node-server-hinzufuegen/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
