惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
J
Java Code Geeks
A
About on SuperTechFans
F
Fortinet All Blogs
B
Blog
aimingoo的专栏
aimingoo的专栏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
Apple Machine Learning Research
Apple Machine Learning Research
V
V2EX
博客园_首页
博客园 - 叶小钗
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
Docker
云风的 BLOG
云风的 BLOG

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
My friend wanted GitLab. He got Gitea and Nextcloud for O...
Alexey · 2026-05-14 · via DEV Community

A friend sent me an article about GitHub potentially getting blocked in Russia and asked me to spin up GitLab. I suggested Gitea — I'd used it at a college hackathon, knew it was lightweight and wouldn't eat half the server. He agreed.

While the deploy was running, I asked him how he syncs Obsidian. He said — plain WebDAV, nothing fancy. Well, server's already open anyway, so I threw in Nextcloud too. Hour and a half later I had both a git host and a cloud storage.


Why not GitLab

My friend originally wanted GitLab. I opened the docs, looked at the requirements — 4 GB RAM just to start — and said no. We don't have a dedicated git server, there's already a project running on it. GitLab would've eaten everything.

Gitea idles at ~150 MB. Actions are compatible with GitHub Actions syntax, so existing workflows move over without rewriting. I'd already used it at a hackathon, knew it worked fine. Suggested it, got the green light.


On Helm

First time I touched Kubernetes was when I had to deploy a college project for a grade. Wrote manifests by hand — Deployment, Service, Ingress, PVC, repeat. I knew Helm existed but never had a reason to dig into it.

Turns out it's like pacman, but for Kubernetes. One values.yaml instead of five hundred lines of YAML, one command — everything's up. Would've lost my mind doing it the old way.

First though, Helm couldn't see the cluster at all:

Kubernetes cluster unreachable: Get "http://localhost:8080/version"

Enter fullscreen mode Exit fullscreen mode

k3s puts the kubeconfig somewhere Helm doesn't look by default. Fix:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc

Enter fullscreen mode Exit fullscreen mode


Gitea

The server already had ingress-nginx and cert-manager with a letsencrypt-prod ClusterIssuer. Set the DNS beforehand — A record git.logiflowadvanced.online → 2.27.42.100.

gitea-values.yaml:

ingress:
  enabled: true
  ingressClassName: nginx
  hosts:
    - host: git.logiflowadvanced.online
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: gitea-tls
      hosts:
        - git.logiflowadvanced.online
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod

gitea:
  admin:
    username: admin
    password: yourpassword
    email: your@email.com

persistence:
  size: 10Gi

postgresql-ha:
  enabled: false

postgresql:
  enabled: true

Enter fullscreen mode Exit fullscreen mode

helm repo add gitea-charts https://dl.gitea.com/charts/
helm repo update
helm install gitea gitea-charts/gitea \
  --namespace gitea --create-namespace \
  -f gitea-values.yaml

Enter fullscreen mode Exit fullscreen mode

Pods came up. Opened the browser — invalid certificate, browser complaining. Checked the Ingress:

NAME    CLASS    HOSTS                          ADDRESS   PORTS
gitea   <none>   git.logiflowadvanced.online              80, 443

Enter fullscreen mode Exit fullscreen mode

CLASS: <none> — the nginx controller just ignored this Ingress entirely. cert-manager didn't issue anything either, so nginx was serving its default self-signed cert.

kubectl patch ingress gitea -n gitea \
  --type=json \
  -p='[{"op":"add","path":"/spec/ingressClassName","value":"nginx"}]'

Enter fullscreen mode Exit fullscreen mode

After the patch, cert-manager issued the certificate and the site opened fine.

SSH

gitea-ssh is created as a headless ClusterIP by default — not reachable from outside. Port 22 is taken by the system SSH, so I needed a NodePort. You can't patch a headless service into NodePort — have to delete and recreate:

kubectl delete svc gitea-ssh -n gitea

kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: gitea-ssh
  namespace: gitea
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: gitea
  ports:
    - port: 22
      targetPort: 2222
      nodePort: 30022
EOF

Enter fullscreen mode Exit fullscreen mode

Remote looks like this:

git remote add gitea ssh://git@git.logiflowadvanced.online:30022/username/repo.git

Enter fullscreen mode Exit fullscreen mode


Nextcloud

Set up the DNS for cloud.logiflowadvanced.online while Gitea was still deploying.

nextcloud-values.yaml:

ingress:
  enabled: true
  ingressClassName: nginx
  hosts:
    - host: cloud.logiflowadvanced.online
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: nextcloud-tls
      hosts:
        - cloud.logiflowadvanced.online
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-body-size: "0"

nextcloud:
  host: cloud.logiflowadvanced.online
  username: admin
  password: yourpassword

mariadb:
  enabled: true
  auth:
    password: yourdbpassword
    database: nextcloud
    username: nextcloud

postgresql:
  enabled: false

persistence:
  enabled: true
  size: 10Gi

Enter fullscreen mode Exit fullscreen mode

helm install nextcloud nextcloud/nextcloud \
  --namespace nextcloud --create-namespace \
  -f nextcloud-values.yaml

Enter fullscreen mode Exit fullscreen mode

Same ingressClassName issue — same patch, same result.

After the first login it kept redirecting to /login/cleary?=1. Nextcloud didn't know its own external address:

kubectl exec -n nextcloud deploy/nextcloud -- \
  php occ config:system:set overwriteprotocol --value="https"
kubectl exec -n nextcloud deploy/nextcloud -- \
  php occ config:system:set overwrite.cli.url \
  --value="https://cloud.logiflowadvanced.online"

Enter fullscreen mode Exit fullscreen mode

Obsidian

Created separate users for me and my friend. WebDAV URL per user:

https://cloud.logiflowadvanced.online/remote.php/dav/files/username/

Enter fullscreen mode Exit fullscreen mode

In the RemotelySave plugin: type — WebDAV, URL, login, password. Works.


The thing that ate most of my time wasn't Gitea or Nextcloud — it was ingressClassName. Neither chart sets it automatically, and without it nginx just ignores the Ingress completely. cert-manager doesn't issue anything. Browser shows self-signed, you stare at the logs, pods are all Running, no errors anywhere.

Run kubectl get ingress -n <namespace> right after deploy. If CLASS says <none> — that's your problem.

The other non-obvious one: gitea-ssh is headless and you can't patch it into a NodePort — you have to delete and recreate it. Spent a few minutes trying to patch it before actually reading the error.

With Nextcloud and MariaDB — if MariaDB didn't come up on the first deploy or you uninstalled and reinstalled, helm will complain about credential mismatch on upgrade. Just helm uninstall + kubectl delete pvc --all -n nextcloud and start fresh, it's faster than untangling the creds.