diff options
| author | Arseney300 <Arseney300@gmail.com> | 2026-02-20 02:02:10 +0700 |
|---|---|---|
| committer | Arseney300 <Arseney300@gmail.com> | 2026-02-20 02:02:10 +0700 |
| commit | 688e8bcd85709811a9140237c2e394c5df6d5652 (patch) | |
| tree | fa2d0e8084dfc9af8059432f727c266959437e11 /doc/setup-guide.md | |
| parent | ebddef6a320b219889152b594cfc7adef5f6764b (diff) | |
Add full server setup guide
Step-by-step instructions to build the bastion server from a fresh
Debian install: Docker, Portainer, Git Server, Ghost, Jenkins,
Nginx with SSL. Includes network architecture, startup order,
and ports summary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'doc/setup-guide.md')
| -rw-r--r-- | doc/setup-guide.md | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/doc/setup-guide.md b/doc/setup-guide.md new file mode 100644 index 0000000..581dee1 --- /dev/null +++ b/doc/setup-guide.md @@ -0,0 +1,340 @@ +# Bastion Server — Setup Guide + +Full instruction to build the server from a fresh Debian installation. + +## Prerequisites + +- Fresh Debian server +- Root access +- Domain `swave.lol` with DNS A records pointing to the server: + - `swave.lol` + - `blog.swave.lol` + - `jenkins.swave.lol` + + +## 1. Install Docker + +Based on https://docs.docker.com/engine/install/debian/#install-using-the-repository + +```bash +# Install prerequisites +apt-get update +apt-get install -y ca-certificates curl gnupg + +# Add Docker GPG key +install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc +chmod a+r /etc/apt/keyrings/docker.asc + +# Add Docker repository +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null + +# Install Docker +apt-get update +apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + +# Verify +docker run hello-world +``` + + +## 2. Clone the bastion repository + +```bash +cd /root/Projects +git clone <your-repo-url> bastion +cd bastion +``` + + +## 3. Start Portainer + +Portainer manages all other containers and stacks via web UI. + +```bash +docker run -d \ + --name="portainer" \ + --restart on-failure \ + -p 9000:9000 \ + -p 8000:8000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v portainer_data:/data \ + portainer/portainer-ce:latest +``` + +Access Portainer at `http://<server-ip>:9000` and create admin account. + + +## 4. Git Server + +### 4.1 Create host directories + +```bash +# Directory for SSH public keys (for git access) +mkdir -p /var/git_ssh_keys + +# Directory for git repositories +mkdir -p /var/git/repos + +# Copy your public SSH keys for git access +# cp ~/.ssh/id_rsa.pub /var/git_ssh_keys/mykey.pub +``` + +### 4.2 Build and start + +```bash +cd /root/Projects/bastion/git-server + +# Build the git-server image +docker build -t git-server . + +# Start (this also creates the git-network) +docker compose -f server.yaml up -d +``` + +### 4.3 Create a test repository + +```bash +# On the server +cd /var/git/repos +git init --bare test.git +chown -R 1000:1000 test.git # git user inside container + +# From a client machine +git clone ssh://git@<server-ip>/repos/test.git +``` + + +## 5. Ghost (Blog) + +### 5.1 Prepare environment + +```bash +cd /root/Projects/bastion/ghost + +# Copy the mysql init script to the expected location +mkdir -p /var/lib/docker/mysql-init-script +cp mysql-init-script/create-multiple-databases.sh /var/lib/docker/mysql-init-script/ + +# Edit stack.env (or .env for non-Portainer use) with your credentials +# IMPORTANT: Change default passwords before first run! +``` + +Key settings in `stack.env`: +- `DOMAIN` — your domain (e.g. `swave.lol`) +- `DATABASE_ROOT_PASSWORD` — MySQL root password +- `DATABASE_USER` / `DATABASE_PASSWORD` — Ghost database credentials +- `UPLOAD_LOCATION` — where Ghost stores content + +### 5.2 Start Ghost + +```bash +cd /root/Projects/bastion/ghost +docker compose up -d +``` + +Ghost will be available at `http://<server-ip>:2368` for testing before Nginx is configured. + +To start with ActivityPub support (optional): +```bash +docker compose --profile activitypub up -d +``` + + +## 6. Jenkins + +### 6.1 Create host directories + +```bash +mkdir -p /var/jenkins_home +``` + +### 6.2 Build and start + +```bash +cd /root/Projects/bastion/jenkins + +# Build Jenkins image (includes Docker CLI and docker-workflow plugin) +docker compose build + +# Start Jenkins +docker compose up -d +``` + +### 6.3 Get initial admin password + +```bash +docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword +``` + +Jenkins will be available at `http://<server-ip>:8080/jenkins` for initial setup. + +### 6.4 Jenkins build setup (DooD) + +Jenkins uses Docker-out-of-Docker: it spawns sibling containers on the host for builds. +Each project defines its own build image in the Jenkinsfile: + +```groovy +pipeline { + agent { + docker { image 'node:20' } + } + stages { + stage('Build') { + steps { + sh 'npm install && npm run build' + } + } + } +} +``` + +See `doc/Jenkinsfile.example` for a full multi-stage example. + + +## 7. Nginx (Reverse Proxy + SSL) + +Nginx must be started AFTER Git Server, Ghost, and Jenkins, because it joins +their networks as external. + +### 7.1 Create host directories + +```bash +# Nginx config directory +mkdir -p /var/nginx/conf + +# Copy nginx.conf +cp /root/Projects/bastion/nginx/nginx.conf /var/nginx/conf/ + +# DH parameters (this takes a few minutes) +mkdir -p /var/dh_param +openssl dhparam -out /var/dh_param/dhparam-2048.pem 2048 + +# Let's Encrypt directories +mkdir -p /var/letsencrypt/etc +mkdir -p /var/letsencrypt/lts_site + +# Copy the ACME challenge placeholder page +cp /root/Projects/bastion/nginx/letsencrypt/index.html /var/letsencrypt/lts_site/ +``` + +### 7.2 First run — HTTP only (no SSL yet) + +Before we have SSL certificates, we need to temporarily disable the SSL server +blocks so Nginx can start and serve the ACME challenge for certbot. + +```bash +# Edit the nginx.conf copy on the host to comment out SSL server blocks +# Keep only the port 80 server block +nano /var/nginx/conf/nginx.conf +``` + +Comment out everything from `# Ghost — swave.lol` to the end of file. +Keep only the `listen 80` server block. + +```bash +cd /root/Projects/bastion/nginx +docker compose up -d +``` + +### 7.3 Obtain SSL certificates + +```bash +cd /root/Projects/bastion/nginx +bash run_certbot.sh +``` + +This requests certificates for: +- `swave.lol` +- `blog.swave.lol` +- `jenkins.swave.lol` + +IMPORTANT: All DNS records must be pointing to the server before running certbot. + +### 7.4 Enable SSL + +```bash +# Restore full nginx.conf with SSL blocks +cp /root/Projects/bastion/nginx/nginx.conf /var/nginx/conf/ + +# Restart Nginx +cd /root/Projects/bastion/nginx +docker compose restart +``` + +### 7.5 Verify + +All services should now be accessible: + +| URL | Service | +|-----|---------| +| `https://swave.lol` | Ghost (blog) | +| `https://blog.swave.lol` | Ghost (blog, alias) | +| `https://swave.lol/jenkins` | Jenkins (path-based) | +| `https://jenkins.swave.lol` | Jenkins (subdomain) | +| `http://<server-ip>:9000` | Portainer | +| `ssh://git@<server-ip>/repos/<repo>.git` | Git (SSH) | +| `git://<server-ip>/<repo>.git` | Git (daemon, read-only) | + + +## Network Architecture + +``` +git-network (172.22.0.0/16) +├── git-server (172.22.0.2) +└── nginx (172.22.0.254) + +ghost_network +├── ghost +├── ghost-db +├── activitypub (optional) +└── nginx + +jenkins_network +├── jenkins +└── nginx +``` + +Nginx sits on all networks so it can reverse proxy to every service. + + +## Startup Order + +The correct order to start all services: + +```bash +# 1. Portainer (standalone, no dependencies) +docker run -d --name="portainer" --restart on-failure \ + -p 9000:9000 -p 8000:8000 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v portainer_data:/data portainer/portainer-ce:latest + +# 2. Git Server (creates git-network) +docker compose -f /root/Projects/bastion/git-server/server.yaml up -d + +# 3. Ghost (creates ghost_network) +docker compose -f /root/Projects/bastion/ghost/compose.yml up -d + +# 4. Jenkins (creates jenkins_network) +docker compose -f /root/Projects/bastion/jenkins/docker-compose.yaml up -d + +# 5. Nginx (joins all networks — must be last) +docker compose -f /root/Projects/bastion/nginx/docker-compose.yaml up -d +``` + + +## Ports Summary + +| Port | Service | Protocol | +|------|---------|----------| +| 22 | Git Server (SSH) | TCP | +| 80 | Nginx (HTTP, redirects to 443) | TCP | +| 443 | Nginx (HTTPS) | TCP | +| 2368 | Ghost (direct, for testing) | TCP | +| 8080 | Jenkins (direct, for testing) | TCP | +| 9000 | Portainer (web UI) | TCP | +| 9418 | Git Server (git daemon) | TCP | +| 50000 | Jenkins (agent communication) | TCP | |
