Writing
How to Connect a Self-Hosted Hermes AI Agent on Hostinger VPS to VS Code
The setup half of my self-hosted agent experiment: getting from a MacBook to the Hermes Agent container on a Hostinger VPS through VS Code, with the model key in the right file and nothing exposed that should not be.
By Ka Lun Chan · Learning and tools · Learning / AI
Why I wanted to try Hermes
This is part of my ongoing experiment with self-hosted AI agents, and it is the setup half. The design half, a job-search agent that runs on a schedule and reports to my phone, is in building my own AI job search agent with Hermes. Before any of that could happen I needed to get at the machine it runs on, and I wanted to do that from the editor I already live in rather than a web console.
Hermes Agent is an open-source, self-hosted AI agent from Nous Research. It runs as a long-lived process on your own server, loads small instruction files called skills when a task needs them, schedules recurring jobs with its own cron, and talks to you through a gateway that connects to Telegram and other messaging platforms. You bring the model: an Anthropic, OpenAI or OpenRouter key, a local model, or the credits a host bundles.
I use ChatGPT and Claude Code most days as tools, and they are good. Hermes is no smarter than they are. It runs when I am not there, keeps state between runs, and has tools wired to my own systems, all of it on a server I administer. That is why self-hosting interests me as an engineer: the plumbing is explicit, and explicit plumbing is what I want to learn. What I hope to automate is the repetitive research in a senior job search, and later some of my own development chores.
VS Code matters here because Remote-SSH turns the VPS into a workspace. I can browse the file system, open the agent's configuration in a real editor, keep a terminal open on the box, read Docker logs, and write the skills and scripts that will become the job-search pipeline, all with the same keybindings and extensions I use locally. A browser console can do some of that. It cannot do it comfortably for hours.
- MacBook to Hostinger VPS
- Hostinger VPS to Docker
- Docker to Hermes Agent
- Hermes Agent to Anthropic API
- Hermes Agent to nexos.ai credits
What you need
- A Hostinger VPS with Hermes Agent installed. In hPanel, open the VPS, then Docker Manager, then Catalog, search for Hermes Agent and select it. The wizard asks for an admin username and password and offers to connect nexos.ai credits if your plan included them. Hostinger’s own tutorial recommends at least 2 vCPU and 8 GB of RAM for the agent.
- Visual Studio Code on your laptop, with Microsoft’s Remote - SSH extension.
- SSH access to the VPS: its IP address, and the root password Hostinger set, which you will stop using once a key works.
- An SSH key pair. Password logins work, and keys are the right habit on a server that will hold API credentials.
- Basic Docker familiarity: what a container, an image and a volume are, and that a container’s filesystem is disposable unless a path is mounted.
Everything below is from a Mac. Linux is the same. Windows users can do all of it from PowerShell with OpenSSH, which ships with Windows.
Configure SSH access
Generate a key pair on the laptop. The comment is a label so you recognize the key later; it is not a secret.
ssh-keygen -t ed25519 -C "hermes-vps"
# accept the default path (~/.ssh/id_ed25519) and set a passphraseInstall the public key on the VPS. If password SSH works, the quickest route is the standard helper, which appends the key to the server’s authorized keys and fixes permissions:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@YOUR_VPS_IPIf SSH does not work yet at all, which is common right after provisioning or after a firewall change, use the browser terminal in hPanel. Open the VPS, start the browser terminal, log in as root, and paste the key in by hand:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA...your public key... hermes-vps" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysThen give the host a short name on the laptop so you never type the IP again. The name is what VS Code will show.
Host hermes
HostName YOUR_VPS_IP
User root
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesTest it. The first connection asks you to confirm the server’s fingerprint; after that it should drop you at a prompt without a password.
ssh hermesOnce the key works, create a non-root user for day-to-day administration and use root only when something needs it. A mistake typed as root on a server that holds API keys has no safety net.
adduser kc
usermod -aG sudo,docker kc
mkdir -p /home/kc/.ssh && cp ~/.ssh/authorized_keys /home/kc/.ssh/
chown -R kc:kc /home/kc/.ssh && chmod 700 /home/kc/.ssh && chmod 600 /home/kc/.ssh/authorized_keysChange User root to User kc in the SSH config after that, and consider turning off password authentication in the server’s SSH daemon once you have confirmed the key login works from a second terminal. Adding the user to the docker group lets them run Docker commands without sudo; it also makes them effectively root for Docker, which is why the account still needs a strong key and nothing else on it.
Connect VS Code to the VPS
- Install the Remote - SSH extension from Microsoft in VS Code.
- Open the Command Palette (Cmd+Shift+P on a Mac).
- Run Remote-SSH: Connect to Host.
- Pick
hermes. VS Code reads it from the same SSH config file you edited. - A new window opens and installs the VS Code server on the VPS. The first time takes a minute. The status bar’s bottom-left corner shows SSH: hermes when it is connected.
- Open a folder with File, then Open Folder. Start with your home directory; you will add the agent’s paths once you know them.
- Open the integrated terminal (Ctrl+backtick). It is a shell on the VPS, not on your laptop.
That last point is the one that confuses people. In a remote window, everything is remote: the file tree, the terminal, the extensions that run on the server, the files you save. If you open a file in a local window and edit it, you have edited your laptop. If you want a file on the VPS, open it from the remote window. The green or blue indicator in the bottom-left corner is how you tell which kind of window you are in, and I check it before I save anything.
Find the Hermes container
Hostinger’s one-click install runs Hermes inside Docker, so the agent is not installed on the host the way a package would be. From the remote terminal:
docker psEach row is a running container. The columns that matter are IMAGE, which tells you what software it is; PORTS, which tells you what, if anything, is published to the network; STATUS, which should say Up; and NAMES, which is the handle you use in every other command. On my install the image was ghcr.io/hostinger/hvps-hermes-agent:latest, Hostinger’s packaging of the agent. Yours may differ as they update the template, so read the output rather than copying mine.
Logs are the first place to look when anything misbehaves, and the container name goes where I have written CONTAINER_NAME:
docker logs --tail 100 CONTAINER_NAME
docker logs -f CONTAINER_NAME # follow live; Ctrl+C to stopTo get a shell inside the container:
docker exec -it CONTAINER_NAME /bin/sh
# or, if the image has it:
docker exec -it CONTAINER_NAME /bin/bashInside, you are in the agent’s environment, with the hermes command on the path. Two things to find out while you are there: where its configuration lives, by default the .hermes directory in the container user’s home, and which paths are volumes. This matters more than anything else in this guide.
docker inspect CONTAINER_NAME --format '{{json .Mounts}}'Paths listed there survive a container restart or recreate. Anything you change elsewhere inside the container is gone the next time the template updates or the container is rebuilt. Put your configuration, skills and data on a mounted path, and if the config directory is not mounted, mount it before you spend an evening configuring the agent.
Configure Hermes to use Claude
Four things get confused here, so I will separate them. A Claude subscription (Pro, Max, Team) pays for the Claude apps and Claude Code. Anthropic API access is a separate, pay-per-token account on the developer platform with its own key. Hermes’s model provider configuration is where you tell the agent which of those to use. And Hostinger’s nexos.ai credits are a third option: a bundled gateway with prefilled credentials that routes to several models, including Claude, until the credits run out.
A Claude subscription does not give you Anthropic API credits. For Hermes, the predictable route is an Anthropic API key, billed per token to the developer platform account. Hermes can also reuse a Claude Code login through OAuth, and its own docs say that path needs a Max plan with extra-usage credits; users on other plans report running into usage errors. Hostinger’s nexos.ai credits are the simplest start if your plan included them, and they are finite.
Hermes keeps non-secret settings in ~/.hermes/config.yaml and secrets in ~/.hermes/.env, and it has an interactive command that writes both. Run it inside the container:
hermes model
# choose Anthropic, paste the API key when asked, pick a Claude modelOr set the pieces directly. The config command writes keys to the env file, so the secret never lands in the YAML:
hermes config set ANTHROPIC_API_KEY sk-ant-... # written to ~/.hermes/.env
hermes config edit # opens config.yaml
hermes config check # validates what you havemodel:
provider: anthropic
default: claude-sonnet-4-6 # pick a current model from the Anthropic docsThe Hermes configuration and provider documentation are the source of truth for the exact keys, and they change between releases, so read the version that matches your container. If Hostinger’s wizard already connected nexos.ai credits, the provider is set for you and you can leave it until you want your own key.
On credentials: the env file is the only place the key belongs. Never put it in config.yaml, in a skill, in a Git repository, or in a screenshot of your terminal; if you paste a terminal into a post, redact the line first, and if you ever expose a key, revoke it in the Anthropic console and make a new one. Keep the file permissions tight (chmod 600), keep the directory on a volume, and prefer a key created for the agent alone, so revoking it affects nothing else.
Using Hermes from VS Code
With the remote window open, the work is ordinary. Open ~/.hermes from the container’s mounted volume on the host, or exec into the container, and edit config.yaml and your skills in the editor. Run hermes commands in the integrated terminal through docker exec: chat with it, list and add cron jobs, start the gateway. Keep a second terminal following the container logs while you try things, because the log is where a bad config or a rejected key shows up first. Write the scripts and skills for an automation on the host, in a project folder under version control, and bind-mount or copy them into the container where the agent can load them.
One expectation to set straight: Remote-SSH gives you remote development access to the machine Hermes runs on. It does not make Hermes a coding assistant inside VS Code. Hermes is an agent you talk to through its CLI, its gateway and its scheduled jobs; the editor is how you administer it and build around it. My plan for the pipeline in the companion post is to develop it as a normal Python project in this remote workspace, test it from the terminal, and only then hand the scheduled run to Hermes.
Common problems
Permission denied (publickey,password). The server rejected both methods. Nine times out of ten the public key is not in the right file, or permissions are wrong: the home directory must not be group-writable, ~/.ssh must be 700, and authorized_keys must be 600, all owned by the user you log in as. Check which key the client offered with ssh -v hermes; if it is offering the wrong one, IdentitiesOnly yes with the right IdentityFile fixes it. If you pasted the key through the browser terminal, confirm it is one line with no breaks.
Wrong private key. If you have several keys, ssh-add -l on the laptop shows what the agent holds, and the SSH config pins the one to use. The public key on the server must match that private key, which ssh-keygen -y -f ~/.ssh/id_ed25519 will print for comparison.
VS Code connects, then hangs. Usually the VS Code server failed to install on the VPS, often from a full disk or a missing tar. Check free space with df -h and read the Remote-SSH output panel.
Container not running. docker ps -a shows exited containers too. docker logs CONTAINER_NAME says why. docker start CONTAINER_NAME brings it back, and if it exits again immediately, the log holds a configuration error.
hermes: command not found. You are on the host, and Hermes lives in the container. Prefix the command with docker exec -it CONTAINER_NAME, or exec into the container first.
Missing or rejected API key. hermes config check inside the container, then look at the env file’s permissions and spelling of the variable name. An HTTP 401 in the log is a bad or revoked key; an error mentioning extra usage means the OAuth route is hitting the subscription billing limit described above.
Changes vanish after an update. They were written to the container’s own filesystem, not a volume. Re-check docker inspect mounts and move your configuration and skills onto a mounted path. Note that hermes update refuses to run inside Docker by design; updates come from pulling a new image.
Exposed ports. If docker ps shows a port published as 0.0.0.0:PORT, it is reachable from the whole internet unless the VPS firewall blocks it. An agent with shell access and your API keys should not have a public port. Bind management interfaces to localhost and reach them through an SSH tunnel, and keep the gateway’s user allow-list on; Hermes’s own deployment guidance warns against allowing all users.
What I am building next
With the box reachable from my editor, the experiment can start. The application I want to build collects engineering leadership postings, searches for Director of Engineering, Head of Engineering, VP of Engineering and Senior Engineering Manager roles, filters by compensation, location and remote availability, compares each description against my background, scores the fit, identifies the gaps between my resume and the requirements, drafts a tailored application for my review, tracks applications and follow-ups, and runs on a schedule.
The split I have in mind: Hermes orchestrates. Its cron runs the search, its skills hold the criteria, its gateway sends the daily report, and its memory keeps track of what it has already shown me. Claude does the thinking in two places: as the model Hermes calls for the fit analysis and the gap list, and as the assistant I use in this remote workspace to write the pipeline itself. Of the list above, Hermes already provides scheduling, skills, messaging and persistent state out of the box. Everything else, the job-board clients, the normalizer, the filters, the database and the scoring prompts, is an integration I have to build, which is the point of the exercise. The design, and why deterministic filtering comes before any model call, is in the companion post.
Short answers
Does a Claude subscription give Hermes access to the Anthropic API?
No. A Claude Pro, Max or Team subscription pays for the Claude apps and Claude Code. The Anthropic API is a separate pay-per-token account with its own key, and that key is the predictable way to run Hermes on Claude. Hermes can reuse a Claude Code login through OAuth, but its docs say that path needs a Max plan with extra-usage credits.
Where does Hermes Agent store its configuration and API keys?
Non-secret settings live in ~/.hermes/config.yaml and secrets in ~/.hermes/.env, inside the container user’s home. The hermes model command writes both interactively, and hermes config set writes a key to the env file so it never lands in the YAML. Keep that directory on a Docker volume or the changes vanish when the container is recreated.
Why does “hermes: command not found” happen on a Hostinger VPS?
Because Hostinger’s one-click install runs Hermes inside a Docker container, so the command exists in the container, not on the host. Run it through docker exec -it CONTAINER_NAME hermes, or open a shell in the container first.
How do I fix “Permission denied (publickey,password)” when connecting to the VPS?
Check that your public key is in ~/.ssh/authorized_keys for the user you log in as, that ~/.ssh is mode 700 and authorized_keys is 600, and that the client is offering the right key, which ssh -v shows. Pin the key with IdentityFile and IdentitiesOnly yes in your SSH config. If SSH is unreachable, paste the key through the hPanel browser terminal.
A server you can reach is a server you can learn on
Keys instead of passwords, a non-root user, VS Code as the remote workspace, the container found and its volumes understood, and the model key in the one file it belongs in.
Secure the path first, then build the agent on it. The interesting part is everything around the model, and it starts with being able to get at the machine.
Next in the series: the first scheduled runs of the job-search agent, and what broke.