Compare commits
4
Commits
bill-patch-1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0292ed11c | ||
|
|
6f310c7085 | ||
|
|
7a80342d4e | ||
|
|
4c142b2e11 |
@@ -1,3 +1,17 @@
|
|||||||
# vpn-dns-gateway
|
# vpn-dns-gateway
|
||||||
|
|
||||||
SSW 590 Group 1 startup product repository.
|
SSW 590 Group 1 startup product repository.
|
||||||
|
|
||||||
|
## Project
|
||||||
|
**Resource-Constrained Personal VPN and DNS Gateway**: a self-hosted VPN
|
||||||
|
and DNS ad-blocking gateway for our own laptops and phones, running on a
|
||||||
|
1 vCPU / 512 MB DigitalOcean droplet.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
- Run a VPN and optional DNS filtering reliably within 512 MB of RAM.
|
||||||
|
- Measure memory, disk, and stability under bounded load.
|
||||||
|
- Show gateway health on a simple operations dashboard.
|
||||||
|
|
||||||
|
## Team workflow
|
||||||
|
Every change goes through an issue-linked branch, a pull request, and one
|
||||||
|
approving peer review before merging to `main`.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Caddy obtains and renews the Let's Encrypt certificate and redirects HTTP to HTTPS automatically.
|
||||||
|
git.yebilly.me {
|
||||||
|
reverse_proxy gitea:3000
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# Gitea Deployment (Assignment 4 / Instructor Manual Chapter 2)
|
||||||
|
|
||||||
|
Pinned Gitea (`gitea/gitea:1.27.3`, SQLite) behind Caddy (`caddy:2.11.4-alpine`,
|
||||||
|
automatic Let's Encrypt HTTPS) on the DigitalOcean droplet **The-Ocean**
|
||||||
|
(Ubuntu 24.04, 1 vCPU, 512 MB). No secrets live in this folder.
|
||||||
|
|
||||||
|
Hostname: `git.yebilly.me` (set in `docker-compose.yml` and `Caddyfile`).
|
||||||
|
Save the output of every step marked
|
||||||
|
**evidence** (screenshots or copied terminal text) for the IT manual.
|
||||||
|
|
||||||
|
## 0. Prerequisites (done in web consoles)
|
||||||
|
|
||||||
|
1. **Domain:** claim a GitHub Student Developer Pack domain. Record the offer,
|
||||||
|
eligibility, first-year cost, renewal cost, and expiry date. **evidence**
|
||||||
|
2. **DNS:** add an `A` record `git` -> droplet IPv4 at the registrar. **evidence**
|
||||||
|
(DNS screen), then from a laptop:
|
||||||
|
`nslookup git.yebilly.me 1.1.1.1` **evidence**
|
||||||
|
3. **DigitalOcean Cloud Firewall** (`Networking -> Firewalls`), name
|
||||||
|
`gitea-fw`, applied to The-Ocean:
|
||||||
|
- Inbound `TCP 443` All IPv4 + All IPv6
|
||||||
|
- Inbound `TCP 80` All IPv4 + All IPv6 (redirect + certificate validation)
|
||||||
|
- Inbound `TCP 22` **team public IPs only** (add these first and confirm SSH
|
||||||
|
still works before removing any wider SSH rule)
|
||||||
|
- Outbound: leave default (all) so apt, Docker Hub, DNS, NTP, and Let's
|
||||||
|
Encrypt remain reachable.
|
||||||
|
**evidence** (rules screen + date)
|
||||||
|
|
||||||
|
## 1. Prepare the droplet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stop color-buttons-app && docker rm color-buttons-app # frees port 80
|
||||||
|
# 512 MB RAM: add 1 GB swap
|
||||||
|
fallocate -l 1G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
|
||||||
|
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||||
|
docker --version && docker compose version # evidence
|
||||||
|
```
|
||||||
|
|
||||||
|
From the laptop, copy this folder:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp -r gitea root@<droplet-ip>:~/gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Start the stack
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/gitea
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps # evidence: only caddy shows 0.0.0.0:80/443
|
||||||
|
docker compose logs caddy | grep -i certificate # evidence: certificate obtained
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `https://git.yebilly.me`, keep **SQLite3** on the install page, create
|
||||||
|
the admin account. Store its password in a password manager, never in Git or
|
||||||
|
the manual.
|
||||||
|
|
||||||
|
## 3. HTTPS evidence
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sI http://git.yebilly.me # expect 308 + Location: https://...
|
||||||
|
curl -vI https://git.yebilly.me 2>&1 | grep -Ei "issuer|expire|subject|HTTP/"
|
||||||
|
```
|
||||||
|
|
||||||
|
Also screenshot the browser certificate viewer (issuer, expiry). **evidence**
|
||||||
|
|
||||||
|
## 4. Renewal test (forced reissue)
|
||||||
|
|
||||||
|
Caddy renews automatically about 30 days before expiry and has no dry-run
|
||||||
|
command, so force a fresh issuance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
date -u
|
||||||
|
docker compose exec caddy rm -rf /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/git.yebilly.me
|
||||||
|
docker compose restart caddy
|
||||||
|
docker compose logs --since 2m caddy | grep -i certificate # evidence
|
||||||
|
curl -vI https://git.yebilly.me 2>&1 | grep -Ei "issuer|expire" # new dates
|
||||||
|
```
|
||||||
|
|
||||||
|
Do this once; repeated reissues can hit Let's Encrypt rate limits.
|
||||||
|
|
||||||
|
## 5. Persistence test
|
||||||
|
|
||||||
|
In Gitea, create a repository and an issue; note the repo name and issue
|
||||||
|
number. Then:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps --filter name=gitea --format '{{.ID}} {{.Image}} {{.CreatedAt}}' # before
|
||||||
|
docker compose up -d --force-recreate --no-deps gitea
|
||||||
|
docker ps --filter name=gitea --format '{{.ID}} {{.Image}} {{.CreatedAt}}' # after: new ID
|
||||||
|
docker compose exec gitea ls -l /data/gitea/gitea.db # SQLite file
|
||||||
|
docker volume inspect gitea_gitea-data --format '{{.Mountpoint}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Reload the repo and issue in the browser. **evidence** (before/after
|
||||||
|
screenshots). The named volume outlives the container, so data persists. This
|
||||||
|
is not a backup or restore test.
|
||||||
|
|
||||||
|
## 6. External exposure test
|
||||||
|
|
||||||
|
Run from a laptop, **not** the droplet. Record source network, time, expected
|
||||||
|
and actual result.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-NetConnection git.yebilly.me -Port 443 # expect True
|
||||||
|
Test-NetConnection git.yebilly.me -Port 80 # expect True (redirects)
|
||||||
|
Test-NetConnection git.yebilly.me -Port 22 # True from approved IP only
|
||||||
|
Test-NetConnection git.yebilly.me -Port 3000 # expect False
|
||||||
|
```
|
||||||
|
|
||||||
|
Repeat the port 22 check from a non-approved network (phone hotspot): expect
|
||||||
|
`False`. Supporting on-droplet view (not proof of public exposure):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ss -tlnp
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Team workflow (Gitea UI)
|
||||||
|
|
||||||
|
Create the organization and product repository with a README, add at least two
|
||||||
|
members with roles, open at least five issues (product and operations), and for
|
||||||
|
two issues: branch -> pull request with `Closes #N` -> peer review -> merge ->
|
||||||
|
issue closed. **evidence** (links/screenshots)
|
||||||
|
|
||||||
|
## Operate
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart gitea # restart
|
||||||
|
docker compose logs -f gitea caddy # troubleshoot
|
||||||
|
docker compose pull && docker compose up -d # after bumping pinned tags
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Gitea behind Caddy (automatic Let's Encrypt HTTPS) on the The-Ocean droplet.
|
||||||
|
# Only Caddy publishes ports; Gitea is reachable solely on the private "web" network.
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:1.27.3
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- GITEA__database__DB_TYPE=sqlite3 # file: /data/gitea/gitea.db
|
||||||
|
- GITEA__server__DOMAIN=git.yebilly.me
|
||||||
|
- GITEA__server__ROOT_URL=https://git.yebilly.me/
|
||||||
|
- GITEA__server__HTTP_PORT=3000
|
||||||
|
- GITEA__server__DISABLE_SSH=true # Git over HTTPS only
|
||||||
|
volumes:
|
||||||
|
- gitea-data:/data
|
||||||
|
networks: [web]
|
||||||
|
# ponytail: no ports: on purpose -- Caddy reaches gitea:3000 privately.
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:2.11.4-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80" # HTTP->HTTPS redirect + ACME HTTP-01 validation
|
||||||
|
- "443:443" # HTTPS
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- caddy-data:/data # certificates + ACME account
|
||||||
|
- caddy-config:/config
|
||||||
|
networks: [web]
|
||||||
|
depends_on: [gitea]
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
gitea-data:
|
||||||
|
caddy-data:
|
||||||
|
caddy-config:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
Reference in New Issue
Block a user