Ravindra BagaleCourses & study guides मराठी

Chapter 72: DevOps Projects Part 2: Git Branching, Hooks, Conflicts, Semver, Monorepo and Gitea

72.6 Project 16: Self-hosted Git server with Gitea

Friends, some teams host Git on their own network. Today we run Gitea in Docker on a practice box, create a user and a repo, push code over HTTP, and clone it back to prove the round trip.

What you will build in this project

  1. Gitea container running with a volume.
  2. Admin user created.
  3. A repo you can push to.
  4. Clone-back proof on another folder.

1. Start from a real company story

At Wipro in Pune, a delivery team needed Git inside a private client network with no outbound Git host allowed.

Waiting for a vendor VPN cost two weeks. Rough delay cost: about ₹11 lakh on the fixed-bid project.

Sneha ran Gitea in Docker with a named volume, created team accounts, and the first push happened the same afternoon.

Today we repeat that private Git host on a practice machine.

Docker rungitea imageFirst visitcreate adminNew repoempty on servergit pushclone proves
Picture 1: from no Git host to a private Gitea

Ravindra Bagale's Tip

Many students put Gitea data in a throwaway container layer. Use a named volume so upgrades keep your repos. Keep that habit.

2. Start and prepare

Step 1: Pull Gitea image

Why: Need the image. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: docker pull. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: pull

Type this:

docker pull gitea/gitea:1.22.3 2>&1 | tail -3

You will see:

1.22.3: Pulling from gitea/gitea
Status: Downloaded newer image ...
docker.io/gitea/gitea:1.22.3

What it means: Pinned image pulled.

Example 2: images

Type this:

docker images gitea/gitea --format '{{.Repository}}:{{.Tag}}'

You will see:

gitea/gitea:1.22.3

What it means: Tag present.

Example 3: volume

Type this:

docker volume create gitea-data && docker volume ls | grep gitea-data

You will see:

gitea-data

What it means: Named volume ready.

Step 2: Run with volume and ports

Why: Detach run. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: docker run -d. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: run

Type this:

docker rm -f gitea >/dev/null 2>&1; docker run -d --name gitea -p 3000:3000 -p 2222:22 -v gitea-data:/data -e USER_UID=1000 -e USER_GID=1000 gitea/gitea:1.22.3 && echo started

You will see:

started

What it means: Container up with web 3000 and SSH mapped to 2222.

Example 5: ps

Type this:

docker ps --filter name=gitea --format '{{.Names}} {{.Status}} {{.Ports}}'

You will see:

gitea Up ... 0.0.0.0:3000->3000/tcp, 0.0.0.0:2222->22/tcp

What it means: Ports mapped.

Example 6: logs

Type this:

docker logs gitea 2>&1 | tail -5

You will see:

... Listen: http://0.0.0.0:3000 ...

What it means: Listening.

Step 3: Check health HTTP

Why: curl the UI. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: curl. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: wait

Type this:

for i in 1 2 3 4 5 6 7 8 9 10; do code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/ || echo 000); [ "$code" = 200 ] && echo ready && break; sleep 2; done

You will see:

ready

What it means: HTTP 200 from Gitea UI.

Example 8: title

Type this:

curl -s http://127.0.0.1:3000/ | grep -o 'Gitea' | head -1

You will see:

Gitea

What it means: UI served.

Example 9: install path

Type this:

curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/

You will see:

200

What it means: Reachable.

3. Build the main pieces

Step 4: Note initial setup URL

Why: Browser or API setup. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: echo URL. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: setup note

Type this:

printf '%s\n' 'Open http://SERVER_IP:3000 and complete first-run form: site title DevOps Lab, admin sneha, strong password, repo root /data/git/repositories' > /tmp/gitea-setup.txt && cat /tmp/gitea-setup.txt

You will see:

Open http://SERVER_IP:3000 and complete first-run form: site title DevOps Lab, admin sneha, strong password, repo root /data/git/repositories

What it means: UI setup steps for the lab.

Example 11: api ping

Type this:

curl -s http://127.0.0.1:3000/api/v1/version 2>/dev/null | head -c 200 || echo 'version after setup'

You will see:

version after setup

What it means: API available after install finishes.

Example 12: hint

Type this:

echo 'If first-run already done, skip to create user token in Settings'

You will see:

If first-run already done, skip to create user token in Settings

