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
|
# 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`, `jenkins.swave.lol`, `cgit.swave.lol`, `gerrit.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` and `https://blog.swave.lol`
### 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)
- 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
### Nginx (reverse proxy)
- Dir: `nginx/`
- Compose: `nginx/docker-compose.yaml`
- Network: joins `git-network` (IP 172.22.0.254), `ghost_network`, `jenkins_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
- 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
## Startup Order
1. Portainer (standalone)
2. Git Server (creates git-network)
3. Ghost (creates ghost_network)
4. Jenkins (creates jenkins_network)
5. Gerrit (joins git-network + jenkins_network, both must exist)
6. 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
- `ghost/.env.example` — template for Ghost env vars
- `.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 (mentioned in Readme but not yet set up)
- Firewall rules (allow only 80, 443, 22, 8080, 8000, 9000, 9418, 50000)
|