Set up Gitea, etc.
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
Gitea Overleaf evidence package
|
||||
|
||||
Files:
|
||||
- giteaStartup.tex
|
||||
Chapter fragment to add to the group's main Overleaf document with:
|
||||
\input{giteaStartup}
|
||||
|
||||
Screenshots:
|
||||
- gitea-persistence-repository.png
|
||||
persistence-test repository after replacement
|
||||
- gitea-persistence-issue-1.png
|
||||
persistence verification issue #1
|
||||
- gitea-admin-activity.png
|
||||
Gitea activity/repository view
|
||||
- gitea-pr-issue-1-merged.png
|
||||
merged pull request for issue #1
|
||||
- gitea-pr-issue-2-merged.png
|
||||
merged pull request for issue #2
|
||||
|
||||
No passwords are included.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 371 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 412 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 394 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
@@ -0,0 +1,472 @@
|
||||
% Insert this file into the group report with:
|
||||
% \input{giteaStartup}
|
||||
%
|
||||
% Required packages in the main document:
|
||||
% \usepackage{graphicx}
|
||||
% \usepackage{minted}
|
||||
% \usepackage{hyperref}
|
||||
%
|
||||
% This chapter intentionally does not use minted's caption option. Captions
|
||||
% are written as ordinary LaTeX text so it remains compatible with the
|
||||
% minted configuration already used by the group report.
|
||||
|
||||
\chapter{Startup Foundation with Gitea}
|
||||
|
||||
\section{Overview}
|
||||
|
||||
The startup's initial operational work hub was deployed on a DigitalOcean
|
||||
Droplet using Gitea. The deployment provides a private Git service for the
|
||||
team, including repositories, issues, pull requests, and collaborative code
|
||||
review.
|
||||
|
||||
The public Git service is available at:
|
||||
|
||||
\begin{center}
|
||||
\url{https://git.ssw590.tech}
|
||||
\end{center}
|
||||
|
||||
The domain used for the service is \texttt{ssw590.tech}, and the Gitea
|
||||
hostname is \texttt{git.ssw590.tech}. The service runs on an Ubuntu
|
||||
DigitalOcean Droplet with Docker Compose. Gitea uses the official
|
||||
\texttt{gitea/gitea} container image pinned to version \texttt{1.27.3}.
|
||||
|
||||
\section{Domain and GitHub Student Developer Pack}
|
||||
|
||||
The domain \texttt{ssw590.tech} was obtained through the GitHub Student
|
||||
Developer Pack using Name.com. GitHub's current Student Developer Pack
|
||||
lists Name.com as providing a free domain from a selection of extensions,
|
||||
and separately lists the .TECH offer as one standard .TECH domain free for
|
||||
one year. Thus, the initial registration used for this project was free
|
||||
under the student offer.
|
||||
|
||||
The project domain is:
|
||||
|
||||
\begin{itemize}
|
||||
\item Domain: \texttt{ssw590.tech}
|
||||
\item Registrar: Name.com
|
||||
\item Gitea hostname: \texttt{git.ssw590.tech}
|
||||
\item Initial student-offer term: one year
|
||||
\item Automatic renewal date shown by Name.com: September 30, 2027
|
||||
\end{itemize}
|
||||
|
||||
The renewal price is not a fixed GitHub Student Developer Pack price.
|
||||
Name.com states that renewals are charged at the then-current renewal fee.
|
||||
The automatic-renewal setting is enabled for this domain. This means the
|
||||
team must maintain a valid payment method if the domain is to remain active
|
||||
after the student-offer term.
|
||||
|
||||
\section{DNS Configuration}
|
||||
|
||||
The DNS record for the Gitea service points the hostname
|
||||
\texttt{git.ssw590.tech} to the DigitalOcean Droplet's public IPv4 address:
|
||||
|
||||
\begin{center}
|
||||
\texttt{157.230.10.81}
|
||||
\end{center}
|
||||
|
||||
The hostname was verified independently by accessing it from outside the
|
||||
Droplet. The HTTPS request succeeded, demonstrating that the hostname
|
||||
resolved to the deployed service and that the service was reachable through
|
||||
the public Internet.
|
||||
|
||||
A command-line DNS lookup can also be recorded in the final submission:
|
||||
|
||||
\begin{minted}{bash}
|
||||
dig +short git.ssw590.tech A
|
||||
\end{minted}
|
||||
|
||||
The expected result is the Droplet's public IPv4 address.
|
||||
|
||||
\section{DigitalOcean Droplet and Docker}
|
||||
|
||||
The DigitalOcean Droplet runs Ubuntu and was configured for password-based
|
||||
SSH authentication. The Droplet was accessed with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
ssh root@157.230.10.81
|
||||
\end{minted}
|
||||
|
||||
Docker Engine and Docker Compose were installed on the Droplet. The final
|
||||
Gitea deployment was managed from:
|
||||
|
||||
\begin{minted}{bash}
|
||||
cd ~/gitea
|
||||
\end{minted}
|
||||
|
||||
The Gitea Compose configuration pins the official image to version
|
||||
\texttt{1.27.3} rather than using an unversioned \texttt{latest} tag.
|
||||
|
||||
\begin{minted}{yaml}
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:1.27.3
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./data/gitea:/data
|
||||
networks:
|
||||
- gitea
|
||||
|
||||
networks:
|
||||
gitea:
|
||||
driver: bridge
|
||||
\end{minted}
|
||||
|
||||
The official image source is the Gitea container repository:
|
||||
\url{https://hub.docker.com/r/gitea/gitea}.
|
||||
|
||||
The image version was verified with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose ps
|
||||
\end{minted}
|
||||
|
||||
The resulting service showed:
|
||||
|
||||
\begin{minted}{text}
|
||||
gitea/gitea:1.27.3
|
||||
\end{minted}
|
||||
|
||||
\section{SQLite Database}
|
||||
|
||||
SQLite was selected for the Gitea database because the deployment is a
|
||||
small startup work hub and does not require a separate database service for
|
||||
this assignment.
|
||||
|
||||
The Gitea configuration contains:
|
||||
|
||||
\begin{minted}{text}
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /data/gitea/gitea.db
|
||||
\end{minted}
|
||||
|
||||
The database file exists inside the persistent Docker bind mount. It was
|
||||
verified on the Droplet with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
ls -lh ~/gitea/data/gitea/gitea/gitea.db
|
||||
\end{minted}
|
||||
|
||||
The file was approximately 2.1 MB at the time of verification.
|
||||
|
||||
The corresponding file inside the container was also verified:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker exec gitea ls -lh /data/gitea/gitea.db
|
||||
\end{minted}
|
||||
|
||||
\section{Persistent Storage}
|
||||
|
||||
The Docker Compose configuration maps the host directory
|
||||
\texttt{./data/gitea} to \texttt{/data} inside the Gitea container:
|
||||
|
||||
\begin{minted}{yaml}
|
||||
volumes:
|
||||
- ./data/gitea:/data
|
||||
\end{minted}
|
||||
|
||||
This is important because Gitea stores its database, repositories, SSH
|
||||
configuration, attachments, package data, indexes, and other application
|
||||
state below \texttt{/data}. The database was observed on the host at:
|
||||
|
||||
\begin{minted}{text}
|
||||
/root/gitea/data/gitea/gitea/gitea.db
|
||||
\end{minted}
|
||||
|
||||
The mount itself was inspected with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker inspect gitea --format '{{json .Mounts}}'
|
||||
\end{minted}
|
||||
|
||||
The result showed the host path
|
||||
\texttt{/root/gitea/data/gitea} mounted read/write at \texttt{/data}.
|
||||
|
||||
\section{Container Replacement and Persistence Test}
|
||||
|
||||
Persistence was explicitly tested by recording the existing container,
|
||||
recreating it, and then checking that Gitea data remained available.
|
||||
|
||||
Before replacement, the container identity was recorded with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker inspect gitea --format '{{.Id}}'
|
||||
\end{minted}
|
||||
|
||||
The persistent mount was also recorded with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker inspect gitea --format '{{json .Mounts}}'
|
||||
\end{minted}
|
||||
|
||||
The Gitea service was then force-recreated:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose up -d --force-recreate gitea
|
||||
\end{minted}
|
||||
|
||||
After the replacement, the running services were verified with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose ps
|
||||
\end{minted}
|
||||
|
||||
The new container continued to use the same host-backed data directory.
|
||||
The SQLite database remained present:
|
||||
|
||||
\begin{minted}{bash}
|
||||
ls -lh ~/gitea/data/gitea/gitea/gitea.db
|
||||
\end{minted}
|
||||
|
||||
The Gitea repository and issue used for the persistence test also remained
|
||||
available after the replacement. This demonstrates that the application
|
||||
state was stored in the persistent volume rather than only in the
|
||||
container's writable layer.
|
||||
|
||||
\section{Persistence Evidence}
|
||||
|
||||
Figure~\ref{fig:gitea-persistence-repository} shows the
|
||||
\texttt{persistence-test} repository after the container replacement.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.90\textwidth]{gitea-persistence-repository.png}
|
||||
\caption{Gitea persistence-test repository after container replacement}
|
||||
\label{fig:gitea-persistence-repository}
|
||||
\end{figure}
|
||||
|
||||
Figure~\ref{fig:gitea-persistence-issue} shows issue \#1 from the same
|
||||
repository after the replacement.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.90\textwidth]{gitea-persistence-issue-1.png}
|
||||
\caption{Persistence verification issue \#1 after container replacement}
|
||||
\label{fig:gitea-persistence-issue}
|
||||
\end{figure}
|
||||
|
||||
\section{Startup Repository and Team Collaboration}
|
||||
|
||||
The startup repository used for the development workflow is
|
||||
\texttt{ssw590-startup}. No separate Gitea organization was required for
|
||||
the assignment, so the repository itself is used as the team's shared
|
||||
workspace.
|
||||
|
||||
Team members were added to the Gitea project using their individual
|
||||
accounts. The usernames used for the team accounts are:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{mfriedma1}
|
||||
\item \texttt{alexn41}
|
||||
\item \texttt{so.stoeckel}
|
||||
\end{itemize}
|
||||
|
||||
Passwords are intentionally not included in the report.
|
||||
|
||||
The repository README was completed, and five issues were created and
|
||||
assigned as part of the team's issue-driven development workflow.
|
||||
|
||||
\section{Issue and Pull Request Workflow}
|
||||
|
||||
The first implementation task was tracked as issue \#1,
|
||||
``Implement product landing page.'' A feature branch named
|
||||
\texttt{feature/issue-1-landing-page} was used for the implementation.
|
||||
The work was submitted as a pull request and reviewed before being merged
|
||||
into \texttt{main}.
|
||||
|
||||
Figure~\ref{fig:gitea-pr-issue-1} shows the merged pull request for issue
|
||||
\#1. The screenshot records the assignment, commit, review comment,
|
||||
merge, and deletion of the feature branch.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.90\textwidth]{gitea-pr-issue-1-merged.png}
|
||||
\caption{Merged pull request implementing issue \#1}
|
||||
\label{fig:gitea-pr-issue-1}
|
||||
\end{figure}
|
||||
|
||||
The second implementation task was tracked as issue \#2 and used the
|
||||
feature branch \texttt{feature/issue-2-tests}. The pull request added the
|
||||
repository validation tests and was merged into \texttt{main}.
|
||||
|
||||
Figure~\ref{fig:gitea-pr-issue-2} shows the completed merge.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.90\textwidth]{gitea-pr-issue-2-merged.png}
|
||||
\caption{Merged pull request for issue \#2 repository validation tests}
|
||||
\label{fig:gitea-pr-issue-2}
|
||||
\end{figure}
|
||||
|
||||
Figure~\ref{fig:gitea-activity} shows the Gitea activity view containing
|
||||
the repository and issue activity.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.90\textwidth]{gitea-admin-activity.png}
|
||||
\caption{Gitea repository and issue activity}
|
||||
\label{fig:gitea-activity}
|
||||
\end{figure}
|
||||
|
||||
\section{HTTPS with Caddy and Let's Encrypt}
|
||||
|
||||
Gitea is not directly exposed to the public Internet on port 3000 in the
|
||||
final deployment. A Caddy reverse proxy is used in front of Gitea.
|
||||
|
||||
The final service layout is:
|
||||
|
||||
\begin{center}
|
||||
\texttt{Internet -> Caddy :443 -> Gitea :3000}
|
||||
\end{center}
|
||||
|
||||
Caddy publishes ports 80 and 443 on the Droplet while Gitea's port 3000 is
|
||||
kept internal to the Docker network. The Gitea container therefore shows
|
||||
port 3000 as an internal container port rather than as a host-published
|
||||
port.
|
||||
|
||||
The current service state was verified with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose ps
|
||||
\end{minted}
|
||||
|
||||
The output showed Caddy publishing ports 80 and 443 and Gitea exposing
|
||||
port 3000 only to the Docker network.
|
||||
|
||||
Gitea's public URL was configured as:
|
||||
|
||||
\begin{minted}{text}
|
||||
DOMAIN = git.ssw590.tech
|
||||
ROOT_URL = https://git.ssw590.tech
|
||||
\end{minted}
|
||||
|
||||
\section{Let's Encrypt Certificate Verification}
|
||||
|
||||
Caddy automatically obtained a Let's Encrypt certificate for
|
||||
\texttt{git.ssw590.tech}. The Caddy log showed successful ACME
|
||||
authorization and certificate issuance.
|
||||
|
||||
The live HTTPS service was verified externally with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
curl -4 -I https://git.ssw590.tech
|
||||
\end{minted}
|
||||
|
||||
The response was HTTP/2 200.
|
||||
|
||||
Plain HTTP was also tested:
|
||||
|
||||
\begin{minted}{bash}
|
||||
curl -4 -I http://git.ssw590.tech
|
||||
\end{minted}
|
||||
|
||||
The response was:
|
||||
|
||||
\begin{minted}{text}
|
||||
HTTP/1.1 308 Permanent Redirect
|
||||
Location: https://git.ssw590.tech/
|
||||
\end{minted}
|
||||
|
||||
This demonstrates that HTTP requests are redirected to HTTPS.
|
||||
|
||||
The certificate itself was inspected with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
echo | openssl s_client \
|
||||
-connect git.ssw590.tech:443 \
|
||||
-servername git.ssw590.tech 2>/dev/null \
|
||||
| openssl x509 -noout -issuer -subject -dates
|
||||
\end{minted}
|
||||
|
||||
The observed certificate information was:
|
||||
|
||||
\begin{minted}{text}
|
||||
issuer=... Let's Encrypt ...
|
||||
subject=CN = git.ssw590.tech
|
||||
notBefore=Sep 30 17:50:34 2026 GMT
|
||||
notAfter=Dec 29 17:50:33 2026 GMT
|
||||
\end{minted}
|
||||
|
||||
Caddy's automatic certificate management is also responsible for renewal,
|
||||
so a separate manual renewal job is not required.
|
||||
|
||||
\section{Firewall Configuration}
|
||||
|
||||
The DigitalOcean Cloud Firewall was configured to allow the ports required
|
||||
by the deployment:
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{lll}
|
||||
\textbf{Protocol} & \textbf{Port} & \textbf{Source} \\
|
||||
TCP & 22 & All IPv4 \\
|
||||
TCP & 80 & All IPv4 and All IPv6 \\
|
||||
TCP & 443 & All IPv4 and All IPv6
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
Port 80 is required for normal HTTP access and HTTP-to-HTTPS redirection,
|
||||
while port 443 provides the public HTTPS service. SSH on port 22 is used
|
||||
for administration.
|
||||
|
||||
Port 3000 is not opened in the DigitalOcean firewall. An external
|
||||
connection test to the public address on port 3000 timed out, while
|
||||
external access to ports 80 and 443 succeeded. This confirms that Gitea
|
||||
is reached through Caddy rather than directly through its application port.
|
||||
|
||||
\section{Restart Behavior}
|
||||
|
||||
The Compose service uses:
|
||||
|
||||
\begin{minted}{yaml}
|
||||
restart: unless-stopped
|
||||
\end{minted}
|
||||
|
||||
This instructs Docker to restart Gitea after an unexpected container or
|
||||
Docker daemon restart, while still allowing an intentional manual stop to
|
||||
remain stopped.
|
||||
|
||||
The deployment can therefore be brought back up with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose up -d
|
||||
\end{minted}
|
||||
|
||||
and its state checked with:
|
||||
|
||||
\begin{minted}{bash}
|
||||
docker compose ps
|
||||
\end{minted}
|
||||
|
||||
\section{Deployment Summary}
|
||||
|
||||
The completed startup work hub has the following architecture:
|
||||
|
||||
\begin{enumerate}
|
||||
\item \texttt{ssw590.tech} was registered using the GitHub Student
|
||||
Developer Pack offer through Name.com.
|
||||
\item \texttt{git.ssw590.tech} was configured to resolve to the
|
||||
DigitalOcean Droplet.
|
||||
\item Gitea \texttt{1.27.3} was deployed using the official
|
||||
\texttt{gitea/gitea} image.
|
||||
\item SQLite was selected for the Gitea database.
|
||||
\item Gitea application data was stored in the persistent
|
||||
\texttt{./data/gitea:/data} bind mount.
|
||||
\item Container replacement was tested and the repository and issue
|
||||
data persisted.
|
||||
\item The \texttt{ssw590-startup} repository was created for team
|
||||
collaboration.
|
||||
\item Team members were added and issues were assigned.
|
||||
\item Pull requests were used to review and merge work into
|
||||
\texttt{main}.
|
||||
\item Caddy was placed in front of Gitea as a reverse proxy.
|
||||
\item Let's Encrypt provided the live TLS certificate for
|
||||
\texttt{git.ssw590.tech}.
|
||||
\item HTTP was redirected to HTTPS.
|
||||
\item Port 3000 remained closed to external clients.
|
||||
\end{enumerate}
|
||||
|
||||
The resulting deployment provides the team with a persistent,
|
||||
version-pinned, HTTPS-protected Git service suitable for the startup's
|
||||
initial development workflow.
|
||||
Reference in New Issue
Block a user