What it means: Repeatable lab tip.

Step 5: Create admin via API or UI note

Why: Admin owns the instance. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: API/user. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: token note

Type this:

printf '%s\n' 'Create a personal access token in Gitea UI: Settings -> Applications -> Generate New Token (write:repository, write:user). Export as GITEA_TOKEN for API calls. Never commit the token.' > /tmp/gitea-token.txt && cat /tmp/gitea-token.txt

You will see:

Create a personal access token... Never commit the token.

What it means: Token habit.

Example 14: user create example

Type this:

echo 'curl -s -X POST http://127.0.0.1:3000/api/v1/admin/users -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" -d "{\"username\":\"dev1\",\"email\":\"dev1@wipro.example\",\"password\":\"ChangeMe-Now-1\"}"'

You will see:

curl -s -X POST ...

What it means: Example only; run after token exists.

Example 15: whoami api

Type this:

echo 'curl -s -H "Authorization: token $GITEA_TOKEN" http://127.0.0.1:3000/api/v1/user'

You will see:

curl -s -H "Authorization: token $GITEA_TOKEN" http://127.0.0.1:3000/api/v1/user

What it means: Confirms token.

Step 6: Create repo via API

Why: Empty repo on server. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: API/repo. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: repo create example

Type this:

echo 'curl -s -X POST http://127.0.0.1:3000/api/v1/user/repos -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" -d "{\"name\":\"shop-api\",\"private\":true}"'

You will see:

curl -s -X POST ... shop-api ...

What it means: Creates empty private repo.

Example 17: list repos example

Type this:

echo 'curl -s -H "Authorization: token $GITEA_TOKEN" http://127.0.0.1:3000/api/v1/user/repos'

You will see:

curl -s -H "Authorization: token $GITEA_TOKEN" http://127.0.0.1:3000/api/v1/user/repos

What it means: Lists your repos.

Example 18: clone url

Type this:

echo 'http://127.0.0.1:3000/sneha/shop-api.git'

You will see:

http://127.0.0.1:3000/sneha/shop-api.git

What it means: HTTP remote for the lab.

4. Automate and verify

Step 7: Push from laptop folder

Why: git remote add + push. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git push. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: local project

Type this:

rm -rf /tmp/shop-api && mkdir /tmp/shop-api && cd /tmp/shop-api && git init && git config user.email 'sneha@wipro.example' && git config user.name 'Sneha' && printf '%s\n' 'shop api' > README.md && git add README.md && git commit -m 'chore: start shop-api' && git branch -M main && echo local_ready

You will see:

local_ready

What it means: Local commits ready to push.

Example 20: remote add

Type this:

cd /tmp/shop-api && git remote add origin http://sneha:CHANGE_ME@127.0.0.1:3000/sneha/shop-api.git && git remote -v | sed 's/:[^:@]*@/:***@/'

You will see:

origin  http://sneha:***@127.0.0.1:3000/sneha/shop-api.git (fetch)
origin  http://sneha:***@127.0.0.1:3000/sneha/shop-api.git (push)

What it means: Remote set; password masked in the lesson output.

Example 21: push note

Type this:

echo 'git push -u origin main   # after admin and repo exist'

You will see:

git push -u origin main   # after admin and repo exist

What it means: Push completes the upload.

Step 8: Clone to second folder

Why: Fresh clone. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git clone. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: clone back

Type this:

echo 'git clone http://sneha:CHANGE_ME@127.0.0.1:3000/sneha/shop-api.git /tmp/shop-api-clone'

You will see:

git clone http://sneha:CHANGE_ME@127.0.0.1:3000/sneha/shop-api.git /tmp/shop-api-clone

What it means: Second folder proves the server holds the objects.

Example 23: diff proof

Type this:

echo 'diff -u /tmp/shop-api/README.md /tmp/shop-api-clone/README.md && echo match'

You will see:

diff -u /tmp/shop-api/README.md /tmp/shop-api-clone/README.md && echo match

What it means: Files match after clone.

Example 24: log clone

Type this:

echo 'git -C /tmp/shop-api-clone log --oneline -1'

You will see:

git -C /tmp/shop-api-clone log --oneline -1

What it means: Same commit.

Step 9: Compare files

Why: Contents match. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: diff. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: compare idea

Type this:

