# Chef Zero: an in-memory Chef server for tests and chef-solo-like work

> Chef Zero is a Ruby implementation of the Chef server API that keeps all its state in memory, so it starts instantly, does no authentication or input validation, and forgets everything when it stops. It suits a developer writing Chef cookbooks who needs a real server to point knife at, and it is Apache-2.0 licensed.

**chef/chef-zero** — Simple, easy-run, fast-start in-memory Chef server for testing and solo purposes

- Repository: https://github.com/chef/chef-zero
- Stars: 530 · Forks: 94
- Language: Ruby
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/chef-chef-zero

## What the server deliberately does not do

Chef Zero is a simple, easy-install, in-memory Chef server that can be useful for Chef Client testing and chef-solo-like tasks that require a full Chef Server.

The readme states the limits in one dense paragraph, and it is worth reading in full because it is the whole specification of the project.

It is intended to be simple, Chef 11+ compliant, easy to run and fast to start. It is not intended to be secure, scalable, performant or persistent. It does no input validation, authentication or authorization, and will not throw a 400, 401 or 403. It does not save data, and will start up empty each time you start it.

That list is unusually clear for a project README, and it converts the usual ambiguity into a set of facts you can plan around. No authentication means there is no user management, no signing-key verification and no policy file, which is why the CLI documentation says any .pem file will do, since the client just needs something to sign requests with and the signature is ignored on the server. Even though it is ignored, the .pem must still be a valid format, which is the kind of detail that produces a confusing failure if you skip it.

No input validation means the server will accept a malformed cookbook, a node object with fields that make no sense, or a data bag that is not valid JSON, and it will store them without complaint. That is exactly what you want in a test harness where the test is about your cookbook logic and not about the shape of the data.

No persistence means the server is empty on every start. The readme puts it plainly at the end of the CLI section: now, stop the Chef Zero server and all the data is gone.

Because Chef Zero runs in memory, it is fast and lightweight, and the readme says that makes it perfect for testing against a real Chef Server without mocking the entire Internet. That phrasing is the actual value proposition: you get the real API surface rather than a hand-written double.

The primary language is Ruby, the licence is Apache-2.0, the default branch is main, and the last push was on 2026-09-29.

## Installing it as a gem, and running it as a library

The server installs as a Ruby gem.

```bash
$ gem install chef-zero
```

If you use bundler, it goes in as a development dependency.

```ruby
group :development do
  gem 'chef-zero'
end
```

And in a gemspec it is a development dependency too.

```ruby
s.add_development_dependency 'chef-zero'
```

You can also clone the source and install it with rake install.

The library usage is four lines, and the first one is the whole API surface.

```ruby
require 'chef_zero/server'
server = ChefZero::Server.new(port: 4000)
server.start
```

That creates a server instance in the foreground, and server.stop stops it. The readme notes that this is great for debugging and logging requests, but you will probably want to run it in the background so you have full control of your thread.

Which is why there is a start_background variant.

```ruby
require 'chef_zero/server'
server = ChefZero::Server.new(port: 4000)
server.start_background
```

And you stop it the same way, with server.stop.

The background version matters more than it looks for a testing tool. When the server runs in the foreground it occupies the thread that started it, so a test harness that wants to control when the server stops, or to run other work against it, needs the background form.

Only three options can currently be passed to the initializer, and they are all in the readme: host, the host to run on, defaulting to 127.0.0.1; port, the port to run on, defaulting to 8889; and debug, to run in debug mode to see all requests and responses, defaulting to false.

The debug flag is the one to know about. Because the server does no validation and no authentication, seeing the actual request and response bodies is how you find out what your cookbook actually sent.

## The CLI, and the flags that go beyond the library

There is an included chef-zero executable, and if you do not want to use Chef Zero as a library you can simply start an instance with it.

```bash
$ chef-zero
```

It runs in the foreground, and you end up with a fully functional, empty Chef Server running.

The flag list is where the CLI offers more than the library does, and it is printed in the readme.

```text
Usage: chef-zero [ARGS]
    -H, --host HOST                  Host to bind to (default: 127.0.0.1)
    -p, --port PORT                  Port to listen on (e.g. 8889, or 8500-8600 or 8885,8888)
        --[no-]generate-keys         Whether to generate actual keys or fake it (faster).  Default: false.
    -d, --daemon                     Run as a daemon process
    -l, --log-level LEVEL            Set the output log level
        --log-file FILE              Log to a file
        --enterprise                 Whether to run in enterprise mode
        --multi-org                  Whether to run in multi-org mode
        --file-store PATH            Persist data to files at the given path
        --[no-]ssl                   Use SSL with self-signed certificate(Auto generate before every run).  Default: false.
    -h, --help                       Show this message
        --version                    Show version
```

Four of these are worth pausing on.

The --[no-]generate-keys flag controls whether the server generates real keys or fakes them, and faking is faster. The default is false, meaning real key generation by default, which is the slower path and arguably pointless when the server ignores signatures anyway.

The --file-store PATH flag is the exception to the no-persistence rule. It persists data to files at the given path, which turns Chef Zero into something more useful than a pure test double: a Chef server you can restart without losing state, which is what you want if you are using it as a chef-solo-like backend rather than a test fixture.

The --enterprise and --multi-org flags exist because the API surface has those variants, and running in those modes changes how the server interprets organisations in requests. And --[no-]ssl uses SSL with a self-signed certificate, auto-generated before every run.

The port help text also hints at something. It lists 8889 as the example and mentions 8500 to 8600 and 8885, 8888, which suggests a set of ports conventionally used for the different Chef server components.

## Testing with knife, and the playground repository

The readme gives a worked example that is also the best way to understand what the server supports.

To try it out, go into the chef-zero/playground directory and run knife. It behaves the same as a normal Chef Server, and all normal knife commands work, including show, list, delete, from file, upload, download and diff. With knife-essentials, or Chef 11, you can upload everything in the repo.

```bash
chef-zero/playground> knife upload .
Created nodes/desktop.json
Created data_bags/dns
Created environments/production.json
Created nodes/lb.json
Created nodes/dns.json
Created nodes/ldap.json
Created nodes/www.json
Created data_bags/dns/services.json
Created environments/staging.json
Created data_bags/passwords
Created data_bags/users
Created data_bags/users/jkeiser.json
Created data_bags/passwords/github.json
Created data_bags/users/schisamo.json
Created data_bags/users/sethvargo.json
Created data_bags/passwords/twitter.json
Created cookbooks/apache2
Created cookbooks/php
```

So a single upload populates nodes, environments, data bags and cookbooks, which tells you the server implements the whole object model rather than a subset.

And then the list command shows the environments.

```bash
chef-zero/playground> knife environment list
_default
production
staging
```

To use it in your own repository, you create a knife.rb like so.

```ruby
chef_server_url   'http://127.0.0.1:8889'
node_name         'stickywicket'
client_key        'path_to_any_pem_file.pem'
```

And use knife as you normally would. Since Chef Zero does no authentication, any .pem file will do, because the client just needs something to sign requests with and that is ignored on the server.

The playground directory is a top-level entry in the repository alongside lib/, bin/, spec/ and the Rakefile, so it ships as part of the gem rather than being a separate sample project.

The repository also carries an .rspec file, a .rubocop.yml, a sonar-project.properties file, a .expeditor/ directory and a SECURITY.md, which together suggest a project with a normal development process attached to it.

## What Chef Zero replaces, and what it does not

Three comparisons are worth drawing, because the choice of Chef Zero versus something else comes down to what you are testing.

The first is against a mock, a hand-written stub of the Chef server API in your test suite. The difference in approach is that a mock encodes what you believe the server does, and it is only as good as that belief. Chef Zero is the actual server implementation in the same language as the client, so a test against it exercises the real request handling, the real object model and the real API semantics. The readme's phrase about not mocking the entire Internet is the right way to put it.

The second is against a full Chef Server, either the open source one or Chef Infra Server. A real server brings persistence, authentication and authorisation, and in the hosted case a licence and a running cost. For a test suite, all of that is overhead, and some of it is actively unhelpful, because a test that has to authenticate and has to clean up after itself is a test that fails for reasons unrelated to what it is testing.

The third comparison is against chef-solo, which is the mode of work Chef Zero most resembles. chef-solo runs cookbooks locally without a server at all. The problem with chef-solo for testing is that it exercises a different code path in the client, because there is no server to talk to, so a bug that only appears when talking to a real server will not show up. Chef Zero gives you the server conversation without the server weight.

The limitation is the one the readme lists, and it is not a small one: this is not a production Chef server. No persistence by default, no authentication, no validation, no scale. The readme says outright that it is not intended to be secure, scalable, performant or persistent.

There is also a version caveat worth flagging. The recent releases listed are v1.6.3 from 2014, v2.0.2 from 2014 and v2.0.1 from 2014, so the published gem versions are more than a decade old, while the last push to the repository was on 2026-09-29. The code is being worked on but the version numbering has not moved in that time, and the Chef 11+ compliance claim is against a much older client generation than a current Chef Infra release.

So the practical question is not whether Chef Zero works, it does, but whether its API still matches the client you are testing against.

## Conclusion

Chef Zero fits a cookbook developer who wants a real Chef server API to point knife at during tests, or anyone who needs a throwaway Chef endpoint for local experimentation, and it does not fit production, since the readme states plainly that it is not intended to be secure, scalable, performant or persistent. Before running it anywhere shared, note that it does no input validation, authentication or authorization and will not throw 400, 401 or 403, so bind it to localhost unless you have put your own access control in front of it.

## FAQ

### What is Chef Zero and what is it for?

Chef Zero is a simple, easy-install, in-memory Chef server for Chef Client testing and chef-solo-like tasks that need a full Chef Server. It is Chef 11+ compliant, easy to run and fast to start, and it keeps all state in memory.

### Is Chef Zero safe to expose on a network?

No. The readme states it is not intended to be secure, scalable, performant or persistent, that it does no input validation, authentication or authorization and will not throw a 400, 401 or 403, and that it does not save data. The host option defaults to 127.0.0.1.

### How do I install and start Chef Zero?

Install it with gem install chef-zero, or add it as a development dependency in your Gemfile or gemspec. Start it with the chef-zero executable, or in code with ChefZero::Server.new(port: 4000) followed by server.start, or server.start_background to run it in the background.

### Can Chef Zero save data between runs?

By default no, it starts up empty each time and loses everything when stopped. The CLI has a --file-store PATH option to persist data to files at the given path, which is useful if you are using it as a chef-solo-like backend rather than a throwaway test server.

## Sources

- [chef/chef-zero on GitHub](https://github.com/chef/chef-zero)
- [Issues](https://github.com/chef/chef-zero/issues)
- [License: Apache-2.0](https://github.com/chef/chef-zero/blob/main/LICENSE)
- [README](https://github.com/chef/chef-zero/blob/main/README.md)
- [Releases](https://github.com/chef/chef-zero/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/chef-chef-zero
