今天整理了一下常用的服务,加上有些服务因为安全问题直接暴露到公网不太合适,需要通过VPN访问,所以干脆重新部署一下服务器, 记录一下搭建过程

作为一个云原生和容器化的脑残粉,遵循可以容器绝不折腾的思想,以容器化部署为主,本文中暂时不提及二进制部署方式

前置需求


配置方面网上有很多相关教程了,这边就不赘述了,以硬性要求为主,有些不是必须的前置需求本次暂时忽略

1. 一个公网服务器

2. 一个看起来还不错的域名

3. 一个比较稳定的魔法工具

环境准备


开启root登录(ubuntu)

1
sudo passwd root

按照提示输入密码,成功后会提示passwd: password updated successfully

1
sudo vi /etc/ssh/sshd_config # 编辑ssh配置文件
  1. PermitRootLogin参数修改为yes
  2. PasswordAuthentication参数修改为yes
1
sudo service ssh restart # 重启ssh服务

更新软件包

1
sudo apt update

安装ShellCrash

魔法工具,一条指令即可实现安装

1
export url='https://fastly.jsdelivr.net/gh/juewuy/ShellCrash@master' && wget -q --no-check-certificate -O /tmp/install.sh $url/install.sh  && bash /tmp/install.sh && source /etc/profile &> /dev/null

根据提示进行安装即可,订阅链接请自行购买

安装Docker

若之前安装过docker请务必先卸载再继续执行,本文假设你是全新vps或者第一次安装

若当前apt源非官方源,ShellCrash可能会导致其无法正常使用,请更换官方源或者关闭ShellCrash进行安装

1. 安装必要支持

1
sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release

2. 添加 Docker 官方 GPG key

这一步可能需要开启VPN

1
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

3. 添加apt源

1
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

4. 更新源

1
2
sudo apt update
sudo apt-get update

5. 安装最新版本Docker

1
sudo apt install docker-ce docker-ce-cli containerd.io

6. 查看版本与运行状态

1
2
sudo docker version # 查看版本
sudo systemctl status docker # 查看运行状态

容器网络

1
2
3
networks:
  common-net:
    driver: bridge

服务列表


本次服务以docker compose部署为主,使用命令单独部署也是可行的

本次服务之间有依赖关系,请先部署数据库

mariadb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  mariadb:
    image: mariadb:latest
    container_name: mariadb
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: <password>
      TZ: 'Asia/Shanghai'
    volumes:
      - /docker-data/mariadb:/var/lib/mysql
    networks:
      common-net:
        aliases:
          - mariadb
    privileged: true

容器创建完成后,需要再创建npm数据库

postgres

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  postgres:
    image: postgres:latest
    container_name: postgres
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: <password>
    volumes:
      - /docker-data/postgres/data:/var/lib/postgresql/data
    networks:
      common-net:
        aliases:
          - postgres
    privileged: true

容器创建完成后,需要再创建memosgitness数据库

nginx-proxy-manager

反向代理,同时结合NPM实现自动SSL以及面板管理,本次部署的数据持久化方式采用mariadb,因此需要前置先部署好mariadb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  nginx-proxy-manager:
    image: 'docker.io/jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: always
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    environment:
      DB_MYSQL_HOST: "mariadb"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "root"
      DB_MYSQL_PASSWORD: <password>
      DB_MYSQL_NAME: "npm"
    volumes:
      - /docker-data/nginx-proxy-manager/data:/data
      - /docker-data/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
    networks:
      common-net:
        aliases:
          - nginx-proxy-manager
    privileged: true
    depends_on:
      - mariadb

部署完毕后清更改基础用户名与密码

初始地址:http://host:81

初始用户名为:admin@example.com

初始密码为:changeme

adguardhome

私有DNS,搭配VPN实现域名私有访问

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguardhome
    restart: always
    ports:
      - "5443:5443/tcp"
      - "5443:5443/udp"
    volumes:
      - /docker-data/adguardhome/work:/opt/adguardhome/work
      - /docker-data/adguardhome/conf:/opt/adguardhome/conf
    networks:
      common-net:
        aliases:
          - adguardhome
    privileged: true

hugo

用于自动化部署hugo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  hugo:
    image: hugomods/hugo:exts
    container_name: hugo
    volumes:
      - /docker-data/blog-nginx/src:/src/hugo
      - /docker-data/navigation-nginx/src:/src/navigation
      - /docker-data/hugo/hugo_cache:/tmp/hugo_cache
      - /docker-data/hugo/script:/script
    networks:
      common-net:
        aliases:
          - hugo
    privileged: true

示例script文件

 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
#!/bin/sh

# 定义变量
REPO_DIR="/repo"
REPO_URL="http://用户名:密钥@仓库地址.git"
BRANCH="master"
SRC_DIR="/src/hugo"

# 检查 REPO_DIR 是否存在,如果不存在则创建它
if [ ! -d "$REPO_DIR" ]; then
  echo "$REPO_DIR 重新拉取..."
  mkdir -p "$REPO_DIR"
fi

# 检查路径中是否有现有的 git 仓库
if [ -d "$REPO_DIR/.git" ]; then
  echo "Git 仓库存在,将删除并重新克隆..."

  # 删除现有仓库
  rm -rf "$REPO_DIR"

  # 重新创建仓库目录
  mkdir -p "$REPO_DIR"
fi

# 进入目录
cd "$REPO_DIR" || { echo "进入目录失败"; exit 1; }

echo "正在克隆仓库..."

# 克隆远程仓库
git clone "$REPO_URL" .

# 检查克隆是否成功
if [ $? -ne 0 ]; then
  echo "克隆远程仓库失败"
  exit 1
