← All posts
Kristijan Lukačin28 April 20266 min read

Manual recipes: deploying things that do not want to be Docker

Not every project fits in a container. v1.6 added a manual recipe for everything else — Nebion runs your deploy and destroy commands directly on the server.

For two years we had a polite, opinionated answer to can I deploy X on Nebion and that answer was: put it in a container.

It worked, mostly. PR environments, multi-service apps, automatic SSL, the whole story is much easier when every project speaks Docker. But there is a long tail of things that do not really want to be Docker: a static site built by Hugo, a WordPress install with two cron jobs, a legacy PHP app that already has its own deploy script and just wants somewhere stable to run.

We kept saying wrap it in a container and people kept… not doing that. Fair enough. So in v1.6 we added a second recipe.

The manual recipe, in one minute

Add this to .nebion.yml at the root of your repo:

.nebion.ymlyaml
recipe: manual

deploy:
  - bin/build.sh
  - bin/release.sh

destroy:
  - bin/teardown.sh

That is it. No docker-compose-nebion.yml. No image tags. When a deployment runs, Nebion clones your repo onto the target server, exports its standard environment variables, and executes your deploy commands one by one. When the environment is torn down, your destroy commands run. You write the bash. We handle the cloning, the variables, the routing, the logging, the dashboard.

Manual recipes get the same dashboard, live logs, actions, and env vars as container recipes. The only thing you give up is container isolation. Your scripts run as the project user on the host.

A real example: a Hugo site behind nginx

Here is the actual config for one of our marketing sites. It is a static Hugo build that we publish to /var/www/site and which nginx serves directly. No container in sight.

# .nebion.yml
recipe: manual

deploy:
  - hugo --minify --baseURL "https://${NEBION_DOMAIN}"
  - rsync -a --delete public/ /var/www/${NEBION_ENV_IDENTIFIER}/
  - nginx -s reload

destroy:
  - rm -rf /var/www/${NEBION_ENV_IDENTIFIER}
  - nginx -s reload

Push to main, Nebion runs the three deploy commands, the site is live. Open a PR, Nebion deploys to a separate NEBION_ENV_IDENTIFIER-scoped directory and gives you a preview URL. Close the PR, the destroy commands clean up. The whole config is twelve lines.

When to reach for it

Use a manual recipe when you already have a working deploy script and you do not want to rewrite it; when the thing you are deploying genuinely does not fit a container; or when you want a static site or a single binary copied to a path, not a service running in a container.

Use a container recipe (the default) when you want PR previews, isolation, or any of the multi-service routing the platform does well.

Keep reading
Block types: code, callout, cta, image, mascot
Read post →
Environment Actions: stop SSH-ing in to clear a cache
Read post →
Why we built Nebion (the short, honest version)
Read post →