diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8dfcf9a
--- /dev/null
+++ b/README.md
@@ -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:
+- This repository:
+- 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.
diff --git a/docker/gitea/Caddyfile b/docker/gitea/Caddyfile
new file mode 100644
index 0000000..5a65f98
--- /dev/null
+++ b/docker/gitea/Caddyfile
@@ -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
+}
diff --git a/docker/gitea/README.md b/docker/gitea/README.md
index 30d853a..2a085ed 100644
--- a/docker/gitea/README.md
+++ b/docker/gitea/README.md
@@ -1,13 +1,16 @@
# Inviscid Gitea foundation
-This is the temporary, Gitea-only deployment used before the domain was registered; retain it as the initial deployment configuration.
-The official image version is pinned; verify that it pulls before starting the service.
+This directory deploys Gitea at https://git.inviscid.dev/ behind a Caddy reverse proxy.
+The official image version is pinned.
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.
-Only EC2 loopback port 3000 is published. Initial browser access uses an SSH tunnel.
-The existing Color Buttons container remains unchanged on port 80.
+Only Caddy publishes host ports (80 and 443). Caddy terminates TLS and forwards to
+`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.
From this directory on EC2:
@@ -19,30 +22,18 @@ sudo docker compose up -d
sudo docker compose ps
```
-This initial configuration is NOT the final hostname-based HTTPS deployment.
-After domain registration, replace DOMAIN and ROOT_URL with the actual hostname
-and HTTPS URL. Payton can attach Caddy to `inviscid_services` and forward to
-`gitea:3000`, publish the proxy web ports, persist certificate state, and resolve
-the existing website's port-80 mapping. Remove the loopback mapping if no longer needed.
+`Caddyfile` must be in this directory before `up`; if it is missing, Docker creates a
+directory in its place and Caddy fails to start. Caddy obtains and renews the
+Let's Encrypt certificate automatically; certificate state persists in the
+`inviscid_caddy_data` and `inviscid_caddy_config` volumes.
-Self-registration is disabled. Create the initial administrator through the installer;
-create Payton's separate account using administration after initialization.
-Keep passwords, app.ini, database files, and volume contents out of Git and screenshots.
+The Color Buttons container is managed outside Compose. To recreate it without a
+published port:
-Sources:
-- https://docs.gitea.com/installation/install-with-docker/
-- https://docs.gitea.com/administration/config-cheat-sheet/
-
-## 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.
+```sh
+sudo docker run -d --name ssw590-group-buttons --restart unless-stopped \
+ --network inviscid_services ssw590-group-buttons
+```
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
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.
-- Displayed renewal: October 15, 2027 at $22.99; auto-renew enabled. Victor owns renewal.
-- Saved A record: `git.inviscid.dev` -> `100.49.80.94`, TTL 300.
-- Windows lookups via 1.1.1.1 and 8.8.8.8 both returned that IP at 19:17 EDT.
-- Both users are organization owners of `Inviscid`; Payton's SSH/Gitea access works per Victor.
-- 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.
+Sources:
+- https://docs.gitea.com/installation/install-with-docker/
+- https://docs.gitea.com/administration/config-cheat-sheet/
+- https://caddyserver.com/docs/running#docker-compose
+- https://caddyserver.com/docs/automatic-https
diff --git a/docker/gitea/compose.yaml b/docker/gitea/compose.yaml
index 356cbac..03c27c1 100644
--- a/docker/gitea/compose.yaml
+++ b/docker/gitea/compose.yaml
@@ -9,9 +9,8 @@ services:
USER_GID: "1000"
GITEA__database__DB_TYPE: sqlite3
GITEA__database__PATH: /data/gitea/gitea.db
- # Temporary URLs for SSH-tunnel initialization; replace after registration.
- GITEA__server__DOMAIN: localhost
- GITEA__server__ROOT_URL: http://localhost:3000/
+ GITEA__server__DOMAIN: git.inviscid.dev
+ GITEA__server__ROOT_URL: https://git.inviscid.dev/
GITEA__server__HTTP_PORT: "3000"
GITEA__server__DISABLE_SSH: "true"
GITEA__service__DISABLE_REGISTRATION: "true"
@@ -22,9 +21,28 @@ services:
networks:
- 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:
gitea_data:
name: inviscid_gitea_data
+ caddy_data:
+ name: inviscid_caddy_data
+ caddy_config:
+ name: inviscid_caddy_config
networks:
services: