Skip to content

Creating projects

Every project starts in the wizard under New project - or, if you prefer, from the command line or through the MCP server. The first project page walks through its three steps. This one is about the interesting part: what ends up in the new project folder.

Envoryx creates that folder below /projects, owned by PUID:PGID. A template, a repository or an uploaded website needs it empty or not there yet, because they fill it from scratch. A project without any of those is different: point it at a folder that already holds code, and Envoryx takes the files as they are. That’s the quickest way to give an application you already have on the host a stack of its own.

A template scaffolds a fresh application for you. It runs in a short-lived container from the project’s runtime image, as the project owner, and where the framework needs a database it gets wired to the project’s one. Downloads go into a shared package cache, which is why your second Laravel project comes up a lot faster than the first.

Runtime Templates After creation
PHP Laravel Run artisan migrate from the Actions section.
PHP Symfony (skeleton plus the webapp pack) Run doctrine:migrations:migrate.
PHP WordPress Open the site to run the WordPress installer.
PHP Drupal (with Drush) Open the site, or run drush site:install - it prints the admin password.
PHP TYPO3 Run typo3 setup from the Actions section - it prints the admin password - or use the web installer on the site.
PHP Shopware Run Shopware system:install from the Actions section; the login is admin / shopware.
PHP Craft CMS Run craft install, or open /admin/install.
Node.js Vite + React (TypeScript), Next.js (App Router, TypeScript), Nuxt The dev server answers on the project URL.
Python Django, Flask, FastAPI Django: run manage.py migrate.
Go Go (net/http), Gin, Echo air rebuilds the server on every change.
Ruby Rails, Rails (API only), Sinatra Rails: Envoryx runs rails db:prepare once the project is up; run it from the Actions section if you created the project stopped.
Java Spring Boot, Quarkus REST The server answers on the project URL; the first build fills the Maven cache.
.NET ASP.NET Core Web API, ASP.NET Core MVC, ASP.NET Core Razor Pages, Blazor Web App dotnet watch applies changes with hot reload.

The CMS templates - Drupal, TYPO3, Shopware and Craft CMS - can’t do without a database, so the wizard picks one for you. In the wizard’s gallery the popular templates come first, and Show all templates, the search and the runtime filter find the rest. Each runtime page has the details on its templates.

The full template gallery filtered to Python, showing Django, FastAPI and FlaskThe full template gallery filtered to Python, showing Django, FastAPI and Flask

Choose Git repository under Or start from and enter the repository URL - https://…, git@host:path.git or ssh://… - and a branch if you don’t want the default one. Envoryx clones it into the empty project folder, again in a short-lived container running as the project owner. Tell Envoryx what the repository runs (PHP application, Node.js application and so on); if you haven’t named the project yet, it takes the repository’s name.

The wizard with Git repository chosen: fields for the repository URL and the branch, and the choice of what the repository runsThe wizard with Git repository chosen: fields for the repository URL and the branch, and the choice of what the repository runs

A private repository over HTTPS needs an access token, and a username if your host wants one. On GitHub, a fine-grained token with Contents: read is enough; on GitLab it’s the username oauth2 plus a token.

For SSH repositories Envoryx uses its deploy key. Copy the public key from Settings → Git deploy key (or from the project’s Git section) into the repository as a read-only deploy key before you create the project. The key itself never gets mounted into your project’s containers.

One option deserves a mention: Use the repository’s envoryx.yml, on by default. If the repository comes with an envoryx.yml, that file decides the runtimes, services, domains, environment, workers and cron jobs, and the rest of the wizard only matters when there isn’t one. It’s the easiest way to hand a project to a colleague.

For a Node.js dev server, the wizard has to guess the script and the preset before it can see the repository. Once the clone is there, Envoryx looks at its package.json: if the script the wizard picked isn’t in there, it takes dev or start (start or preview for a production build) and the preset of the framework it finds in the dependencies, Next.js, Nuxt or Vite, otherwise Other. The dependencies themselves come with the dev server’s first start, from the repository’s lockfile, as the Node.js page explains.

After that, the Git section pulls, switches branches (a branch that only exists on the remote becomes a local one that tracks it; pull first if it was pushed after the clone) and shows the status. If the repository moves, change the Repository URL there; saving it points the checkout’s origin at the new address too, so the next pull comes from the right place.

Existing website under Or start from is for sites that already live somewhere else - an old shared host, a backup, an FTP download. Upload the files as a ZIP or tar archive (.zip, .tar.gz, .tgz or plain .tar), and a database dump (.sql or .sql.gz) if there is one. A single wrapping folder like public_html/ gets dropped automatically. Envoryx looks through the archive and fills in the rest of the wizard with what it found. You can still change all of it.

