provision-nixos-server

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Provision NixOS Server

部署NixOS服务器

Workflow Overview

工作流概述

  1. Gather requirements from user
  2. Create Proxmox container
  3. Set up SSH access
  4. Create Colmena init configuration
  5. Deploy init config and update to static IP
  6. Copy infrastructure key for SOPS
  7. Configure application (if applicable)
  8. Deploy full configuration
  1. 收集用户需求
  2. 创建Proxmox容器
  3. 配置SSH访问
  4. 创建Colmena初始化配置
  5. 部署初始化配置并更新为静态IP
  6. 复制基础设施密钥用于SOPS
  7. 配置应用(如适用)
  8. 部署完整配置

Step 1: Gather Requirements

步骤1:收集需求

Ask user for:
  • Hostname: Server name (e.g.,
    woodpecker
    )
  • Container ID: Proxmox container ID (e.g.,
    122
    )
  • Proxmox server: Target Proxmox host (e.g.,
    thrall
    )
  • Storage:
    local-lvm
    (fast) or
    cephpool1
    (distributed, slower)
  • Memory: RAM in MB (default:
    4096
    )
  • Disk size: In GB (default:
    100
    )
  • Application: What will run on this server
Verify soft-secrets exist for the new host (
host.<hostname>.admin_ip_address
, etc.) or ask user to create them.
向用户收集以下信息:
  • 主机名:服务器名称(例如:
    woodpecker
  • 容器ID:Proxmox容器ID(例如:
    122
  • Proxmox服务器:目标Proxmox主机(例如:
    thrall
  • 存储
    local-lvm
    (高速)或
    cephpool1
    (分布式,低速)
  • 内存:内存大小(MB,默认值:
    4096
  • 磁盘大小:磁盘容量(GB,默认值:
    100
  • 应用:该服务器将运行的应用
验证新主机的软密钥是否存在(如
host.<hostname>.admin_ip_address
等),或要求用户创建这些密钥。

Step 2: Create Proxmox Container

步骤2:创建Proxmox容器

bash
PROXMOX_SERVER=<server>
HOSTNAME=<hostname>
CONTAINER_ID=<id>
STORAGE=local-lvm
MEMORY=4096
DISK_SIZE_IN_GB=100

ssh $PROXMOX_SERVER "pct create $CONTAINER_ID \
    --arch amd64 local:vztmpl/nixos-system-x86_64-linux.tar.xz \
    --ostype unmanaged \
    --description nixos \
    --hostname $HOSTNAME \
    --net0 name=eth0,bridge=vmbr3,ip=dhcp,firewall=1 \
    --storage $STORAGE \
    --memory $MEMORY \
    --rootfs $STORAGE:$DISK_SIZE_IN_GB \
    --unprivileged 1 \
    --features nesting=1 \
    --cmode console \
    --onboot 1 \
    --start 1"
Timeout note: Use longer timeouts (5+ minutes) for
cephpool1
storage.
bash
PROXMOX_SERVER=<server>
HOSTNAME=<hostname>
CONTAINER_ID=<id>
STORAGE=local-lvm
MEMORY=4096
DISK_SIZE_IN_GB=100

ssh $PROXMOX_SERVER "pct create $CONTAINER_ID \
    --arch amd64 local:vztmpl/nixos-system-x86_64-linux.tar.xz \
    --ostype unmanaged \
    --description nixos \
    --hostname $HOSTNAME \
    --net0 name=eth0,bridge=vmbr3,ip=dhcp,firewall=1 \
    --storage $STORAGE \
    --memory $MEMORY \
    --rootfs $STORAGE:$DISK_SIZE_IN_GB \
    --unprivileged 1 \
    --features nesting=1 \
    --cmode console \
    --onboot 1 \
    --start 1"
超时说明: 使用
cephpool1
存储时,需设置更长超时时间(5分钟以上)。

Step 3: Set Up SSH Access

步骤3:配置SSH访问

Fresh NixOS containers require full paths. Run via
pct exec
:
bash
ssh $PROXMOX_SERVER "pct exec $CONTAINER_ID -- /run/current-system/sw/bin/bash -c '\
  mkdir -p ~/.ssh && \
  curl -s https://github.com/fred-drake.keys > ~/.ssh/authorized_keys && \
  chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys'"
Get DHCP IP address:
bash
ssh $PROXMOX_SERVER "pct exec $CONTAINER_ID -- /run/current-system/sw/bin/ip addr show eth0 | grep 'inet '"
全新的NixOS容器需要使用完整路径。通过
pct exec
运行以下命令:
bash
ssh $PROXMOX_SERVER "pct exec $CONTAINER_ID -- /run/current-system/sw/bin/bash -c '\
  mkdir -p ~/.ssh && \
  curl -s https://github.com/fred-drake.keys > ~/.ssh/authorized_keys && \
  chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys'"
获取DHCP IP地址:
bash
ssh $PROXMOX_SERVER "pct exec $CONTAINER_ID -- /run/current-system/sw/bin/ip addr show eth0 | grep 'inet '"

Step 4: Create Colmena Init Configuration

步骤4:创建Colmena初始化配置

Create these files (see references/colmena-host-template.md and references/nixos-config-template.md):
  1. mkdir -p modules/nixos/host/<hostname>
  2. Create
    modules/nixos/host/<hostname>/configuration.nix
  3. Create
    colmena/hosts/<hostname>.nix
  4. Update
    colmena/default.nix
    with imports
Initial deploy config: Use DHCP IP and
root
user:
nix
deployment = {
  targetHost = "<DHCP_IP>";
  targetUser = "root";
};
Stage files and build:
bash
git add colmena/hosts/<hostname>.nix modules/nixos/host/<hostname>/ colmena/default.nix
colmena build --impure --on <hostname>-init
创建以下文件(参考references/colmena-host-template.mdreferences/nixos-config-template.md):
  1. mkdir -p modules/nixos/host/<hostname>
  2. 创建
    modules/nixos/host/<hostname>/configuration.nix
  3. 创建
    colmena/hosts/<hostname>.nix
  4. 更新
    colmena/default.nix
    添加导入配置
初始部署配置: 使用DHCP IP和
root
用户:
nix
deployment = {
  targetHost = "<DHCP_IP>";
  targetUser = "root";
};
暂存文件并构建:
bash
git add colmena/hosts/<hostname>.nix modules/nixos/host/<hostname>/ colmena/default.nix
colmena build --impure --on <hostname>-init

Step 5: Deploy Init and Update IP

步骤5:部署初始化配置并更新IP

Deploy (will hang when network restarts due to IP change):
bash
colmena apply --impure --on <hostname>-init
Kill the hanging command, then update
colmena/hosts/<hostname>.nix
:
nix
deployment = {
  targetHost = soft-secrets.host.<hostname>.admin_ip_address;
  targetUser = "default";
};
Verify with another deploy:
bash
colmena apply --impure --on <hostname>-init
部署(网络因IP变更重启时,命令会挂起):
bash
colmena apply --impure --on <hostname>-init
终止挂起的命令,然后更新
colmena/hosts/<hostname>.nix
nix
deployment = {
  targetHost = soft-secrets.host.<hostname>.admin_ip_address;
  targetUser = "default";
};
通过再次部署验证配置:
bash
colmena apply --impure --on <hostname>-init

Step 6: Copy Infrastructure Key

步骤6:复制基础设施密钥

Required for SOPS secret decryption:
bash
ssh default@<NEW_IP> "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
scp ~/.ssh/id_infrastructure default@<NEW_IP>:~/id_infrastructure
ssh default@<NEW_IP> "chmod 600 ~/id_infrastructure"
Age public key (for .sops.yaml):
age1rnarwmx5yqfhr3hxvnnw2rxg3xytjea7dhtg00h72t26dn6csdxqvsryg5
If secrets fail to decrypt, user needs to add this key to
.sops.yaml
and run
sops updatekeys
on the secret files.
该密钥用于SOPS密钥解密:
bash
ssh default@<NEW_IP> "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
scp ~/.ssh/id_infrastructure default@<NEW_IP>:~/id_infrastructure
ssh default@<NEW_IP> "chmod 600 ~/id_infrastructure"
Age公钥(用于.sops.yaml):
age1rnarwmx5yqfhr3hxvnnw2rxg3xytjea7dhtg00h72t26dn6csdxqvsryg5
如果密钥解密失败,用户需要将此密钥添加到
.sops.yaml
并对密钥文件执行
sops updatekeys

Step 7: Configure Application

步骤7:配置应用

See references/app-templates.md for patterns.
参考references/app-templates.md中的配置模板。

Add Container Images

添加容器镜像

  1. Edit
    apps/fetcher/containers.toml
  2. Run
    just update-container-digests
  3. Stage:
    git add apps/fetcher/containers.toml apps/fetcher/containers-sha.nix
  1. 编辑
    apps/fetcher/containers.toml
  2. 运行
    just update-container-digests
  3. 暂存文件:
    git add apps/fetcher/containers.toml apps/fetcher/containers-sha.nix

Create Application Config

创建应用配置

Create
apps/<appname>.nix
with:
  • Nginx proxy with SSL (if web-facing)
  • PostgreSQL container (if database needed)
  • Application container(s)
  • tmpfiles rules for data directories
创建
apps/<appname>.nix
,包含以下内容:
  • 带SSL的Nginx反向代理(如果是Web应用)
  • PostgreSQL容器(如果需要数据库)
  • 应用容器
  • 数据目录的tmpfiles规则

Create Secrets Config

创建密钥配置

Create
modules/secrets/<hostname>.nix
referencing SOPS files.
User must create SOPS files in secrets repo with:
  • postgresql-env.sops
    (POSTGRES_PASSWORD, POSTGRES_USER, POSTGRES_DB)
  • <appname>-env.sops
    (app-specific secrets)
创建
modules/secrets/<hostname>.nix
,关联SOPS文件。
用户必须在密钥仓库中创建以下SOPS文件:
  • postgresql-env.sops
    (包含POSTGRES_PASSWORD、POSTGRES_USER、POSTGRES_DB)
  • <appname>-env.sops
    (应用专属密钥)

Update Colmena Full Config

更新Colmena完整配置

In
colmena/hosts/<hostname>.nix
, add to full configuration imports:
nix
../../modules/secrets/<hostname>.nix
../../apps/<appname>.nix
colmena/hosts/<hostname>.nix
中,将以下内容添加到完整配置的导入项:
nix
../../modules/secrets/<hostname>.nix
../../apps/<appname>.nix

Step 8: Deploy Full Configuration

步骤8:部署完整配置

bash
just update-secrets  # Get latest secrets
git add <all-new-files>
colmena apply --impure --on <hostname>
bash
just update-secrets  # 获取最新密钥
git add <all-new-files>
colmena apply --impure --on <hostname>

Common Issues

常见问题

SOPS decrypt fails: Age key not in .sops.yaml - user must add key and re-encrypt
Nginx duplicate directive: Don't add
proxy_http_version
when using
proxyWebsockets = true
PostgreSQL 18 fails: Mount at
/var/lib/postgresql
not
/var/lib/postgresql/data
Container can't reach postgres: Use
0.0.0.0:5432:5432
for port binding,
host.containers.internal
in connection string
SOPS解密失败: Age密钥未添加到.sops.yaml中 - 用户必须添加密钥并重新加密
Nginx重复指令: 当设置
proxyWebsockets = true
时,请勿添加
proxy_http_version
PostgreSQL 18启动失败: 挂载路径应为
/var/lib/postgresql
而非
/var/lib/postgresql/data
容器无法连接PostgreSQL: 端口绑定使用
0.0.0.0:5432:5432
,连接字符串中使用
host.containers.internal