summaryrefslogtreecommitdiff
path: root/CLAUDE.md
blob: 0ab9222cbebb4b1d009a846ce4ab7a3437d19611 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Bastion — Claude Code Context

## Project Overview
Bastion is a self-hosted server system on Debian that runs multiple services in Docker containers. All containers are managed via Portainer. Nginx acts as reverse proxy sitting on all service networks.

## Domain
- Primary domain: `swave.lol`
- Subdomains: `blog.swave.lol`, `ghost.swave.lol`, `jenkins.swave.lol`, `cgit.swave.lol`, `gerrit.swave.lol`, `nexus.swave.lol`, `registry.swave.lol`

## Services / Stacks

### Portainer
- Standalone `docker run`, not in a compose file
- Web UI on port 9000
- Used to manage all other containers/stacks

### Ghost (blog)
- Dir: `ghost/`
- Compose: `ghost/compose.yml`, env: `ghost/stack.env` (for Portainer) or `.env` (for local)
- Network: `ghost_network`
- Services: ghost (port 2368), ghost-db (MySQL 8), activitypub (optional, profile-gated)
- Accessible at `https://swave.lol`, `https://blog.swave.lol`, and `https://ghost.swave.lol`
- URL must be configured as `https://` in compose.yml (Ghost caches URL config internally)
- DOMAIN in stack.env must be the bare domain (e.g., `swave.lol`) without a port number

### Git Server
- Dir: `git-server/`
- Compose: `git-server/server.yaml`, needs `docker build -t git-server .` first
- Networks: `git-network` (172.22.0.0/16, static IP 172.22.0.2) and `jenkins_network` (172.23.0.0/16, static IP 172.23.0.3)
- Ports: 22 (SSH), 9418 (git daemon)
- Volumes: `/var/git_ssh_keys` (public keys), `/var/git/repos` (repositories)
- Host SSH runs on a non-standard port, so port 22 is free for git

### Cgit (git web interface)
- Dir: `git-server/cgit/`
- Builds from `git-server/cgit/Dockerfile` (Alpine + cgit + fcgiwrap + nginx)
- Part of `git-server/server.yaml` compose stack
- Network: `git-network`
- Mounts `/var/git/repos:/repos:ro` (read-only, shared with git-server)
- Auto-discovers all bare repos via `scan-path=/repos`
- No host ports (accessed only via main nginx reverse proxy)
- Accessible at `https://cgit.swave.lol` and `https://swave.lol/cgit`

### Gerrit (code review)
- Part of `git-server/server.yaml` compose stack
- Image: `gerritcodereview/gerrit:latest` (no custom Dockerfile)
- Networks: `git-network` (static IP 172.22.0.4) and `jenkins_network` (static IP 172.23.0.4)
- Web UI on port 8080 internally, SSH on 29418
- No host ports (accessed only via main nginx reverse proxy)
- Volumes: `/var/gerrit` (etc, git, db, index, cache), shared `/var/git/repos`
- Accessible at `https://gerrit.swave.lol` and `https://swave.lol/gerrit`

### Jenkins
- Dir: `jenkins/`
- Compose: `jenkins/docker-compose.yaml`, builds from `jenkins/Dockerfile`
- Network: `jenkins_network` (172.23.0.0/16, static IP 172.23.0.2)
- Uses Docker-out-of-Docker (DooD): mounts `/var/run/docker.sock` to spawn sibling build containers
- Dockerfile extends `jenkins/jenkins:lts` with Docker CLI and `docker-workflow` plugin
- `--prefix=/jenkins` set via JENKINS_OPTS for path-based access
- Accessible at `https://jenkins.swave.lol` and `https://swave.lol/jenkins`
- Ports: 8080 (web UI), 50000 (agent communication via JNLP, used by remote build agents)
- Volume: `/var/jenkins_home`
- Pipeline durability: set to "Performance-optimized" to prevent flow execution corruption
- Startup script: `jenkins/init.groovy.d/clear-stuck-builds.groovy` auto-cleans stuck builds on restart
- Currently runs all builds on the controller via DooD; supports adding permanent SSH agents for scaling (see setup guide 6.6)

