Skip to content

Security

Envoryx is a development tool for your own network, and it runs containers for you through the Docker socket. That’s a lot of power, so it’s worth knowing where the boundaries are and what you should keep an eye on.

Envoryx starts with /var/run/docker.sock mounted, and access to that socket is effectively root on the host. There’s no way around that for a tool that creates containers, so Envoryx puts its own limits in place.

It builds container specifications only from a fixed catalogue, and that catalogue simply can’t express the dangerous things: no privileged mode, no extra capabilities, no host networking, no device access, no arbitrary bind mounts. Containers run with no-new-privileges and without NET_RAW. Before it changes anything, Envoryx checks the target’s envoryx.managed=true label, so containers, networks and volumes it didn’t create are never touched - they only show up, read-only, on the Docker page. The same goes for what another Envoryx on the host created: its envoryx.instance label names the other instance, and this one keeps its hands off (several instances on one host). And the API never takes container ids at all; it talks about project + service and looks up the container on the server side, so nobody can point it at a container of their choosing.

If you want to narrow things down further, put a socket proxy such as tecnativa/docker-socket-proxy in between and set DOCKER_HOST=tcp://docker-socket-proxy:2375. Envoryx needs the CONTAINERS, IMAGES, NETWORKS, VOLUMES, EXEC, EVENTS, INFO, VERSION and POST groups, plus BUILD if you build custom images from a project Dockerfile and SYSTEM for the volume sizes in the resource history. SWARM, NODES, SECRETS, CONFIGS, PLUGINS and COMMIT can stay off.

A socket proxy filters by endpoint, not by what a request asks for. With CONTAINERS and POST open, whoever controls Envoryx can still create a privileged container, so the proxy narrows what a bug can reach but doesn’t make a taken-over Envoryx any less than root on the host. The real protection is keeping Envoryx out of reach: HTTPS, not open to the internet, and accounts only for people you’d trust with the projects’ containers.

Passwords are hashed with argon2id and have to be at least 10 characters long. A session ends after 12 hours without activity and after 7 days at the latest (ENVORYX_SESSION_IDLE_TIMEOUT, ENVORYX_SESSION_ABSOLUTE_TIMEOUT). When you serve Envoryx over HTTPS, set ENVORYX_SECURE_COOKIES=true so the session cookie never travels unencrypted.

Envoryx slows down failed sign-ins per address and user name, so guessing passwords gets tedious quickly. Changing your password signs out all your other sessions - useful if you suspect a browser somewhere is still logged in.

Locked yourself out? See Troubleshooting → Lost access.

A token (they start with stq_) is shown once and then stored only as a hash. Give every client its own token with the smallest scope it needs, and limit it to projects where you can - then a leaked CI token can only do so much. Tokens can’t create other tokens, change the password, manage users or show the secret key, and the MCP endpoint only accepts tokens, never a session cookie.

The SSH server on port 2222 never lets anyone into the Envoryx container or onto the host. Every session is a docker exec into a project container, as the project owner. SFTP shows exactly two folders: the project and its persistent home. Wrong or unknown API tokens are counted: ten within ten minutes lock that address out of the project for five minutes, 30 over all projects lock out the whole address. Offered keys and the empty password OpenSSH sends without a prompt don’t count, so a team behind one NAT doesn’t lock itself out by accident. The details are under Locked out?.

Delve (Go), rdbg (Ruby) and JDWP (Java) have no authentication at all: whoever reaches the port can run any code in the container. Xdebug, the Node inspector and debugpy aren’t much different. So switch a debug port on while you’re debugging, switch it off afterwards, and don’t use them on a Docker host that’s reachable from networks you don’t trust.

/config holds the database (with project credentials and secret variables), the SSH keys and the local CA. The CA key deserves special care: it can sign certificates for any name, so whoever has it can impersonate websites on every device that trusts your CA. Keep the folder private and only install the CA on machines you control. If you ever think the key got out, delete /config/ca/; Envoryx creates a new CA, which you then install on your devices again.

Backups contain credentials and tokens too. Treat a downloaded backup like a password file, and use the encryption of offsite backups.

The secrets Envoryx stores are encrypted: Git tokens, secret variables, the service credentials, the single sign-on client secret, registry logins, and the notification, offsite and ACME settings. The key for that comes from ENVORYX_SECRET_KEY on the container, or, without it, from /config/secret.key, which Envoryx creates at the first start. The variable is the better place, because then a copy of /config (an appdata backup, a stolen disk image) holds only encrypted secrets. openssl rand -base64 32 makes a good key, and switching from the file to the variable needs nothing else: at that start Envoryx re-encrypts everything with the new key and deletes the file.

Settings → Secret key shows the key’s ID and where it comes from. Show key reveals the key itself, and the audit log notes that you did. Keep a copy somewhere outside Envoryx. Instance backups never contain the key, so without that copy you can’t restore one on another host. With the key file, Replace the key creates a new one and re-encrypts everything; with the variable, you set the new key there and the current one as ENVORYX_SECRET_KEY_OLD for one start. Your local project backups are re-encrypted along with everything else, but instance backups made before and the copies of project backups already on offsite targets keep needing the old key, so keep it as long as you might restore one of them. A restore that lacks the key names the ID of the one it needs. Either way of replacing the key ends up in the audit log (settings.secret_key_rotated).

Showing and replacing the key need an admin’s browser session. API tokens are refused, even with admin scope, so a leaked token can’t walk off with the key to every stored secret.

A share makes a project reachable from the internet without any sign-in. If there’s anything in it that isn’t meant for everyone, put a password on it in the project’s rules - or share a staging copy instead of the real thing.

Project containers can reach Envoryx’s ports on the project network, just like any other device on your LAN. Code you run in a project is trusted about as much as code you run on your own workstation, so treat unfamiliar repositories with the same care.