Existing C++ Projects | Vix.cpp Documentation
Vix.cpp v2.7.0 is here Read the blog
Skip to content

Existing C++ Projects

Vix production files can be used with an existing C++ project even when the project was not created with vix new. The project may already have its own CMake layout, build directory, service binary, configuration loader, and deployment habits. In that case, Vix does not need to reshape the source tree. It only needs a small vix.json file that describes the production parts around the application.

This is useful when a C++ service already exists and the missing piece is not project scaffolding, but operational structure: how the service is installed, how it is restarted, which health endpoint proves it is running, which Nginx proxy points to it, where logs are read from, and which environment variables must exist in production.

The idea

A Vix-generated backend already contains production metadata because the template creates vix.json, .env.example, routes, health endpoints, and the expected directory layout. An existing C++ project may not have any of that. It may only have a binary and a server where the binary runs.

For this kind of project, Vix production files act as a small operational layer. The application remains your application. The build system remains your build system. Vix simply reads the project metadata and uses it to run production commands such as service management, proxy generation, health checks, log inspection, deployment, environment validation, database checks, and WebSocket diagnostics.

Minimal project shape

A simple existing project can look like this:

txt
legacy-api/
  CMakeLists.txt
  src/
  include/
  build/
  .env
  .env.example
  vix.json

The important file for Vix is vix.json. The .env and .env.example files are useful when the service depends on runtime variables, but Vix does not require the project to use a Vix template layout.

Minimal vix.json

Start with a small production file that describes the real binary and working directory.

json
{
  "name": "legacy-api",

  "production": {
    "service": {
      "name": "legacy-api",
      "user": "deploy",
      "working_dir": "/srv/legacy-api",
      "exec": "/srv/legacy-api/build/legacy-api",
      "restart": "always",
      "restart_sec": 3,
      "limit_nofile": 65535
    }
  }
}

This gives Vix enough information to manage the service around the existing binary. The exec value should point to the executable that your normal build command produces. The working_dir should match the directory from which the application expects to read files such as .env, storage/, public/, or other runtime assets.

Add a deploy workflow

After the service metadata is clear, add the deploy section. The build command can be a Vix command, a CMake command, a Make command, or any command that works for the project on the server.

json
{
  "name": "legacy-api",

  "production": {
    "service": {
      "name": "legacy-api",
      "user": "deploy",
      "working_dir": "/srv/legacy-api",
      "exec": "/srv/legacy-api/build/legacy-api",
      "restart": "always",
      "restart_sec": 3,
      "limit_nofile": 65535
    },

    "deploy": {
      "pull": true,
      "branch": "main",
      "build": "cmake --build build --config Release",
      "tests": true,
      "test_command": "ctest --test-dir build --output-on-failure",
      "service": "legacy-api",
      "health_local": true,
      "health_public": false,
      "proxy_check": false,
      "proxy_reload": false,
      "logs_on_failure": true,
      "log_lines": 120,
      "rollback": false
    }
  }
}

This configuration tells Vix how to release the existing project without assuming it was generated by Vix. The deploy command will pull code, build the application, run tests when enabled, restart the service, check service status, run health checks when configured, and show logs if something fails.

bash
vix deploy --dry-run
vix deploy

Use the dry run first. It confirms the deployment flow before Vix changes the running service.

Add health checks

A production service should expose a small endpoint that proves the process is running and reachable. For an existing C++ project, this can be any route the application already supports.

json
{
  "production": {
    "health": {
      "service": "legacy-api",
      "local": "http://127.0.0.1:8080/health",
      "public": "https://api.example.com/health",
      "expected_status": 200,
      "timeout_ms": 2000,
      "max_response_ms": 1000
    }
  }
}

Then run:

bash
vix health local
vix health public

The local check should be configured first because it verifies the application before the proxy is involved. Once the local endpoint is stable, add the public endpoint if the service is exposed through Nginx.

Add proxy configuration

When the service is exposed through a domain, describe the Nginx proxy in the same production file.

json
{
  "production": {
    "proxy": {
      "domain": "api.example.com",

      "http": {
        "port": 8080
      },

      "tls": {
        "enabled": true
      }
    }
  }
}

Then initialize or check the proxy:

bash
vix proxy nginx init
vix proxy nginx check

The application still listens on its local port. Nginx receives public traffic and forwards it to the local upstream. Vix uses the metadata to generate and validate that Nginx configuration.

Add logs

Logs connect the production commands to the real runtime output. For an existing Linux service, application logs usually come from systemd and proxy logs usually come from Nginx.

json
{
  "production": {
    "logs": {
      "service": "legacy-api",
      "nginx_access": "/var/log/nginx/legacy-api.access.log",
      "nginx_error": "/var/log/nginx/legacy-api.error.log",
      "lines": 120
    }
  }
}

Useful commands:

bash
vix logs app
vix logs proxy
vix logs errors --repeated

