Automated server provisioning: cloud-init and user-data

Every new server configured manually is hours of engineer time and risk of error. We set up automated cloud-init provisioning as a turnkey service: a node receives a ready configuration on first boot. Server delivery accelerates several times, and settings stop diverging between environments.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Manual server provisioning instead of cloud-init: what breaks

Manual server configuration lives in the engineer’s head and in command history: the first node is brought up according to an instruction, the second — “like last time, but slightly differently,” the third — from memory.

cloud-init removes this gap — on first boot, the node itself applies packages, users, keys, and disk partitioning from user-data.

Configuration drift accumulates unnoticed: on one node a library was updated manually, on another it remained as before, on a third a kernel parameter was added “for debugging” and forgotten.

After a few months, environments stop being reproducible: an incident on production is not reproduced on staging, because the package set and limits there are different.

Errors during initial setup surface with a delay — a missed checklist step, a service not in autostart, incorrect mount order.

The node is formally healthy, joins the pool behind the load balancer, and service failure at node startup occurs already under load — when there is nothing to roll back to: a manual edit has neither version nor author.

Different environments in staging diverge precisely for this reason: production, pre-production, and test environments were assembled at different times and by different hands.

We examine how configuration becomes a versioned artifact — identical for all environments and verifiable before the node is put into operation.

What automatic provisioning at server startup provides

Provisioning at node startup removes manual steps between machine creation and its readiness to accept load. Instructions are defined in advance, and cloud-init applies them on first boot — without SSH access or on-the-spot edits.

The time to bring a server into operation drops from tens of minutes to a few minutes and no longer depends on who is on duty.

A single configuration baseline is the source of predictability in node provisioning. One description defines packages, users, keys, network settings, and monitoring agents, so the hundredth machine in the cluster does not differ from the first.

The description lives in a repository, undergoes review, and is versioned — divergence between nodes becomes visible before an incident, not during one.

Along with manual steps, a whole class of failures goes away: a forgotten package, an incorrect path, an open port, a diverged agent version, a step in the wrong order.

Previously, every mistake showed up in production and required investigation; now it either fails validation at the description stage or is reproduced and fixed in one place for all nodes.

Recovery of a node after a failure comes down to reapplying the same description: the machine comes up from scratch and reaches the baseline state in the same predictable time.

A separate metric is the share of successful first boots: as long as it holds, the on-duty engineer reads it as a health indicator for the entire process rather than troubleshooting each node separately.

Automation approaches: cloud-init, images, configuration

Initial node setup is solved at one of four levels, and the choice of level determines what will have to be changed the next time requirements change. Below is how the approaches compare by scenario and where each one runs into limitations.

Approach When it fits Limitations
Declarative first-boot script Standard nodes: users, access keys, disk mounting, package installation Runs once at creation; changes after startup are not tracked, and a long script is hard to debug
Prebuilt image A homogeneous fleet where startup speed and an identical software composition matter Rebuilding and versioning with every update; divergence from the source template accumulates
Node configuration management Long-lived servers that change during operation Requires an agent and constant access to the node; for disposable instances it adds overhead
Infrastructure-as-code template A reproducible environment: network, disks, roles, binding nodes to environments Describes the environment but not internal configuration; without a startup script the node remains unready

In practice, the levels are combined: a template creates the node and its environment, a declarative script brings the system to a working state on first boot, an image shortens time to readiness, and configuration management maintains the state afterward.

Next, we examine how to draw the boundary between them and avoid duplicating one setting at two levels.

Implementation order: from audit to handover of policies

The transition from manual machine provisioning to declarative provisioning is a process overhaul, not a cloud-init installation.

Below is the sequence in which we carry out the work: each stage produces a verifiable result, and the work can be stopped without losing what has already been done.

  1. Audit of current server provisioning. We collect an inventory: where images come from, which parameters are set manually, where configurations diverge between environments. The result is a map of differences and a list of operations to remove.
  2. Provisioning scheme. We divide responsibilities: what is baked into the image, what goes into user-data, what is defined later. We fix the template format, secret sources, and application order.
  3. Templates and modules. We write reusable blocks — network, accounts, disk mounting, monitoring agents. One node role — one template, without branching by hostname.
  4. Staging validation. We run the templates in an isolated environment: create and recreate nodes, check repeated runs, behavior when the secret source is unavailable, and behavior with partially applied configuration.
  5. Pilot group of nodes. We move one environment segment to the new scheme and compare it against the baseline by package composition, services, and open ports. We fix errors in the template, not on the machine.
  6. Handover to operations. We provide policies, the provisioning scheme, and the procedure for changing templates: versioning, pre-rollout validation, rollback to the previous revision.

What the team retains: templates, schemes, policies

Server provisioning automation is valuable not for the act of running it, but for what remains in the repository afterward. Templates, profiles, and rules are stored in version control, so provisioning is reproducible in a new environment without the author’s involvement. Below is the list of what we hand over to the team.

  • Set of provisioning templates and profiles — base images, role profiles (web node, database, broker), and environment variables: a new machine comes up from a ready profile rather than being assembled manually.
  • Provisioning flow scheme — the path from request to ready node: where user-data and metadata are inserted, and at what point the node enters load balancing and monitoring.
  • Access policies and roles — least privilege: who edits templates, who can only launch, who reads logs; secrets are not stored in plain text in user-data.
  • Operations documentation — entry points and typical failures with action procedures: initialization failed, node did not register, configuration diverged from the baseline.
  • Template change policy — edits through a branch and validation in a staging environment, profile versioning, a rollback window to the previous revision.
  • Pre-rollout check set — idempotency of repeated runs, correctness of network settings, and node inclusion in monitoring and inventory.