### Nexus (artifact repository & Docker registry)
- Dir: `nexus/`
- Compose: `nexus/docker-compose.yaml`
- Image: `sonatype/nexus3:latest` (no custom Dockerfile)
- Network: `nexus_network` (172.25.0.0/16, static IP 172.25.0.2)
- Nexus web UI on port 8081 internally, Docker registry API on port 5000
- No host ports (accessed only via main nginx reverse proxy)
- Volume: `/var/nexus-data` (must be owned by UID 200)
- Accessible at `https://nexus.swave.lol` and `https://swave.lol/nexus`
- Docker registry accessible at `https://registry.swave.lol`
- Docker registry requires manual setup after first login: create a "docker (hosted)" repository with HTTP connector on port 5000

### Nginx (reverse proxy)
- Dir: `nginx/`
- Compose: `nginx/docker-compose.yaml`
- Network: joins `git-network` (IP 172.22.0.254), `ghost_network`, `jenkins_network`, `nexus_network`
- Ports: 80 (HTTP, redirects to HTTPS), 443 (HTTPS)
- Config mounted from `/var/nginx/conf/` on host
- SSL: Let's Encrypt certs via `run_certbot.sh`, dhparam at `/var/dh_param/`
- SSL protocols: TLSv1.2 + TLSv1.3 only
- Default catch-all server blocks return 404 error page for unknown subdomains
- Error page: `nginx/error-pages/unknown-host.html`
- IMPORTANT: SSL server blocks must be commented out for first run (before certs exist)

## Networking
Each stack has its own Docker network. Nginx joins all of them to reverse proxy:
- `git-network` — git-server + cgit + gerrit + nginx
- `ghost_network` — ghost + ghost-db + nginx
- `jenkins_network` — jenkins + git-server + gerrit + nginx
- `nexus_network` — nexus + nginx

## Startup Order
1. Portainer (standalone)
2. Git Server (creates git-network)
3. Ghost (creates ghost_network)
4. Jenkins (creates jenkins_network)
5. Nexus (creates nexus_network)
6. Gerrit (joins git-network + jenkins_network, both must exist)
7. Nginx (joins all networks, must be last)

## Key Files
- `doc/setup-guide.md` — full build instructions from fresh Debian
- `doc/Jenkinsfile.example` — example DooD pipeline
- `doc/Jenkinsfile.kernel-example` — example kernel build pipeline using kernel-builder image
- `doc/jenkins-cpp-build.md` — guide for building C++ apps in Jenkins with Docker agent
- `jenkins/kernel-builder/Dockerfile` — custom Docker image for building the Linux kernel
- `jenkins/init.groovy.d/clear-stuck-builds.groovy` — startup script to clean stuck pipeline executions
- `nexus/docker-compose.yaml` — Nexus Repository Manager + Docker registry
- `doc/Jenkinsfile.nexus-example` — example pipelines for uploading artifacts and Docker images to Nexus
- `ghost/.env.example` — template for Ghost env vars
- `doc/git-performance.md` — git server performance tuning guide
- `nginx/error-pages/unknown-host.html` — 404 page for unknown subdomains
- `.gitignore` — excludes `.env` files (secrets)

## Conventions
- Each service lives in its own directory with its own compose file
- Compose files are named `docker-compose.yaml` or `compose.yml` or `server.yaml` (inconsistent, historical)
- Environment variables with secrets go in `.env`/`stack.env` files (gitignored)
- Nginx config is a single `nginx.conf` with multiple server blocks
- All services use `restart: always`

## TODOs (from Readme.md)
- Automatic certificate renewal for Let's Encrypt
- Better organization of nginx configs (split per service?)
- ~~Cgit web interface for git repos~~ (done)
- ~~Nexus~~ (done)
- Firewall rules (allow only 80, 443, 22, 8080, 8000, 9000, 9418, 50000)