A backup you downloaded from Envoryx works here too: instead of analysing it as a website, Envoryx restores it into a new project with the settings it was made with.

The Existing website source after uploading a downloaded backup: recognised as a backup of Acme Shop, with a Restore into a new project buttonThe Existing website source after uploading a downloaded backup: recognised as a backup of Acme Shop, with a Restore into a new project button

Here’s what it recognises:

Site Recognised by Suggestion
WordPress wp-config.php, wp-includes/version.php PHP up to what the WordPress version supports, mysqli, MariaDB
Laravel artisan + laravel/framework document root public, database from .env
Symfony bin/console + symfony/framework-bundle document root public (web for Symfony 2/3), database from DATABASE_URL
Drupal core/lib/Drupal.php (also below web/), Drupal 7 document root, PHP by major version
TYPO3 typo3/sysext, typo3/cms-core document root public in Composer mode
Joomla configuration.php with JConfig PHP by version, mysqli
Shopware, Craft CMS, other Composer apps composer.json PHP from require.php, ext-* extensions
Plain PHP .php files document root where index.php is; the files that connect to a database
Static site, Node.js, Python, Go, Ruby, Java, .NET index.html, package.json, manage.py/requirements.txt, go.mod, Gemfile, pom.xml/build.gradle, .sln/.slnx/.csproj at the top the matching runtime

For PHP, Envoryx picks the newest version it offers that composer.json and the CMS version allow. If the code uses functions PHP 8 removed, you get PHP 7.4. And if there’s a .htaccess in the document root, it suggests Apache, since that’s the only web server that reads it.

Adapting the configuration is on by default and connects the site to the project database. WordPress reads the injected database variables in wp-config.php. Drupal, TYPO3 and Joomla get the connection written into their configuration. WordPress, Drupal and TYPO3 also get the same lines a new project of theirs gets: the address, trusted hosts, Redis and mail follow the project, as the PHP page explains. Laravel, Symfony and Shopware need nothing at all, because the injected DB_* and DATABASE_URL override their .env. Symfony gets one line, though: the site’s .env usually names the server version in DATABASE_URL, the injected URL doesn’t, and Doctrine would stop with Invalid platform version. So config/packages/doctrine.yaml reads server_version from DB_SERVER_VERSION, as in the Symfony template, unless it sets a version itself. That file is changed in place, without a copy next to it, because Symfony would load a copy in config/packages as configuration. Every other file Envoryx changes keeps its original right next to it as <name>.envoryx-original.php, and that one answers with a 404, so the old credentials are never served. One thing it can’t fix for you: WordPress itself and wp-admin follow the new address, but the links inside posts and pages are stored with the old one. WP-CLI is in the PHP image, so wp search-replace 'https://old-blog.example' 'https://old-blog.test' in the PHP terminal takes care of those.

The dump gets imported once the containers exist. Statements that tie it to the old server - CREATE DATABASE, USE, users, owners, grants, roles - are skipped. Hosting panels and phpMyAdmin like to export the old user’s GRANT and CREATE USER lines, and those no longer stop the import. A MySQL view, trigger or routine also loses its DEFINER: that user only existed on the old server, and MySQL would create the object but refuse to run it. Without the clause it belongs to the user that imports the dump. pg_dump’s custom format won’t work; export plain SQL with pg_dump --format=plain instead. If the import fails, the project is rolled back and the upload stays around for another try.

Uploads wait for 24 hours. An archive may be up to 20 GiB and unpack to at most 64 GiB. The same works from the command line:

Terminal window
envoryx import ./old-blog "Old Blog" --db old-blog.sql.gz --start
envoryx import backup.zip --php 8.2 --web nginx --no-adapt
envoryx import ./site --dry-run # only show what Envoryx recognises

The Create step shows the plan - the containers, volumes and images Envoryx is going to create - and warns you about things that don’t add up, say a server that’s switched on while nothing will create the application yet. Before anything runs, Envoryx asks the registry for the current build of every image in the plan. Another project may have left an older build of the same tag on the host, and that one could lack tools the current Envoryx relies on. Without a connection it goes ahead with the local image. Once you start, creation runs on the server until it’s done, even if you close the browser tab.

The Create step for a Laravel project: identifier, template, files, URL and network, then the containers with their images, ports and mountsThe Create step for a Laravel project: identifier, template, files, URL and network, then the containers with their images, ports and mounts