Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89359a6ce3 | ||
|
|
1d7c528795 | ||
|
|
0cd8561d44 | ||
|
|
aeba4fe443 |
No files matched your search
@@ -0,0 +1,58 @@
|
|||||||
|
# Inviscid
|
||||||
|
|
||||||
|
Inviscid is a proposed startup that helps small businesses monitor the health
|
||||||
|
and performance of their web applications. Customers would use a dashboard to
|
||||||
|
see availability, response times, request volume, and error rates, paired with
|
||||||
|
plain-language status summaries such as "Your website is responding slowly."
|
||||||
|
|
||||||
|
The semester prototype targets one demonstration customer application, building
|
||||||
|
on the team's existing Node.js website. Monitoring, the dashboard,
|
||||||
|
and deployment automation are **planned work, not completed features**. See the
|
||||||
|
Project Proposal chapter of the manual for the full plan and the Prometheus vs.
|
||||||
|
VictoriaMetrics comparison.
|
||||||
|
|
||||||
|
## Repository contents
|
||||||
|
|
||||||
|
| Path | Contents |
|
||||||
|
|---|---|
|
||||||
|
| `devopsAssignment.tex`, `chapters/`, `frontmatter/`, `backmatter/`, `figures/` | The team's LaTeX DevOps IT manual (SSW 590) |
|
||||||
|
| `docker/gitea/` | Versioned deployment files for the Gitea work hub (Compose, Caddyfile, deployment README) |
|
||||||
|
| `docker/color-buttons/` | Color Buttons demonstration app (Node.js/Express, Dockerfile) |
|
||||||
|
| `docker/latex-compiler/` | Docker image for compiling the manual |
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- Gitea work hub: <https://git.inviscid.dev/>
|
||||||
|
- This repository: <https://git.inviscid.dev/Inviscid/SSW590-DevOps>
|
||||||
|
- Deployment documentation: [`docker/gitea/README.md`](docker/gitea/README.md)
|
||||||
|
|
||||||
|
## Building the manual
|
||||||
|
|
||||||
|
The manual uses `minted`, which needs shell escape and the `latexminted`
|
||||||
|
helper. Overleaf compiles it as-is. Locally:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
latexmk -pdf devopsAssignment.tex
|
||||||
|
```
|
||||||
|
|
||||||
|
`latexmkrc` enables `-shell-escape` and runs `makeglossaries` automatically.
|
||||||
|
|
||||||
|
## Team
|
||||||
|
|
||||||
|
| Member | Gitea account | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| Victor | `victor` | Organization owner; site administrator; domain, DNS, and Gitea deployment |
|
||||||
|
| Payton | `payton` | Organization owner; HTTPS, firewall, persistence testing, repository workflow |
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Open an issue with a short description and acceptance criteria.
|
||||||
|
2. Create a branch from `main`.
|
||||||
|
3. Open a pull request into `main` and reference the issue with `Closes #N`.
|
||||||
|
4. Request a review from the other team member; merge only after approval.
|
||||||
|
5. Confirm the linked issue closed.
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
Never commit passwords, tokens, private keys, `app.ini`, database files, or
|
||||||
|
volume contents. The manual's Passwords table contains hints only.
|
||||||
@@ -374,9 +374,16 @@ not confirmed. Payton has taken ownership of the remaining Gitea tasks.
|
|||||||
The initial main push is not counted as a reviewed PR.
|
The initial main push is not counted as a reviewed PR.
|
||||||
|
|
||||||
\section{Architecture and Operation}
|
\section{Architecture and Operation}
|
||||||
The current private initialization path is shown in
|
Figure~\ref{Figure:GiteaArchitecture} shows the deployed request and data paths.
|
||||||
Figure~\ref{Figure:GiteaInitialPath}. Payton will add a final deployment diagram
|
\begin{figure}[htbp]
|
||||||
showing browser HTTPS to Caddy and private forwarding to Gitea.
|
\centering
|
||||||
|
\resizebox{\linewidth}{!}{\input{figures/devopsGiteaFoundation/giteaArchitecture}}
|
||||||
|
\caption{October 15: deployed architecture. The security group admits 443 and 80 from any source and 22 only from approved team addresses. Caddy is the only container publishing host ports; Gitea, the Color Buttons app, and both data volumes are private.}
|
||||||
|
\label{Figure:GiteaArchitecture}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
The initial October 12 access path, before Caddy was deployed, is kept for
|
||||||
|
reference in Figure~\ref{Figure:GiteaInitialPath}.
|
||||||
\begin{figure}[htbp]
|
\begin{figure}[htbp]
|
||||||
\centering
|
\centering
|
||||||
\fbox{\parbox{0.92\linewidth}{\centering
|
\fbox{\parbox{0.92\linewidth}{\centering
|
||||||
@@ -387,7 +394,7 @@ $\downarrow$ EC2: 100.49.80.94\\
|
|||||||
EC2 loopback:3000 to Gitea container:3000\\
|
EC2 loopback:3000 to Gitea container:3000\\
|
||||||
$\downarrow$ persistent named volume\\
|
$\downarrow$ persistent named volume\\
|
||||||
\texttt{inviscid\_gitea\_data}: repositories, SQLite, configuration}}
|
\texttt{inviscid\_gitea\_data}: repositories, SQLite, configuration}}
|
||||||
\caption{Initial SSH-tunnel access path. Caddy and hostname-based HTTPS are not yet verified.}
|
\caption{October 12: initial SSH-tunnel-only access path, before Caddy and hostname-based HTTPS were deployed.}
|
||||||
\label{Figure:GiteaInitialPath}
|
\label{Figure:GiteaInitialPath}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
@@ -406,8 +413,40 @@ The following are operational commands, not additional claimed test results:
|
|||||||
cd ~/gitea
|
cd ~/gitea
|
||||||
sudo docker compose ps
|
sudo docker compose ps
|
||||||
sudo docker compose logs --tail=40 gitea
|
sudo docker compose logs --tail=40 gitea
|
||||||
|
sudo docker compose logs --tail=40 caddy
|
||||||
sudo docker compose restart gitea
|
sudo docker compose restart gitea
|
||||||
|
sudo docker compose restart caddy
|
||||||
\end{minted}
|
\end{minted}
|
||||||
|
|
||||||
|
\paragraph{Where data lives.} Repositories, attachments, Gitea configuration,
|
||||||
|
and the SQLite database (\path{/data/gitea/gitea.db}) live in the named volume
|
||||||
|
\texttt{inviscid\_gitea\_data}. Certificates and the ACME account live in
|
||||||
|
\texttt{inviscid\_caddy\_data} (with \texttt{inviscid\_caddy\_config}). All
|
||||||
|
three volumes are on the instance's EBS disk, outside the disposable container
|
||||||
|
layers. Deployment files are versioned in \path{docker/gitea/} of the repository.
|
||||||
|
|
||||||
|
\paragraph{Public and private interfaces.} Public: TCP 443 (HTTPS to Caddy) and
|
||||||
|
TCP 80 (redirect to HTTPS, ACME validation, and the Color Buttons app by IP),
|
||||||
|
both from any source. Restricted: TCP 22 (administrative SSH) from approved team
|
||||||
|
addresses only. Private: Gitea's port 3000 (reachable only on the Compose network
|
||||||
|
and EC2 loopback), the Color Buttons container's port 3000, Caddy's admin port
|
||||||
|
2019, and the SQLite file, which has no network port.
|
||||||
|
|
||||||
|
\paragraph{Troubleshooting.} If \url{https://git.inviscid.dev} fails, check in
|
||||||
|
order: (1) \texttt{docker compose ps} shows both services running; (2) the Caddy
|
||||||
|
log shows no certificate or upstream errors; (3) the Gitea log shows it listening
|
||||||
|
on port 3000; (4) \texttt{curl -I http://127.0.0.1:3000/} on EC2 returns 200,
|
||||||
|
which isolates Gitea from Caddy; (5) DNS still resolves to the Elastic IP and the
|
||||||
|
security group still admits 443. Restarting one service leaves its volume intact.
|
||||||
|
|
||||||
|
\paragraph{Persistence test versus backup/restore.} The container-replacement
|
||||||
|
test shows that data survives when the Gitea \emph{container} is discarded,
|
||||||
|
because the named volume is reattached. It does not protect against loss of the
|
||||||
|
volume, the EBS disk, or the instance, and it creates no copy elsewhere. A
|
||||||
|
backup/restore test would copy the volume and database to separate storage and
|
||||||
|
prove recovery into a different instance; that optional exercise
|
||||||
|
(Section~2.8 of the assignment) was not performed.
|
||||||
|
|
||||||
Closing a workstation tunnel does not stop Gitea on EC2. Reconnect the tunnel
|
Closing a workstation tunnel does not stop Gitea on EC2. Reconnect the tunnel
|
||||||
for browser access. Container replacement should retain the named volume;
|
for browser access. Container replacement should retain the named volume;
|
||||||
never delete that volume as part of the persistence check. Before destructive
|
never delete that volume as part of the persistence check. Before destructive
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
\usepackage{minted}
|
\usepackage{minted}
|
||||||
\setminted{fontsize=\footnotesize,breaklines,frame=single}
|
\setminted{fontsize=\footnotesize,breaklines,frame=single}
|
||||||
\usepackage{tcolorbox}
|
\usepackage{tcolorbox}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usetikzlibrary{positioning,arrows.meta,fit,backgrounds}
|
||||||
\usepackage{makeidx}
|
\usepackage{makeidx}
|
||||||
\usepackage[colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue]{hyperref}
|
\usepackage[colorlinks=true,citecolor=blue,linkcolor=blue,urlcolor=blue]{hyperref}
|
||||||
\usepackage[acronym,toc]{glossaries}
|
\usepackage[acronym,toc]{glossaries}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
git.inviscid.dev {
|
||||||
|
reverse_proxy gitea:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
http://100.49.80.94, http://ec2-100-49-80-94.compute-1.amazonaws.com {
|
||||||
|
reverse_proxy ssw590-group-buttons:3000
|
||||||
|
}
|
||||||
+24
-43
@@ -1,13 +1,16 @@
|
|||||||
# Inviscid Gitea foundation
|
# Inviscid Gitea foundation
|
||||||
|
|
||||||
This is the temporary, Gitea-only deployment used before the domain was registered; retain it as the initial deployment configuration.
|
This directory deploys Gitea at https://git.inviscid.dev/ behind a Caddy reverse proxy.
|
||||||
The official image version is pinned; verify that it pulls before starting the service.
|
The official image version is pinned.
|
||||||
SQLite is `/data/gitea/gitea.db`; repositories and other application data share the
|
SQLite is `/data/gitea/gitea.db`; repositories and other application data share the
|
||||||
persistent named volume `inviscid_gitea_data`. Container replacement must preserve it.
|
persistent named volume `inviscid_gitea_data`.
|
||||||
Never run `docker compose down --volumes` against the working service.
|
Never run `docker compose down --volumes` against the working service.
|
||||||
|
|
||||||
Only EC2 loopback port 3000 is published. Initial browser access uses an SSH tunnel.
|
Only Caddy publishes host ports (80 and 443). Caddy terminates TLS and forwards to
|
||||||
The existing Color Buttons container remains unchanged on port 80.
|
`gitea:3000` over the private `inviscid_services` network. Gitea's port 3000 is also
|
||||||
|
bound to EC2 loopback only, for SSH-tunnel administration.
|
||||||
|
The Color Buttons container (`ssw590-group-buttons`) no longer publishes port 80; it
|
||||||
|
runs on `inviscid_services` and Caddy serves it at http://100.49.80.94.
|
||||||
No public backend or Git SSH firewall rule is needed.
|
No public backend or Git SSH firewall rule is needed.
|
||||||
|
|
||||||
From this directory on EC2:
|
From this directory on EC2:
|
||||||
@@ -19,30 +22,18 @@ sudo docker compose up -d
|
|||||||
sudo docker compose ps
|
sudo docker compose ps
|
||||||
```
|
```
|
||||||
|
|
||||||
This initial configuration is NOT the final hostname-based HTTPS deployment.
|
`Caddyfile` must be in this directory before `up`; if it is missing, Docker creates a
|
||||||
After domain registration, replace DOMAIN and ROOT_URL with the actual hostname
|
directory in its place and Caddy fails to start. Caddy obtains and renews the
|
||||||
and HTTPS URL. Payton can attach Caddy to `inviscid_services` and forward to
|
Let's Encrypt certificate automatically; certificate state persists in the
|
||||||
`gitea:3000`, publish the proxy web ports, persist certificate state, and resolve
|
`inviscid_caddy_data` and `inviscid_caddy_config` volumes.
|
||||||
the existing website's port-80 mapping. Remove the loopback mapping if no longer needed.
|
|
||||||
|
|
||||||
Self-registration is disabled. Create the initial administrator through the installer;
|
The Color Buttons container is managed outside Compose. To recreate it without a
|
||||||
create Payton's separate account using administration after initialization.
|
published port:
|
||||||
Keep passwords, app.ini, database files, and volume contents out of Git and screenshots.
|
|
||||||
|
|
||||||
Sources:
|
```sh
|
||||||
- https://docs.gitea.com/installation/install-with-docker/
|
sudo docker run -d --name ssw590-group-buttons --restart unless-stopped \
|
||||||
- https://docs.gitea.com/administration/config-cheat-sheet/
|
--network inviscid_services ssw590-group-buttons
|
||||||
|
```
|
||||||
## Recorded deployment (October 12, 2026)
|
|
||||||
|
|
||||||
- EC2: `ssw590-group-web`, `i-025a57432604c8d4b`, us-east-1.
|
|
||||||
- Current public Elastic IP: `100.49.80.94` (replaces `54.221.175.174`).
|
|
||||||
- Remote configuration directory: `/home/ubuntu/gitea`.
|
|
||||||
- Observed image digest: `docker.gitea.com/gitea@sha256:f505a0d3a41323b786e05942fc7a4075e07ae7c169fd9485649aa55ee543a21a`.
|
|
||||||
- Gitea initialized with site title Inviscid; victor is administrator and payton is a regular user.
|
|
||||||
- Local HTTP check returned 200; named-volume mount and SQLite file were verified.
|
|
||||||
- Both containers remained running following Elastic IP association.
|
|
||||||
- This October 12 configuration predates domain registration; see the October 15 update below.
|
|
||||||
|
|
||||||
For private browser access, use your own authorized key:
|
For private browser access, use your own authorized key:
|
||||||
|
|
||||||
@@ -53,20 +44,10 @@ ssh -i /path/to/your-private-key -o ExitOnForwardFailure=yes -N -L 127.0.0.1:300
|
|||||||
Open http://localhost:3000 while the tunnel stays open. Each team member must
|
Open http://localhost:3000 while the tunnel stays open. Each team member must
|
||||||
have their public key authorized and their source IP allowed for administrative SSH.
|
have their public key authorized and their source IP allowed for administrative SSH.
|
||||||
|
|
||||||
## October 15 handoff update
|
Keep passwords, app.ini, database files, and volume contents out of Git and screenshots.
|
||||||
|
|
||||||
- Student Pack domain offer redeemed: `inviscid.dev`, Name.com, one year at $0.00.
|
Sources:
|
||||||
- Displayed renewal: October 15, 2027 at $22.99; auto-renew enabled. Victor owns renewal.
|
- https://docs.gitea.com/installation/install-with-docker/
|
||||||
- Saved A record: `git.inviscid.dev` -> `100.49.80.94`, TTL 300.
|
- https://docs.gitea.com/administration/config-cheat-sheet/
|
||||||
- Windows lookups via 1.1.1.1 and 8.8.8.8 both returned that IP at 19:17 EDT.
|
- https://caddyserver.com/docs/running#docker-compose
|
||||||
- Both users are organization owners of `Inviscid`; Payton's SSH/Gitea access works per Victor.
|
- https://caddyserver.com/docs/automatic-https
|
||||||
- Existing main history pushed to `Inviscid/SSW590-DevOps`; issue #1 and PR #2 created.
|
|
||||||
- PR #2 (`da6a369`, `codex/gitea-foundation-docs`) awaits Payton's review and merge.
|
|
||||||
- Payton owns the remaining Gitea tasks; Victor will review his separate PR.
|
|
||||||
- Public HTTPS, renewal tests, external exposure, container replacement persistence,
|
|
||||||
README/five-issue completion, and two completed reviewed PR workflows are not yet verified.
|
|
||||||
|
|
||||||
Payton: update DOMAIN to `git.inviscid.dev` and ROOT_URL to
|
|
||||||
`https://git.inviscid.dev/` alongside Caddy configuration. The tracked Compose
|
|
||||||
file still intentionally records the initial localhost setup; do not interpret
|
|
||||||
the new DNS record as proof that HTTPS has been deployed.
|
|
||||||
@@ -9,9 +9,8 @@ services:
|
|||||||
USER_GID: "1000"
|
USER_GID: "1000"
|
||||||
GITEA__database__DB_TYPE: sqlite3
|
GITEA__database__DB_TYPE: sqlite3
|
||||||
GITEA__database__PATH: /data/gitea/gitea.db
|
GITEA__database__PATH: /data/gitea/gitea.db
|
||||||
# Temporary URLs for SSH-tunnel initialization; replace after registration.
|
GITEA__server__DOMAIN: git.inviscid.dev
|
||||||
GITEA__server__DOMAIN: localhost
|
GITEA__server__ROOT_URL: https://git.inviscid.dev/
|
||||||
GITEA__server__ROOT_URL: http://localhost:3000/
|
|
||||||
GITEA__server__HTTP_PORT: "3000"
|
GITEA__server__HTTP_PORT: "3000"
|
||||||
GITEA__server__DISABLE_SSH: "true"
|
GITEA__server__DISABLE_SSH: "true"
|
||||||
GITEA__service__DISABLE_REGISTRATION: "true"
|
GITEA__service__DISABLE_REGISTRATION: "true"
|
||||||
@@ -22,9 +21,28 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- services
|
- services
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:2.10.2
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
networks:
|
||||||
|
- services
|
||||||
|
depends_on:
|
||||||
|
- gitea
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
gitea_data:
|
gitea_data:
|
||||||
name: inviscid_gitea_data
|
name: inviscid_gitea_data
|
||||||
|
caddy_data:
|
||||||
|
name: inviscid_caddy_data
|
||||||
|
caddy_config:
|
||||||
|
name: inviscid_caddy_config
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\footnotesize,
|
||||||
|
>={Stealth[length=2mm]},
|
||||||
|
box/.style={draw, rounded corners=2pt, align=center, fill=white, inner sep=3pt},
|
||||||
|
ctr/.style={box, fill=devopsLightBlue, text width=34mm},
|
||||||
|
vol/.style={box, fill=devopsGray!12, text width=36mm},
|
||||||
|
ext/.style={box, text width=30mm},
|
||||||
|
pub/.style={->, thick, devopsBlue},
|
||||||
|
priv/.style={->, thick, devopsGreen},
|
||||||
|
adm/.style={->, thick, devopsGray, dashed},
|
||||||
|
blk/.style={->, thick, devopsRed, densely dotted},
|
||||||
|
lbl/.style={font=\scriptsize, fill=white, inner sep=1pt}
|
||||||
|
]
|
||||||
|
% External clients
|
||||||
|
\node[ext] (browser) at (0, 2.55) {Browser / Git client (any source)};
|
||||||
|
\node[ext] (ip) at (0, 1.5) {Instructor browser\\\texttt{\scriptsize http://100.49.80.94}};
|
||||||
|
\node[ext] (admin) at (0,-0.8) {Team admin (approved /32 sources)};
|
||||||
|
\node[ext] (scan) at (0,-2.5) {Any other source};
|
||||||
|
|
||||||
|
% EC2 contents
|
||||||
|
\node[vol] (cdata) at (6.6, 4.8) {\textbf{Volume} \texttt{\scriptsize inviscid\_caddy\_data}\\certificates, ACME account};
|
||||||
|
\node[ctr] (caddy) at (6.6, 2.15) {\textbf{Caddy} \texttt{\scriptsize caddy:2.10.2}\\TLS termination;\\only 80/443 publisher};
|
||||||
|
\node[ctr] (gitea) at (11.4, 3.0) {\textbf{Gitea} \texttt{\scriptsize 28.1.0}\\\texttt{\scriptsize gitea:3000}};
|
||||||
|
\node[ctr, text width=40mm] (buttons) at (11.4, 1.3) {\textbf{Color Buttons}\\\texttt{\scriptsize ssw590-group-buttons:3000}};
|
||||||
|
\node[vol] (gdata) at (16.0, 3.0) {\textbf{Volume} \texttt{\scriptsize inviscid\_gitea\_data}\\repositories, config,\\SQLite \texttt{\scriptsize gitea.db}};
|
||||||
|
\node[box, text width=34mm] (sshd) at (6.6,-0.8) {\textbf{sshd} (EC2 host), TCP 22};
|
||||||
|
|
||||||
|
\begin{scope}[on background layer]
|
||||||
|
\node[draw=devopsGreen, dashed, rounded corners, fill=devopsGreen!5, inner sep=3mm,
|
||||||
|
fit=(caddy)(gitea)(buttons),
|
||||||
|
label={[font=\scriptsize, text=devopsGreen, anchor=north west, yshift=-1pt]south west:Docker network \texttt{inviscid\_services} (private)}] (net) {};
|
||||||
|
\node[draw=devopsBlue, thick, rounded corners, inner sep=4mm,
|
||||||
|
fit=(net)(sshd)(gdata)(cdata),
|
||||||
|
label={[font=\scriptsize\bfseries, text=devopsBlue]above:EC2 \texttt{ssw590-group-web} (\texttt{us-east-1}) --- Elastic IP 100.49.80.94, no IPv6}] (ec2) {};
|
||||||
|
\end{scope}
|
||||||
|
|
||||||
|
% Security group wall
|
||||||
|
\coordinate (sgTop) at (3.25, 5.9);
|
||||||
|
\coordinate (sgBot) at (3.25,-3.0);
|
||||||
|
\draw[line width=2pt, devopsRed] (sgTop) -- (sgBot);
|
||||||
|
\node[font=\scriptsize, text=devopsRed, align=center, anchor=north, fill=white, inner sep=1pt] at ([yshift=-1mm]sgTop) {Security group\\\texttt{ssw590-web-sg}};
|
||||||
|
|
||||||
|
% Public flows (allowed by the security group)
|
||||||
|
\draw[pub] (browser.east) -- node[lbl, above, pos=0.72]{443; 80$\to$308} (caddy.west |- browser.east);
|
||||||
|
\draw[pub] (ip.east) -- node[lbl, above, pos=0.72]{80 HTTP} (caddy.west |- ip.east);
|
||||||
|
|
||||||
|
% Private flows
|
||||||
|
\draw[priv] (caddy.east |- gitea.west) -- node[lbl, above]{\texttt{\scriptsize git.inviscid.dev}} (gitea.west);
|
||||||
|
\draw[priv] (caddy.east |- buttons.west) -- node[lbl, below, pos=0.4]{by IP} (buttons.west);
|
||||||
|
\draw[priv] (caddy.north) -- (cdata.south);
|
||||||
|
\draw[priv] ([yshift=2mm]gitea.east) -- ([yshift=2mm]gdata.west |- gitea.east);
|
||||||
|
|
||||||
|
% Administrative path
|
||||||
|
\draw[adm] (admin.east) -- node[lbl, above, pos=0.72]{22 SSH} (sshd.west);
|
||||||
|
\draw[adm] (sshd.east) -- node[lbl, below]{SSH tunnel to \texttt{\scriptsize 127.0.0.1:3000}} (13.75,-0.8) |- ([yshift=-3mm]gitea.east);
|
||||||
|
|
||||||
|
% Blocked
|
||||||
|
\draw[blk] (scan.east) -- node[lbl, above, pos=0.62]{22, 3000, 222, 2019} ([xshift=-1.2mm]sgBot |- scan.east);
|
||||||
|
\node[text=devopsRed, font=\large\bfseries] at (sgBot |- scan.east) {$\times$};
|
||||||
|
\end{tikzpicture}
|
||||||
Reference in new issue
Block a user