感谢meiyouqian学长笔记
要记得改 postgres 的密码不然容易被攻击来着(

alt text

基础环境搭建

cat /etc/os-release
# 作用:显示当前 Linux 发行版的详细信息
uname -a
# 作用:显示系统所有信息(内核名称、主机名、内核版本、硬件架构等)
uname -r
# 作用:只显示内核版本号
docker --version
lsb_release -a
# 作用:显示 Linux Standard Base 和发行版信息

systemctl list-units --type=service
# 作用:显示当前系统中所有服务(service)的状态
# 参数说明:
# --type=service - 只显示服务类型的单元
  • 判断docker是否安装:
which docker
systemctl status docker
ps aux | grep docker

A1CTF靶场搭建_image-1.png

安装docker

  • 安装基础工具
sudo apt install -y \
vim \
git \
curl \
wget \
htop \
net-tools \
ufw \
nginx \
docker.io \
docker-compose
  • 直接成功了,根据建议reboot一下

防火墙配置

#先添加规则(防火墙未启用时添加)
sudo ufw allow 50071/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw allow 8080/tcp comment 'CTF'

# 确认规则已添加
sudo ufw status numbered
# Status: inactive

# 启用防火墙(输入 y)
sudo ufw enable

# 查看状态
sudo ufw status verbose

alt text

Node.js 22+配置

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v

alt text

Go 1.24+配置

wget https://go.dev/dl/go1.24.11.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.24.11.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

go version

alt text

PostgreSQL 15+配置

sudo sed -i 's/http:\/\/cn.archive.ubuntu.com/https:\/\/mirrors.aliyun.com/g' /etc/apt/sources.list
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install postgresql-15

psql --version

alt text

Redis 7+配置

wget https://github.com/redis/redis/archive/7.2.5.tar.gz

tar -xzvf 7.2.5.tar.gz
cd redis-7.2.5

sudo apt update
sudo apt install build-essential
make # 编译源码

alt text

sudo apt update
sudo apt install -y pkg-config build-essential tcl libssl-dev

# 回到 Redis 目录
# cd ~/redis-7.2.5

# 清理之前的编译
make distclean

# 重新编译安装
make
make test # 运行测试套件
sudo make install # 安装到系统

# 创建目录
sudo mkdir -p /etc/redis /var/lib/redis
sudo cp redis.conf /etc/redis/

# 后台启动
redis-server /etc/redis/redis.conf --daemonize yes
# 遇到警告Linux 内存分配策略未启用(可能导致后台保存失败)
sudo sysctl vm.overcommit_memory=1

单节点Kubernetes配置

https://zhuanlan.zhihu.com/p/1932852088334951626

环境准备

# 关闭防火墙
sudo systemctl disable ufw

# 禁用 swap
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab

# 查看 fstab 确认 swap 已删除
cat /etc/fstab

# 确认 swap 已禁用
free -h

内核参数配置

# 创建内核参数文件
sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0
EOF

# 加载内核模块
sudo modprobe br_netfilter

# 应用配置
sudo sysctl --system

安装依赖工具

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl

安装 Kubernetes 组件

# 添加 Kubernetes 阿里云源
sudo tee /etc/apt/sources.list.d/kubernetes.list <<EOF
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

# 添加 GPG 密钥
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubernetes-aliyun.gpg

# 更新源
sudo apt update
# 安装 kubelet/kubeadm/kubectl
sudo apt install -y kubelet kubeadm kubectl
# 锁定版本防止自动升级
sudo apt-mark hold kubelet kubeadm kubectl

初始化控制面板

# 先确保 cri-dockerd 已安装运行
sudo systemctl status cri-dockerd
  • 没安装,安装
# 下载(如果还没下载)
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd-0.3.4.amd64.tgz
tar -xvf cri-dockerd-0.3.4.amd64.tgz

# 移动到系统路径
sudo mv cri-dockerd/cri-dockerd /usr/local/bin/
sudo chmod +x /usr/local/bin/cri-dockerd

# 验证
cri-dockerd --version
# 创建服务文件
sudo tee /etc/systemd/system/cri-docker.service > /dev/null <<EOF
[Unit]
Description=CRI Docker Daemon
Documentation=https://github.com/Mirantis/cri-dockerd
Requires=docker.service
After=network.target docker.service

[Service]
ExecStart=/usr/local/bin/cri-dockerd --container-runtime-endpoint unix:///var/run/cri-dockerd.sock --docker-endpoint unix:///var/run/docker.sock
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# 创建 socket 文件(可选,用于激活)
sudo tee /etc/systemd/system/cri-docker.socket > /dev/null <<EOF
[Unit]
Description=CRI Docker Socket

[Socket]
ListenStream=/var/run/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
EOF
# 重载 systemd
sudo systemctl daemon-reload

# 启动并启用服务
sudo systemctl start cri-docker.service
sudo systemctl enable cri-docker.service

# 验证状态
sudo systemctl status cri-docker.service

# 检查 socket
ls -la /var/run/cri-dockerd.sock
  • 初始化
# 指定使用 Docker
sudo kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
--cri-socket unix:///var/run/cri-dockerd.sock
# root 用户的简捷方式配置 kubectl
export KUBECONFIG=/etc/kubernetes/admin.conf

# 检查节点状态
kubectl get nodes

安装 Calico 网络插件

kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

# 检查 Pod 状态(可能显示 ImagePullBackOff)
kubectl get pods -n kube-system

alt text

移除污点

# 检查当前污点
kubectl describe node | grep Taints

# 移除污点
kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule-

# 确认污点已移除
kubectl describe node | grep Taints

alt text

安装Dashboard

#下载helm
wget https://get.helm.sh/helm-v3.18.4-linux-amd64.tar.gz

#安装helm
tar zxvf helm-v3.18.4-linux-amd64.tar.gz

mv linux-amd64/helm /usr/local/bin/

# 添加 Dashboard 仓库
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
  • 报错说仓库错误
  • 直接用 kubectl 安装
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

# 检查 Dashboard Pods
kubectl get pods -n kubernetes-dashboard

访问Dashboard

注意这边我们是云服务器啊,不是本地的,不要搞本地的,要用公网IP进行端口转发

# 停止之前可能的端口转发
pkill -f "kubectl port-forward"

# NodePort + HTTPS 跳过
# 1. 改为 NodePort
kubectl -n kubernetes-dashboard patch svc kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'

# 2. 查看端口
kubectl get svc -n kubernetes-dashboard

# 3. 创建登录账号
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
EOF

# 4. 获取 token
kubectl -n kubernetes-dashboard create token admin-user
# 防火墙放过端口
sudo ufw allow XXX/tcp

alt text

  • 32152端口

alt text

  • 好玩好玩

常用命令备忘录

# 停止之前可能的端口转发
pkill -f "kubectl port-forward"
# NodePort + HTTPS 跳过
# 1. 改为 NodePort
kubectl -n kubernetes-dashboard patch svc kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'

# 2. 查看端口
kubectl get svc -n kubernetes-dashboard

# 4. 获取 token
kubectl -n kubernetes-dashboard create token admin-user
# 查看所有资源
kubectl get all --all-namespaces

# 查看组件状态
kubectl get componentstatuses

# 查看系统事件
kubectl get events --sort-by='.lastTimestamp'

# 查看 Pod 日志
kubectl logs <pod-name> -n <namespace>

# 进入 Pod
kubectl exec -it <pod-name> -- sh

搭建A1CTF

wget https://github.com/carbofish/A1CTF/archive/refs/heads/main.zip
apt install unzip
unzip main.zip

alt text

配置环境

cp config.example.yaml config.yaml

启动Docker

git init
git add .
git commit -m "A1CTF Initial commit"

docker-compose up -d

修改配置

docker-compose.yml

version: '3.8'

services:
app:
build: .
image: test-a1ctf:latest
ports:
- "0.0.0.0:7777:7777" # 后端API
- "0.0.0.0:5173:5173" # 前端
- "0.0.0.0:8081:8081" # 监控
environment:
- GIN_MODE=release
volumes:
- ./appdata:/app/data
- ./config.yaml:/app/config.yaml:ro
- ./k8sconfig.yaml:/app/k8sconfig.yaml:ro
depends_on:
- postgres
- redis
restart: unless-stopped
networks:
- a1ctf-network

postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: a1ctf
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
volumes:
- ./postgres_data:/var/lib/postgresql/data
ports:
- "0.0.0.0:5433:5432"
restart: unless-stopped
networks:
- a1ctf-network
# 健康检查 - 确保数据库完全就绪
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d a1ctf"]
interval: 10s
timeout: 5s
retries: 10
start_period: 20s
redis:
image: redis:alpine
# 修改Redis端口映射,避免冲突
# 将外部端口改为63790,内部端口还是6379
ports:
- "0.0.0.0:63790:6379"
restart: unless-stopped
networks:
- a1ctf-network

networks:
a1ctf-network:
driver: bridge

前人踩坑

# 设置正确的目录权限
sudo chown -R 1000:1000 appdata
sudo chmod -R 755 appdata

alt text

  • 修改config.yml

alt text

  • 报错:k8sconfig.yaml是一个目录而不是文件
sudo cp /etc/kubernetes/admin.conf ~/A1CTF-main/k8sconfig.yaml
sudo chown $USER:$USER ~/A1CTF-main/k8sconfig.yaml
docker-compose up -d
docker-compose restart app

alt text

  • 欸怎么还在重启

alt text
alt text

  • …?
root@hkwdjaION31UcV:~/A1CTF-main# rm -rf ~/A1CTF-main/k8sconfig.yaml
root@hkwdjaION31UcV:~/A1CTF-main# ls -la ~/A1CTF-main/k8sconfig.yaml
ls: cannot access '/root/A1CTF-main/k8sconfig.yaml': No such file or directory
root@hkwdjaION31UcV:~/A1CTF-main# sudo cp /etc/kubernetes/admin.conf ~/A1CTF-main/k8sconfig.yaml
root@hkwdjaION31UcV:~/A1CTF-main# sudo chown $USER:$USER ~/A1CTF-main/k8sconfig.yaml
root@hkwdjaION31UcV:~/A1CTF-main# ls -la ~/A1CTF-main/k8sconfig.yaml
-rw------- 1 root root 5642 Feb 7 15:10 /root/A1CTF-main/k8sconfig.yaml
root@hkwdjaION31UcV:~/A1CTF-main#
  • 可能原因是本来就存在该目录,复制不会覆盖,所以要先删除
# 因为文件有修改要重新构建
docker-compose build
# 启动服务
docker-compose up -d
  • 还是报错
docker logs --tail 50 a1ctf-main_app_1
  • 权限问题,容器内的应用无法读取 k8sconfig.yaml 文件
# 1. 修改文件权限
chmod 644 ~/A1CTF-main/k8sconfig.yaml

# 2. 确认权限
ls -l k8sconfig.yaml

# 3. 清理并重启容器
docker-compose down
docker-compose up -d --force-recreate
docker-compose ps

alt text

  • 无法连接
  • 尝试修改配置,使用 Docker 网关地址
  • 还是失败。。交给ai

自己踩坑

用户问题

  • 首先,postgres用户是超级用户,比较不安全,如果要创建用户
  • 使用 Docker 环境变量 (推荐,最简单)
  • docker-compose.ymlpostgres 服务下直接定义环境变量。这是最标准的做法。
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: a1ctf # 作用:容器启动时自动创建名为 a1ctf 的超级用户
POSTGRES_PASSWORD: postgres # 作用:自动将该用户的密码设置为 postgres
POSTGRES_DB: a1ctf # 作用:自动创建一个名为 a1ctf 的数据库,并归属给上述用户

k8sconfig.yaml

推荐方案:使用宿主机的局域网静态 IP。

apiVersion: v1
clusters:
- cluster:
# 使用宿主机真实 IP
server: https://10.0.124.2:6443
# ... 其他证书配置保持不变
ip a
# 找宿主机静态ip
ps aux | grep kube-apiserver
# --secure-port=6443 k8s端口

网络与防火墙设置

在启动容器前,必须确保 Docker 容器网段可以访问宿主机的 K8s API 端口 (默认6443)。

  • 如何确认端口:
ps aux | grep kube-apiserver
# --secure-port=6443
  • 防火墙设置
# 1. 查看 Docker 网络子网 (通常是 172.18.0.0/16 或 172.17.0.0/16)
docker network inspect a1ctf-main_a1ctf-network | grep Subnet

# 2. 添加 iptables 允许规则 (假设子网是 172.18.0.0/16)
iptables -I INPUT -s 172.18.0.0/16 -p tcp --dport 6443 -j ACCEPT

注意:此规则重启后可能会失效,建议写入持久化防火墙配置中。

  • 美滋滋,ai还是把我养得太好了
    alt text

配置域名

apt update
apt install -y nginx
curl ifconfig.me # 得到公网ip
nano /etc/nginx/sites-available/a1ctf.conf

server {
listen 80;
server_name luoyinhui.xyz www.luoyinhui,xyz;

# 反向代理到 A1CTF(Gin)端口
location / {
proxy_pass http://127.0.0.1:7777;

proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# 可选:长连接/大包更稳
proxy_read_timeout 300;
proxy_send_timeout 300;
client_max_body_size 200m;
}
}
# 启用站点并重载
ln -s /etc/nginx/sites-available/a1ctf.conf /etc/nginx/sites-enabled/a1ctf.conf
nginx -t
systemctl reload nginx

apt install -y certbot python3-certbot-nginx
# 配置好dns等一会
dig @223.5.5.5 luoyinhui.xyz A +short #有回显才能继续

certbot --nginx -d luoyinhui.xyz -d www.luoyinhui.xyz

总结

数据库连接

  • 端口
  • docker-compose.yml
postgres:
image: postgres:17-alpine
# ...
ports:
- "5433:5432" # 左边是外部端口(5433),右边是内部端口(5432)

存档配置文件

  • config.yml
    alt text
  • Prometheus 监控端口 ( 8081 ) 仅监听在容器内部/本地回环接口,不再对外部网络(包括宿主机局域网)开放,避免危险
configVersion: v1

system:
gin-port: 7777
gin-host: 0.0.0.0
prometheus-port: 8081
prometheus-host: 127.0.0.1
# current only support ico
favicon: ./data/favicon.ico
# The base url for your website
baseURL: http://localhost:5173
# if you are using a reverse proxy like nginx, enable it to get the real client ip
forwarded-by-client-ip: true
# real client ip request headers added by your reverse proxy server
remote-ip-headers:
- X-Forwarded-For
- X-Real-IP
# make sure that you include your reverse proxy server's ip in this list
# don't use 0.0.0.0/0, it's dangerous
trusted-proxies:
- 0.0.0.0/0
# enable pprof for performance profiling, default is false
pprof-enable: false

redis:
address: redis:6379
password: "postgres"
db: 0

k8s:
k8s-config-file: "k8sconfig.yaml"
node-ip-map:
- { name: "vm-4-3-ubuntu", "address": "example.com/1.1.1.1" }
# manual port assignments
manual-port-assignments:
enabled: false
port-range-map:
# You can add multiple port range map with same node name
# - { name: "vm-4-3-ubuntu", "start": 23101, "end": 24101 }
# - { name: "vm-4-3-ubuntu", "start": 24102, "end": 25102 }
pull-secret-names:
# You can add multiple pull secret names here, make sure they are created in the a1ctf-challenges namespace as the pods
# - default-name
custom-dns-server:
enabled: false
nameservers:
- 8.8.8.8

postgres:
host: postgres
port: 5432
user: a1ctf
password: "postgres"
dbname: a1ctf
sslmode: disable

cache-time:
user-list: 500ms
upload-list: 500ms
solved-challenges-for-game: 500ms
game-info: 500ms
all-teams-for-game: 500ms
game-scoreboard: 500ms
challenges-for-game: 1s
challenge-detail: 500ms
container-status: 100ms
team-flag: 100ms
team-solve-status: 100ms
judge-result: 100ms

# time format like 1s 500ms etc..
redis-cache-time:
user-list: 500ms
upload-list: 500ms
solved-challenges-for-game: 500ms
game-info: 500ms
all-teams-for-game: 500ms

# if you need garafana, enable it
monitoring:
enabled: true
system-monitor-interval: 1s
gorm-slow-query-threshold: 100ms

# job intervals
job-intervals:
update-activate-game-score: 500ms
update-active-game-score-board: 5s
flag-judge: 1s
update-game-scoreboard-cache: 1s
container-updating: 1s
compress-and-delete-old-logs: 2h

# captcha settings
cap-settings:
defaultChallengeTokenSize: 25
defaultChallengeCount: 80
defaultChallengeSize: 32

# difficulty is the number of leading zeros in the hash, don't set it too low or too high, it will affect the performance
defaultChallengeDifficulty: 4
defaultChallengeExpires: 10m

# token size is the size of the token in bytes
defaultTokenSize: 64
defaultTokenIdSize: 16
defaultTokenExpires: 20m
defaultTokenVerifyOnce: true

defaultHttpHandleLimitRPS: 10
defaultHttpHandleLimitBurst: 50

game-settings:
container-cooldown-time: 60s
  • docker-compose.yml
version: '3.8'

services:
app:
build: .
image: test-a1ctf:latest
ports:
- "7777:7777" # 后端API
- "5173:5173" # 前端
- "8681:8681" # 监控(建议用8681而不是8081)
environment:
- GIN_MODE=release
volumes:
- ./appdata:/app/data
- ./config.yaml:/app/config.yaml:ro
- ./k8sconfig.yaml:/app/k8sconfig.yaml:ro
depends_on:
postgres:
condition: service_healthy # 等待数据库健康
redis:
condition: service_started
restart: unless-stopped
networks:
- a1ctf-network

postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: a1ctf
POSTGRES_USER: a1ctf # 改为 a1ctf 保持一致性
POSTGRES_PASSWORD: postgres # 改为 a1ctf 保持一致性
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
volumes:
- ./postgres_data:/var/lib/postgresql/data
ports:
- "5433:5432"
restart: unless-stopped
networks:
- a1ctf-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d a1ctf"] # 现在匹配了
interval: 10s
timeout: 5s
retries: 10
start_period: 20s

redis:
image: redis:alpine
ports:
- "63790:6379" # 外部63790 -> 内部6379
restart: unless-stopped
networks:
- a1ctf-network

networks:
a1ctf-network:
driver: bridge