fi

# 切换到指定分支
git checkout "$BRANCH" || { echo "切换到分支 $BRANCH 失败"; exit 1; }

# 删除 src 目录下的所有内容
echo "删除 $SRC_DIR..."
rm -rf "$SRC_DIR"

# 复制 WebBlog 目录下的内容到 src 目录
echo "将 $REPO_DIR/WebBlog 下的内容复制到 $SRC_DIR..."
cp -rf "$REPO_DIR/WebBlog/"* "$SRC_DIR/"

# 确保复制操作成功
if [ $? -ne 0 ]; then
  echo "复制文件失败"
  exit 1
fi

# 确保 hugo 已经安装
if ! command -v hugo > /dev/null 2>&1; then
  echo "hugo 命令未找到,请确保 hugo 已经安装"
  exit 1
fi

cd "$SRC_DIR" || { echo "进入目录失败"; exit 1; }

echo "重新构建 hugo 站点..."
rm -rf public

hugo

echo "构建完成"

blog-nginx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  blog-nginx:
    image: nginx:latest
    container_name: blog-nginx
    restart: always
    volumes:
      - /docker-data/blog-nginx/log:/var/log/nginx
      - /docker-data/blog-nginx/src/public:/usr/share/nginx/html
    networks:
      common-net:
        aliases:
          - blog-nginx
    privileged: true
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  navigation-nginx:
    image: nginx:latest
    container_name: navigation-nginx
    restart: always
    volumes:
      - /docker-data/navigation-nginx/log:/var/log/nginx
      - /docker-data/navigation-nginx/src/public:/usr/share/nginx/html
    networks:
      common-net:
        aliases:
          - navigation-nginx
    privileged: true

gitness

用于CI/CD

 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
  gitness:
    image: harness/gitness:latest
    container_name: gitness
    restart: always
    ports:
      - "3000:3000"
    environment:
      GITNESS_URL_BASE: <host>
      GITNESS_TOKEN_COOKIE_NAME: <token名称>
      GITNESS_PRINCIPAL_ADMIN_EMAIL: <邮箱>
      GITNESS_PRINCIPAL_ADMIN_PASSWORD: <密码>
      GITNESS_USER_SIGNUP_ENABLED: false
      GITNESS_DATABASE_DRIVER: postgres
      GITNESS_DATABASE_DATASOURCE: host=postgres port=5432 sslmode=disable dbname=gitness user=postgres password=<password>
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /docker-data/gitness/data:/data
      - /docker-data/gitness/daemon:/etc/docker/
    networks:
      common-net:
        aliases:
          - gitness
    privileged: true
    depends_on:
      - postgres

alist

用于文件存储

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  alist:
    image: 'xhofe/alist:latest'
    container_name: alist
    restart: always
    ports:
      - "5244:5244"
    volumes:
      - /docker-data/alist:/opt/alist/data
    environment:
      - PUID=0
      - PGID=0
      - UMASK=022
    networks:
      common-net:
        aliases:
          - alist
    privileged: true

部署完毕后需要执行docker exec -it alist ./alist admin set NEW_PASSWORD更改初始密码

并修改/docker-data/alist/config.json中的site_url项为你的域名

code-server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  code-server:
    image: codercom/code-server:latest
    container_name: code-server
    restart: always
    ports:
      - "8080:8080"
    environment:
      - PASSWORD=<password>
    networks:
      common-net:
        aliases:
          - code-server
    privileged: true

registry

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  registry:
    image: registry:latest
    container_name: registry
    restart: always
    ports:
      - "5000:5000"
    volumes:
      - /docker-data/registry:/var/lib/registry
      - /docker-data/registry/auth:/var/lib/registry/auth
    networks:
      common-net:
        aliases:
          - registry
    privileged: true

nebula

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  nebula:
    image: nebulaoss/nebula:latest
    container_name: nebula
    restart: always
    cap_add:
      - NET_ADMIN
    volumes:
      - /docker-data/nebula/etc:/etc/nebula
      - /docker-data/nebula/config:/config
    network_mode: host
    privileged: true

frp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  frps:
    image: snowdreamtech/frps:latest
    container_name: frps
    ports:
      - "8800-8831:8800-8831"
    restart: always
    volumes:
      - /docker-data/frp/frps.toml:/etc/frp/frps.toml
    networks:
      common-net:
        aliases:
          - frps

memos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  memos:
    image: neosmemo/memos:latest
    container_name: memos
    restart: always
    ports:
      - "5230:5230"
    environment:
      MEMOS_DRIVER: postgres
      MEMOS_DSN: user=postgres password=<password> dbname=memos host=postgres sslmode=disable
    volumes:
      - /docker-data/memos:/var/opt/memos
    networks:
      common-net:
        aliases:
          - memos
    depends_on:
      - postgres

poste

 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
  poste:
    image: analogic/poste.io:latest
    container_name: poste
    ports:
      - "980:80"  #申请证书时启用
      - "9443:443"  #申请证书时启用
      - "25:25"
      - "110:110"
      - "143:143"
      - "465:465"
      - "587:587"
      - "993:993"
      - "995:995"
      - "4190:4190"
    restart: always
    hostname: <hostname>
    environment:
      - LETSENCRYPT_EMAIL=<email>
      - LETSENCRYPT_HOST=<hostname>
      - VIRTUAL_HOST=<hostname>
      - DISABLE_CLAMAV=FALSE
      - DISABLE_RSPAMD=FALSE
      - TZ=Asia/Shanghai
      - HTTPS=ON
    volumes:
      - /docker-data/poste:/data
    networks:
      common-net:
        aliases:
          - poste