# Deploy Your First Configuration

Source: https://docs.ops0.com/docs/how-to/first-configuration

Write an Ansible playbook in the ops0 editor, get it approved, and deploy it to a server — with full output tracking and rollback capability.

---

## Scenario

You need to configure a server — install nginx, set up a service, or apply a system setting — consistently and repeatably. You want to:
- Write the Ansible playbook in ops0
- Run a dry run to see what would change
- Deploy to one or more servers
- Have a full record of what was applied

---

## Prerequisites

- At least one server registered in [Settings → Infrastructure](https://docs.ops0.com/docs/settings/infrastructure) with SSH access configured

- The target server is reachable from ops0 (agent is online)

---

## Step 1: Create a Configuration Project

1. Click **Configurations** in the left sidebar

2. Click **New Configuration Project**

3. Name it `Install nginx`

4. Set **Type** to **Playbook**

5. Click **Create**

---

## Step 2: Write the Playbook

The configuration editor opens with a Monaco editor (YAML syntax, full highlighting and validation).

Paste or type your playbook:

```yaml
---
- name: Install and configure nginx
  hosts: all
  become: yes

  vars:
    nginx_port: "{{ port | default(80) }}"
    server_name: "{{ server_name | default('localhost') }}"

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600
      when: ansible_os_family == "Debian"

    - name: Install nginx
      package:
        name: nginx
        state: present

    - name: Start and enable nginx
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Check nginx is responding
      uri:
        url: "http://localhost:{{ nginx_port }}"
        status_code: 200
      register: nginx_check
      ignore_errors: yes

    - name: Show nginx status
      debug:
        msg: "nginx is {{ 'running' if nginx_check.status == 200 else 'not responding' }}"
```

---

## Step 3: Define Variables (Optional)

Click the **Variables** panel on the right side of the editor to set default values:

| Variable | Default | Description |
|----------|---------|-------------|
| `port` | `80` | Port nginx listens on |
| `server_name` | `localhost` | Server name for nginx config |

Variables can be overridden at deploy time without editing the playbook.

---

## Step 4: Get Approval

If your organization requires approval before configuration deployments:

1. Click **Submit for Approval**
2. An admin reviews the playbook and either approves or rejects it
3. Rejected playbooks return with comments for revision
4. Once approved, the configuration is ready to deploy

If approval is not required in your org, skip to Step 5.

---

## Step 5: Run a Dry Run

Before deploying, run a dry run to see what would change without making any actual changes.

1. Click **Deploy**

2. Select your target server(s) from the **Targets** picker

3. Set **Execution Mode** to **Dry Run**

4. Click **Run**

The dry run output shows each task and whether it would make a change:

```
TASK [Update apt cache] ───────────────────────── ok
TASK [Install nginx]    ───────────────────────── changed  ← would install
TASK [Start nginx]      ───────────────────────── changed  ← would start
TASK [Check nginx]      ───────────────────────── skipped (dry run)

Dry run complete. 2 tasks would make changes.
```

---

## Step 6: Deploy

Once you're satisfied with the dry run results:

1. Click **Deploy** again

2. Select the same target server(s)

3. Set **Execution Mode** to **Apply**

4. Optionally override variables (e.g. set `port` to `8080`)

5. Click **Run**

The deployment output streams in real time:

```
PLAY [Install and configure nginx] ─────────────────────

TASK [Gathering Facts] ──────────────────────────── ok
TASK [Update apt cache] ─────────────────────────── ok
TASK [Install nginx] ────────────────────────────── changed
TASK [Start and enable nginx] ───────────────────── changed
TASK [Check nginx is responding] ────────────────── ok
TASK [Show nginx status] ────────────────────────── ok
  msg: nginx is running

PLAY RECAP ──────────────────────────────────────────────
web-server-01: ok=6  changed=2  failed=0  skipped=0

Deployment complete.
```

---

## Verification

After the deploy:

1. The deployment record shows **Succeeded** with a summary: `ok=6 changed=2 failed=0`
2. SSH into the server and verify: `systemctl status nginx`
3. You should see nginx active and listening on port 80

---

## Deployment History

Every deployment is recorded with:
- Timestamp and who triggered it
- Variables used
- Full play output
- Summary (ok/changed/failed counts)

Click **History** on the configuration project to see all past deployments and their outputs.

---

## Next Steps

[Automate with Workflows → Trigger configuration deployments automatically as part of a pipeline](https://docs.ops0.com/docs/how-to/first-workflow)
[Configuration projects → Roles, task files, variable management, and version history](https://docs.ops0.com/docs/configurations/overview)

---

## Troubleshooting

Deploy fails: "Host unreachable"

Verify the target server is reachable from ops0 and SSH is configured. Check Settings → Infrastructure to confirm the server shows as online and the correct PEM key is attached.

Task fails: "Permission denied"

Ensure the playbook uses `become: yes` for tasks that need elevated privileges. The SSH user must have sudo access or be root.

YAML validation error on save

The Monaco editor validates YAML syntax in real time. Common issues: incorrect indentation (YAML is whitespace-sensitive), missing quotes around strings with colons, or mixing tabs and spaces. The error indicator points to the problematic line.
