|
1 | 1 | # Deployment Guide |
2 | 2 |
|
3 | | -For system administrators with Linux experience, deploying on a single host from scratch. |
| 3 | +Docker Compose is the recommended way to deploy. No need to install PostgreSQL, Go, or compile from source. |
4 | 4 |
|
5 | | -## Prerequisites |
| 5 | +## 1. Install Docker |
6 | 6 |
|
7 | | -- Ubuntu 22.04+ / Debian 12+ (or equivalent systemd-based distro) |
8 | | -- Root or sudo access |
9 | | -- Public IP (for bootstrap endpoint and user SSH access) |
10 | | -- At least one proxy config for an egress IP |
| 7 | +### Linux |
11 | 8 |
|
12 | | -## 1. Environment Setup |
| 9 | +```bash |
| 10 | +curl -fsSL https://get.docker.com | sh |
| 11 | +``` |
13 | 12 |
|
14 | | -### Dependency Check |
| 13 | +Add your user to the `docker` group: |
15 | 14 |
|
16 | 15 | ```bash |
17 | | -sudo bash deploy/scripts/host-preflight.sh |
| 16 | +sudo usermod -aG docker $USER |
| 17 | +# Log out and back in for it to take effect |
18 | 18 | ``` |
19 | 19 |
|
20 | | -Checks: Docker Engine 28+, FUSE kernel module, nftables, nsenter, curl, ip, systemctl, Go 1.26+, PostgreSQL 18.x, Node.js 24 LTS (optional). |
21 | | - |
22 | | -### Install Missing Dependencies |
| 20 | +### macOS |
23 | 21 |
|
24 | | -**Docker Engine:** |
| 22 | +Install [Docker Desktop](https://www.docker.com/products/docker-desktop/), or via Homebrew: |
25 | 23 |
|
26 | 24 | ```bash |
27 | | -curl -fsSL https://get.docker.com | sh |
28 | | -systemctl enable --now docker |
| 25 | +brew install --cask docker |
29 | 26 | ``` |
30 | 27 |
|
31 | | -**nftables / nsenter / curl:** |
| 28 | +### Windows |
32 | 29 |
|
33 | | -```bash |
34 | | -apt-get install -y nftables util-linux curl |
35 | | -``` |
| 30 | +Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) with WSL 2 backend enabled. |
36 | 31 |
|
37 | | -**FUSE kernel module:** |
| 32 | +## 2. Start |
38 | 33 |
|
39 | 34 | ```bash |
40 | | -modprobe fuse |
41 | | -echo fuse >> /etc/modules-load.d/fuse.conf |
| 35 | +git clone https://github.com/ZaneL1u/cloud-cli-proxy.git |
| 36 | +cd cloud-cli-proxy |
| 37 | + |
| 38 | +bash deploy/scripts/setup-env.sh |
| 39 | +docker compose pull |
| 40 | +docker compose up -d |
42 | 41 | ``` |
43 | 42 |
|
44 | | -Verify: `ls -la /dev/fuse` should show a character device with `crw-rw-rw-` permissions. |
| 43 | +`setup-env.sh` interactively generates all passwords and secrets. It supports: |
45 | 44 |
|
46 | | -**Go 1.26:** |
| 45 | +- **Built-in PostgreSQL (recommended)**: auto-created, managed by Docker Compose, zero config |
| 46 | +- **External PostgreSQL**: provide your existing database connection details |
47 | 47 |
|
48 | | -```bash |
49 | | -wget https://go.dev/dl/go1.26.1.linux-amd64.tar.gz |
50 | | -rm -rf /usr/local/go && tar -C /usr/local -xzf go1.26.1.linux-amd64.tar.gz |
51 | | -echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile.d/go.sh |
52 | | -source /etc/profile.d/go.sh |
53 | | -``` |
| 48 | +After startup: |
54 | 49 |
|
55 | | -**PostgreSQL 18:** |
| 50 | +- Admin dashboard: `http://YOUR_HOST:3000` |
| 51 | +- API: `http://YOUR_HOST:8080` |
| 52 | + |
| 53 | +Verify: |
56 | 54 |
|
57 | 55 | ```bash |
58 | | -apt-get install -y postgresql-18 |
59 | | -systemctl enable --now postgresql |
| 56 | +curl http://127.0.0.1:8080/healthz |
| 57 | +# {"status":"ok"} |
60 | 58 | ``` |
61 | 59 |
|
62 | | -### FUSE & AppArmor Compatibility |
| 60 | +## Users in Mainland China |
63 | 61 |
|
64 | | -sshfs inside containers requires FUSE. Docker's default AppArmor profile includes a `deny mount` rule. The system automatically adds `--security-opt apparmor=unconfined` when creating containers. |
| 62 | +`ghcr.io` may be slow or unreachable from within mainland China. Use one of the following workarounds. |
65 | 63 |
|
66 | | -| Host OS | Impact | Handling | |
67 | | -|---------|--------|----------| |
68 | | -| Ubuntu 24.04 | Default AppArmor blocks FUSE mount | Handled automatically | |
69 | | -| Ubuntu 25.04+ | Additional fusermount3 profile may block | `aa-disable /usr/bin/fusermount3` | |
70 | | -| Debian 12+ | No AppArmor | No action needed | |
| 64 | +### Option 1: Pull through a proxy (recommended) |
71 | 65 |
|
72 | | -Verify FUSE compatibility: |
| 66 | +If your machine already has a TUN-mode proxy or global proxy set up: |
73 | 67 |
|
74 | 68 | ```bash |
75 | | -sudo bash scripts/verify-fuse-compat.sh |
| 69 | +docker compose pull |
| 70 | +docker compose up -d |
76 | 71 | ``` |
77 | 72 |
|
78 | | -## 2. PostgreSQL Configuration |
| 73 | +Images will be pulled through the proxy. No further configuration needed. |
79 | 74 |
|
80 | | -```bash |
81 | | -sudo -u postgres psql <<'SQL' |
82 | | -CREATE DATABASE cloudproxy; |
83 | | -CREATE USER cloudproxy WITH PASSWORD 'replace-with-strong-password'; |
84 | | -GRANT ALL PRIVILEGES ON DATABASE cloudproxy TO cloudproxy; |
85 | | -ALTER DATABASE cloudproxy OWNER TO cloudproxy; |
86 | | -\c cloudproxy |
87 | | -GRANT ALL ON SCHEMA public TO cloudproxy; |
88 | | -SQL |
89 | | -``` |
| 75 | +### Option 2: Use a mirror registry |
90 | 76 |
|
91 | | -Verify connection: |
| 77 | +Replace `ghcr.io` with one of the available mirrors: |
92 | 78 |
|
93 | | -```bash |
94 | | -psql "postgresql://cloudproxy:password@127.0.0.1:5432/cloudproxy" -c "SELECT 1" |
| 79 | +``` |
| 80 | +ghcr.io/zanel1u/cloud-cli-proxy/control-plane |
| 81 | +→ ghcr.nju.edu.cn/zanel1u/cloud-cli-proxy/control-plane |
| 82 | +→ ghcr.nuaa.edu.cn/zanel1u/cloud-cli-proxy/control-plane |
| 83 | +→ docker.1ms.run/zanel1u/cloud-cli-proxy/control-plane |
95 | 84 | ``` |
96 | 85 |
|
97 | | -## 3. Build |
| 86 | +Or pull and re-tag with a mirror prefix: |
98 | 87 |
|
99 | 88 | ```bash |
100 | | -git clone https://github.com/ZaneL1u/cloud-cli-proxy.git /opt/cloud-cli-proxy |
101 | | -cd /opt/cloud-cli-proxy |
102 | | - |
103 | | -go build -o /opt/cloud-cli-proxy/bin/control-plane ./cmd/control-plane |
104 | | -go build -o /opt/cloud-cli-proxy/bin/host-agent ./cmd/host-agent |
105 | | -bash deploy/docker/managed-user/build-managed-image.sh |
106 | | - |
107 | | -# Frontend (optional) |
108 | | -cd web/admin && pnpm install && pnpm build && cd /opt/cloud-cli-proxy |
109 | | -``` |
| 89 | +REGISTRY=ghcr.nju.edu.cn |
110 | 90 |
|
111 | | -## 4. Configuration |
| 91 | +docker pull $REGISTRY/zanel1u/cloud-cli-proxy/control-plane:latest |
| 92 | +docker pull $REGISTRY/zanel1u/cloud-cli-proxy/admin:latest |
112 | 93 |
|
113 | | -```bash |
114 | | -useradd --system --no-create-home --shell /usr/sbin/nologin cloudproxy |
115 | | -usermod -aG docker cloudproxy |
| 94 | +docker tag $REGISTRY/zanel1u/cloud-cli-proxy/control-plane:latest ghcr.io/zanel1u/cloud-cli-proxy/control-plane:latest |
| 95 | +docker tag $REGISTRY/zanel1u/cloud-cli-proxy/admin:latest ghcr.io/zanel1u/cloud-cli-proxy/admin:latest |
116 | 96 |
|
117 | | -mkdir -p /var/lib/cloud-cli-proxy /run/cloud-cli-proxy /etc/cloud-cli-proxy |
118 | | -chown cloudproxy:cloudproxy /var/lib/cloud-cli-proxy /run/cloud-cli-proxy /etc/cloud-cli-proxy |
| 97 | +docker compose up -d |
119 | 98 | ``` |
120 | 99 |
|
121 | | -Create `/etc/cloud-cli-proxy/env`. See [Configuration](./configuration) for the full variable reference. |
122 | | - |
123 | | -## 5. Install systemd Services |
| 100 | +## Environment Variables |
124 | 101 |
|
125 | | -```bash |
126 | | -cp deploy/systemd/cloud-cli-proxy-control-plane.service /etc/systemd/system/ |
127 | | -cp deploy/systemd/cloud-cli-proxy-host-agent.service /etc/systemd/system/ |
| 102 | +After running `setup-env.sh`, manual changes are usually unnecessary. See [Configuration](./configuration) for the full reference. |
128 | 103 |
|
129 | | -systemctl daemon-reload |
130 | | -systemctl enable --now cloud-cli-proxy-control-plane |
131 | | -systemctl enable --now cloud-cli-proxy-host-agent |
132 | | -``` |
| 104 | +## Building from Source |
133 | 105 |
|
134 | | -Or use the automated deploy script: |
| 106 | +Only needed when prebuilt images are unavailable: |
135 | 107 |
|
136 | 108 | ```bash |
137 | | -sudo bash deploy/scripts/deploy.sh |
| 109 | +docker compose -f docker-compose.yml -f docker-compose.build.yaml --profile build-only build --no-cache |
| 110 | +docker compose -f docker-compose.yml -f docker-compose.build.yaml up -d --force-recreate |
138 | 111 | ``` |
139 | 112 |
|
140 | | -## 6. Verify |
| 113 | +## Bare-metal Deployment |
| 114 | + |
| 115 | +For scenarios that require native systemd deployment: |
141 | 116 |
|
142 | 117 | ```bash |
143 | | -systemctl status cloud-cli-proxy-control-plane |
144 | | -systemctl status cloud-cli-proxy-host-agent |
145 | | -curl -s http://127.0.0.1:8080/healthz |
146 | | -# {"status":"ok"} |
| 118 | +sudo bash deploy/scripts/deploy.sh |
147 | 119 | ``` |
148 | 120 |
|
149 | | -## Post-deploy Layout |
150 | | - |
151 | | -``` |
152 | | -/opt/cloud-cli-proxy/bin/ # binaries |
153 | | -/etc/cloud-cli-proxy/env # environment variables (chmod 600) |
154 | | -/var/lib/cloud-cli-proxy/ # data directory |
155 | | -/run/cloud-cli-proxy/ # Unix socket |
156 | | -``` |
| 121 | +This automates: creating the system user → building binaries and images → generating config → installing systemd units → starting services. See `deploy/scripts/deploy.sh` in the repo for details. |
0 commit comments