Each item is a working artifact, not a description of “how it should be.” The team changes templates itself and does not come back to us for every edit.

Case study: server provisioning accelerated severalfold

Before implementation, provisioning one node took the client’s team from several hours to a day.

An engineer manually created a virtual machine, installed additional packages, configured network settings and monitoring system connectivity, and then registered the node in the accounting system.

One server required more than twenty manual actions, and roughly every fifth first boot ended in troubleshooting: a forgotten parameter, diverged library versions, an incorrect address in the configuration that kept the node out of monitoring.

What was changed

We assembled a library of declarative templates for standard roles — web node, application node, database, load balancer.

cloud-init on first boot partitions disks, installs packages, configures users and access keys, and starts the monitoring agent; differences between environments are described by variables in user-data, not by instructions for an engineer.

The template is run in a staging environment before rollout, so a configuration error is caught during image preparation rather than when the node is put into operation.

Node provisioning time dropped from hours to a few minutes, and manual operations in the standard scenario were reduced to zero — the engineer only selects the template and environment.

The share of failed first boots fell from 18% to less than 2%, and the remaining failures are related to external causes such as network unavailability and are diagnosed from logs rather than by trial and error.

Recurring configuration errors are gone as a class: the same template produces the same result on the tenth server and the hundredth.

How does initial node setup differ from configuration management?

Initial node setup solves a task for which there is no place in configuration yet: the machine has just appeared, there is no management agent on it, and access has not been granted.

Here cloud-init retrieves user-data from metadata and executes it once — creates users and keys, partitions the disk, configures the network, and installs the configuration management system agent.

Configuration management over the lifecycle begins where initial setup ends.

After that, node state is not created but maintained: it is compared with the desired state, drifted parameters are restored, and changes are delivered across the entire fleet — repeatedly, after reboots, manual edits, and failures.

The tools’ areas of responsibility diverge by repeatability. A first-boot script is almost never idempotent: running it on an already configured node creates duplicate users, remounts a partition, or overwrites a file.

Configuration management is structured the opposite way — a module describes the target state rather than the order of commands, so reapplying settings changes nothing.

The boundary runs along the point when the node is ready to accept the agent: user-data brings the machine to a manageable state, after which the single source of truth is the configuration description.

The overlap remains narrow — image version, time zone, certificates — and is fixed in one place so that both layers do not compete for the same files.

Confusion at this boundary is costly: treating drift by rerunning user-data produces an inconsistent state after reboot, and failing to install the agent during initial setup leaves the machine outside management until manual intervention.

Common technical questions about server provisioning automation

Doubts about automatic server provisioning usually arise not around cloud-init itself, but around how it behaves in the customer’s real environment: with an isolated network, live nodes, and their own operations team.

We address these questions before work starts — they directly affect the provisioning scheme and the scope of materials handed over.

Will provisioning work in an isolated environment without external network access?

Yes. Metadata and user-data are served by an internal source — a service in the environment or a hypervisor template — and packages are taken from an internal mirror.

External access is needed only during the initial assembly of the baseline: after that, the node comes up fully autonomously.

Can existing running servers be migrated?

Yes, but one node at a time. First we capture the current state as a template and validate it on a test copy, then migrate node by node, leaving the old image available for rollback. A mass “single-pass” replacement is not used here.

Who is responsible for templates after handover?

We transfer the templates to the customer’s repository with change history and a description of each parameter. Edits go through review according to an agreed policy — this way, a change that breaks provisioning is visible before it is applied, not after.

How is a node’s compliance with the baseline verified?

Through regular configuration comparison: divergences are included in a report and resolved by reapplying the template rather than by manual edits on the node. Otherwise, configuration drift accumulates and the baseline ceases to mean anything.

What is included in support handover?

Documentation on the provisioning scheme, the template update policy, and incident review with your operations team. After that, you run the environment yourself or keep us on support — both options work.

Let’s discuss your provisioning automation task

For the deployment automation assessment to be substantive, we need inputs about the infrastructure: where the servers live, what you manage them with now, and which machine roles recur.

With this set, we come back not with a generic presentation, but with a work plan and responsibility boundaries.

To start, it is enough to know:

  • how machines are created today — manually, with scripts, or from templates, and how much time one node takes;
  • the list of recurring roles: web node, database, queue broker, build node — and how their configurations differ;
  • whether there are existing cloud-init and user-data artifacts and which base system you are starting from;
  • how secrets and access are structured: where keys are stored, who issues them, and how they reach a starting machine;
  • requirements for rerunning the template on an already running machine;
  • network and storage design: addressing, load balancer, data volumes;
  • what you want to see in the deployment report and where to store template versions.

After the review, we will return an estimate and a stage-by-stage work plan: template preparation, trial on a limited group of machines, then rollout to the entire environment.

A pilot on several nodes shows the time for a machine to reach working state and reveals divergences between roles before changes reach production.

After that, the steps are simple: we agree on the stages, fix readiness criteria for each role, and start with the pilot. Describe the task to the extent you have it — we will clarify the rest with questions.