# Netcup Server Provisioning — Initial Setup

Covers provisioning a fresh Netcup RS VPS (Manassas) — from order confirmation email to secure, usable server.

## SCP REST API Authentication

The Netcup SCP (Server Control Panel) provides a REST API at `https://www.servercontrolpanel.de/scp-core/api/v1/`. This is distinct from the CCP (Customer Control Panel) API.

### Auth Flow

The SCP uses Keycloak (OIDC) for authentication, NOT the CCP API key / API password method.

**Correct auth flow (password grant):**

```bash
# Step 1: Get token
curl -s "https://www.servercontrolpanel.de/realms/scp/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=scp&username=${CUSTOMER_NUMBER}&password=${CCP_PASSWORD}" \
  -o /tmp/netcup_token.json

TOKEN=$(jq -r '.access_token' /tmp/netcup_token.json)

# Step 2: Use token
curl -s "https://www.servercontrolpanel.de/scp-core/api/v1/servers" \
  -H "Authorization: Bearer ${TOKEN}"
```

**⚠️ Cron mode:** `python3 -c` and `curl | python3` are blocked by the security scanner in cron. Use `jq` (as shown above) and two-step file approach instead of pipes.

### Key Details

| Parameter | Value |
|-----------|-------|
| Auth URL | servercontrolpanel.de/realms/scp/protocol/openid-connect/token |
| Client ID | scp (from SCP web app) |
| Grant type | password |
| Username | Customer number (e.g. 389212) -- NOT the CCP API key |
| Password | CCP login password -- NOT the API password |
| Token lifetime | 300 seconds (5 min) |
| API base | servercontrolpanel.de/scp-core/api/v1/ |
| Auth header | Authorization: Bearer <token> |

### Auth Pitfalls

- The CCP API Key + API Password from Master Data are for a DIFFERENT API (DNS/domain management via XML-RPC)
- The SCP REST API uses the CCP LOGIN credentials (customer number + password), not the API keys
- Make sure the server's IP is whitelisted in SCP -> REST API Settings, or leave the whitelist empty to allow all
- The X-API-Key header does NOT work with the SCP API -- only Authorization: Bearer with an OIDC token
- The correct API path is /scp-core/api/ -- NOT /scp-ui/api/ (which serves the web UI, not data)
- scp-ui/api/v1/servers returns the HTML login page instead of JSON -- this is how it behaves when auth is missing

### Available Endpoints (from this account)

| Endpoint | Purpose | Works? |
|----------|---------|--------|
| GET /scp-core/api/v1/servers | List all servers | Yes |
| GET /scp-core/api/v1/servers/{id} | Server details | Yes |
| POST /scp-core/api/v1/templates | Provisioning | Not found |

The provisioning endpoints (/templates, /images) may be scoped to reseller/partner accounts only. Standard customer accounts can create/view servers but not provision new ones via API.

## After Order Approval

Netcup sends two emails:
1. **SCP access** — `https://www.servercontrolpanel.de/SCP/` with username + password
2. **Server ready** — IP address, root password, hostname, OS info

### Data Processing Agreement (DPA)

New accounts must complete a DPA before payment processes. Standard EU GDPR boilerplate:
- Navigate CCP → Master Data → Order Processing
- "Conclude Data Processing Agreement" — pre-filled standard text, just review and accept
- Netcup acts as processor (Art. 28 GDPR), you as controller
- Required even for US businesses with US customers in Manassas

## First SSH — Do NOT change root password before capturing it

**CRITICAL PITFALL:** Do NOT change the root password inside the same SSH command that creates users. If the command errors mid-way (e.g. package install fails), the new password was set but never captured in the output. The original email password no longer works, and the server is unreachable.

**Correct procedure:**

```bash
# Step 1: SSH in with original password, deploy SSH key immediately
sshpass -p '<original-root-pw>' ssh -o StrictHostKeyChecking=accept-new root@<server-ip> '
  set -e
  mkdir -p /root/.ssh && chmod 700 /root/.ssh
'
# Pipe the SSH key in a separate step
sshpass -p '<pw>' ssh root@<server-ip> 'cat >> /root/.ssh/authorized_keys' < ~/.ssh/wisp_rsa.pub

# Step 2: Test key-based auth, THEN create users + change passwords
ssh -i ~/.ssh/wisp_rsa root@<server-ip> '
  useradd -m -s /bin/bash -G sudo ippadmin
  echo "ippadmin ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ippadmin
  mkdir -p /home/ippadmin/.ssh && chmod 700 /home/ippadmin/.ssh
  cat /root/.ssh/authorized_keys >> /home/ippadmin/.ssh/authorized_keys
  chown -R ippadmin:ippadmin /home/ippadmin/.ssh && chmod 600 /home/ippadmin/.ssh/authorized_keys
  ROOT_PASS=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 20)
  echo "root:${ROOT_PASS}" | chpasswd
  echo "New root password: ${ROOT_PASS}"
'
```

## Debian 13 (Trixie) Package Names

Netcup deploys Debian 13 (Trixie) minimal by default. Package names differ from Debian 12:

| Package | Notes |
|---------|-------|
| docker.io | Available (Docker 26.1.5) |
| docker-compose-plugin | NOT in Debian 13 repos — must use Docker's apt repo |
| python3-pip | Available |
| python3-venv | May need `python3.13-venv` |
| ufw | Available |
| gnupg | Not pre-installed, needed for apt-key management |
| unzip | Not pre-installed |
| awscli v2 | Must install manually via `curl + unzip` |

### Docker Compose — Dedicated apt repo

```bash
apt-get install -y gnupg
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bookworm stable" | tee /etc/apt/sources.list.d/docker.list
apt-get update && apt-get install -y docker-compose-plugin
```

Use **bookworm** (Debian 12 codename), not trixie — Docker doesn't have a trixie-specific repo yet. The bookworm packages work on trixie.

### AWS CLI v2

```bash
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
apt-get install -y unzip
unzip -q /tmp/awscliv2.zip -d /tmp/
/tmp/aws/install --update
rm -rf /tmp/aws /tmp/awscliv2.zip
```

### Wasabi S3 Credentials

```bash
aws configure set aws_access_key_id GYH83FP0KL0K85N60JKQ
aws configure set aws_secret_access_key <key-from-control-box>
aws configure set region us-east-1
chmod 600 /root/.aws/credentials

# Test — note: s3:ListAllMyBuckets is NOT supported by Wasabi IAM
aws s3 ls s3://hermes-vps-backups/ --endpoint-url https://s3.us-east-1.wasabisys.com
```

### Hermes

```bash
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
```

## Standard Netcup SCP

- URL: `https://www.servercontrolpanel.de/SCP/`
- Use for: password resets, firewall policy management, OS reinstall, boot/rescue mode
- Netcup pre-installs a firewall policy that blocks SMTP. Remove "netcup Mail Block" policy in SCP → Firewall if email delivery is needed.

## Standard Admin User

All servers use `ippadmin` (sudo, no password) with the `wisp_rsa` Ed25519 SSH key. Root SSH login should be disabled after setup:

```bash
sed -i 's/^PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
```

## Firewall (UFW)

```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow http
ufw allow https
ufw --force enable
```

## Root password safety rule

When setting up a new remote server:
1. Connect with the provided password
2. **Immediately deploy your SSH public key** first
3. Then create users, install packages, change passwords
4. Record new passwords in password manager
5. Use SSH key for all future access

**Never change root password mid-script without capturing the output.** If the script fails before `echo "password: ${PASS}"` executes, you're locked out.