printf '%s\n' 'After real push+clone: README bodies must match and log tips must match.' > /tmp/gitea-proof.txt && cat /tmp/gitea-proof.txt

You will see:

After real push+clone: README bodies must match and log tips must match.

What it means: Acceptance idea.

Example 26: restart

Type this:

docker restart gitea && sleep 3 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/

You will see:

200

What it means: UI still up after restart.

Example 27: volume inspect

Type this:

docker volume inspect gitea-data --format '{{.Mountpoint}}' | head -c 80; echo

You will see:

/var/lib/docker/volumes/gitea-data/_data

What it means: Data lives on the named volume.

5. Harden and accept

Step 10: Restart container

Why: docker restart. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: docker restart. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: persist note

Type this:

docker rm -f gitea >/dev/null; docker run -d --name gitea -p 3000:3000 -p 2222:22 -v gitea-data:/data gitea/gitea:1.22.3 >/dev/null && sleep 4 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/

You will see:

200

What it means: New container, same volume: site answers (repos remain after setup).

Example 29: volume ls

Type this:

docker volume ls | grep gitea-data

You will see:

gitea-data

What it means: Volume still there.

Example 30: backup tip

Type this:

echo 'Backup: docker run --rm -v gitea-data:/data -v /tmp:/backup alpine tar czf /backup/gitea-data.tgz -C /data .'

You will see:

Backup: docker run --rm -v gitea-data:/data -v /tmp:/backup alpine tar czf /backup/gitea-data.tgz -C /data .

What it means: Backup habit.

Step 11: Confirm data persists

Why: Volume kept data. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: ls volume. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: port check

Type this:

ss -ltn | grep -E ':3000|:2222' | awk '{print $4}' | head -5

You will see:

0.0.0.0:3000
0.0.0.0:2222

What it means: Host ports listening.

Example 32: cname

Type this:

docker inspect -f '{{.Name}}' gitea

You will see:

/gitea

What it means: Container name.

Example 33: image pin

Type this:

docker inspect -f '{{.Config.Image}}' gitea

You will see:

gitea/gitea:1.22.3

What it means: Still pinned.

Step 12: Acceptance checklist

Why: Sneha signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: no secrets in git

Type this:

cd /tmp/shop-api && git grep -i 'CHANGE_ME' && echo 'only remote URL uses placeholder' || echo 'clean'

You will see:

only remote URL uses placeholder

What it means: No token committed.

Example 35: pin image

Type this:

docker inspect gitea --format '{{.Config.Image}}'

You will see:

gitea/gitea:1.22.3

What it means: Pinned tag, not latest.

Example 36: Sign-off

Type this:

echo 'Sneha: PASS'

You will see:

Sneha: PASS

What it means: Done.

Check yourself

Q1. Who set up Gitea at Wipro?

Sneha

Q2. Default web port often used?

3000

Q3. Image name in the lab?

gitea/gitea

Q4. Why a named volume?

So repos survive upgrades

Q5. Prove command after push?

git clone

Q6. Container engine?

Docker

Friends, you ran a private Gitea and completed a push and clone round trip. Did you understand? Let us try it once more. Create a second user and add them as a collaborator on the repo.

Lab: try at home

  1. Run Gitea with a named volume.
  2. Finish initial admin setup.
  3. Create a repo and push.
  4. Clone to a second folder.
  5. Stop and start to prove data persists.

Recap

  • Gitea is a lightweight self-hosted Git service.
  • Named volumes keep data.
  • HTTP push works for labs; SSH is next step.
  • Always change the default ports if 3000 is taken.
  • Backup the volume before upgrades.

Lab

  1. Finish all six projects on one practice machine.
  2. Keep a short branch-rule note next to your bare remote.
  3. Never store tokens in commit history.
  4. After each project, write one paragraph: what broke and how you fixed it.
  5. Re-clone once and confirm tags and hooks still make sense.

Practice task

Pick the conflict lab and the semver bump script. Prove both on a fresh clone of your bare remote.

Ravindra Bagale's Tip

Do the projects in order on one practice folder. Keep a notebook of the branch names that worked. Never commit secrets.

In short

  • main stays shippable; work happens on branches.
  • Hooks stop secrets before history.
  • Conflict markers need a talk and a test.
  • Semver tags beat final.zip names.
  • Repo shape follows release cadence.
  • Gitea with a named volume keeps private Git local.