This makes failure diagnostics easier during deployment. When logs_on_failure is enabled in the deploy section, Vix can show recent repeated errors automatically when a release step fails.

Add environment checks

If the service depends on runtime variables, keep .env.example in the repository and declare production-required keys in vix.json.

json
{
  "production": {
    "env": {
      "required": ["APP_ENV", "SERVER_PORT", "DATABASE_URL", "API_TOKEN"]
    }
  }
}

Then check the environment:

bash
vix env check
vix env check --production

This helps catch missing variables before a service restart. It also helps detect a common production issue: the project file says one thing, while systemd is running the service with another value.

Add database metadata

For SQLite-backed services, Vix can inspect storage, apply migrations, and create backups.

json
{
  "database": {
    "engine": "sqlite",
    "sqlite": {
      "path": "storage/legacy-api.db"
    },
    "storage": "storage",
    "migrations": "migrations"
  }
}

Useful commands:

bash
vix db status
vix db backup
vix db migrate

This does not require the application to use a Vix-generated database layer. Vix only needs to know where the SQLite file, storage directory, and migration files live.

Add WebSocket metadata

If the application exposes a WebSocket endpoint, describe both the local endpoint and the public endpoint.

json
{
  "production": {
    "websocket": {
      "host": "127.0.0.1",
      "port": 9090,
      "path": "/ws",
      "local_url": "ws://127.0.0.1:9090/ws",
      "public_url": "wss://api.example.com/ws",
      "timeout_ms": 3000,
      "heartbeat": true
    },

    "proxy": {
      "domain": "api.example.com",
      "http": {
        "port": 8080
      },
      "websocket": {
        "enabled": true,
        "path": "/ws",
        "port": 9090
      },
      "tls": {
        "enabled": true
      }
    }
  }
}

Then check the local endpoint first:

bash
vix ws check ws://127.0.0.1:9090/ws
vix proxy nginx check

For WebSocket problems, debug from the application outward: local service, local WebSocket URL, proxy configuration, then public endpoint.

Complete example

A more complete existing C++ service can use this kind of vix.json:

json
{
  "name": "legacy-api",

  "database": {
    "engine": "sqlite",
    "sqlite": {
      "path": "storage/legacy-api.db"
    },
    "storage": "storage",
    "migrations": "migrations"
  },

  "production": {
    "service": {
      "name": "legacy-api",
      "user": "deploy",
      "working_dir": "/srv/legacy-api",
      "exec": "/srv/legacy-api/build/legacy-api",
      "restart": "always",
      "restart_sec": 3,
      "limit_nofile": 65535
    },

    "deploy": {
      "pull": true,
      "branch": "main",
      "build": "cmake --build build --config Release",
      "tests": true,
      "test_command": "ctest --test-dir build --output-on-failure",
      "service": "legacy-api",
      "health_local": true,
      "health_public": true,
      "proxy_check": true,
      "proxy_reload": false,
      "logs_on_failure": true,
      "log_lines": 120,
      "rollback": false
    },

    "env": {
      "required": ["APP_ENV", "SERVER_PORT", "DATABASE_SQLITE_PATH"]
    },

    "health": {
      "service": "legacy-api",
      "local": "http://127.0.0.1:8080/health",
      "public": "https://api.example.com/health",
      "expected_status": 200,
      "timeout_ms": 2000,
      "max_response_ms": 1000
    },

    "proxy": {
      "domain": "api.example.com",
      "http": {
        "port": 8080
      },
      "tls": {
        "enabled": true
      }
    },

    "logs": {
      "service": "legacy-api",
      "nginx_access": "/var/log/nginx/legacy-api.access.log",
      "nginx_error": "/var/log/nginx/legacy-api.error.log",
      "lines": 120
    }
  }
}

This file does not force a Vix source layout. It gives Vix the production contract for an existing service.

Practical adoption order

Add production files gradually. Start with the service section because it identifies the running process. Then add health checks so Vix can prove the application responds. After that, add logs, proxy, deploy, environment, database, and WebSocket sections as the project needs them.

A clean first pass usually looks like this:

bash
vix service status
vix health local
vix logs app

Then validate the wider production setup:

bash
vix production validate
vix production status

When the deploy section is ready:

bash
vix deploy --dry-run
vix deploy

Common problems

If Vix cannot restart the service, check that production.service.name and production.deploy.service refer to the same systemd unit.

If the service starts but health fails, confirm that the application listens on the port used by production.health.local.

If the public health check fails while local health passes, inspect the proxy configuration, DNS, TLS, and Nginx logs.

If deploy builds the project but the old binary still runs, check that production.service.exec points to the binary produced by the build command.

If logs are empty or missing, check the systemd service name and the Nginx log paths.

Next step

Continue with the production status documentation to see how Vix combines service, health, proxy, and logs into one inspection command for deployed applications.

Released under the MIT License.