Security

Securing CodeHero.

Three levels of steps: Dev, Production and Fortress. Each level includes the one before it. They are steps for you, not switches in the panel: CodeHero gives the same protections at every level. The levels differ in what you do — who can reach the server, what data you put on it, and how you get back in.

For CodeHero 5.7.0.

Before any step that closes a port, turns on 2FA or changes SSH, read Do not lock yourself out.

Facts for every level

  • One owner per installation. Never share the panel’s login.
  • The panel can do everything on the server. It runs as the user claude, with sudo without a password, because it manages the server. Treat the panel’s password and 2FA like the server’s root password.
  • CodeHero installs no firewall and never changes one. You choose it: your cloud’s firewall or your router’s is the simple choice.
  • CodeHero never changes SSH. SSH is your own decision. Some clouds have no web console to get back in.
  • Use two domain names: one for the panel (for example panel.example.com), one for the previews (for example apps.example.com). A browser sends a site’s cookies to every port of the same name; with two names, a project page never receives your panel’s login. Set both in Settings → Domains.
  • Apply your firewall rules to IPv4 and to IPv6, if your server has IPv6.
  • The Production profile in Settings → Performance tunes speed and memory. It is not a security level.
LevelForDataThe panel from the internet
DevDevelopment and testsTest data onlyOnly your own IPs
ProductionYour customers’ live apps, a government appReal dataOnly through the CodeHero VPN
FortressThe least exposureReal dataOnly through the CodeHero VPN; the previews too

Level 1 — Dev

For development and tests, with test data. Do not put real customer data or real production passwords on a Dev server.

What you do

#StepWhereWhy
1Save the passwords the installer showed at its end in your password manager.The end of the install. Later: /etc/codehero/credentials.conf (root only).You need them outside the server.
2If the server came from a version before 5.7.0 and you still sign in with admin123, set your own password.The page «Set your password» opens by itself after that sign-in. It asks for the one-time setup code the upgrade showed in a box (console: sudo cat /etc/codehero/panel-setup-code).Older versions published that password. The code proves that it is you.
3Set the panel’s name and the previews’ name.Settings → DomainsThe panel’s login never reaches a project page.
4Get a real certificate for both names.Settings → Certificates → Import Let's EncryptThe browser checks that it talks to your server.
5Read Do not lock yourself out. Then turn on 2FA.Settings → Security → Enable 2FAA stolen password alone does not open the panel.
6Allow 9453 and 9454 only from your own IPs.Your cloud’s firewall, or your routerStrangers do not reach the sign-in page.
7Give each project a container.Project → Container Isolation (LXC) → Create ContainerA project’s code runs in its own hardened container.
8Press Apply security on each container made before 5.7.0.Project → Container tabThe upgrade does not harden old containers.
9Use test data in tickets, previews and screenshots.Your ticketsTicket text, code and screenshots go to the ticket’s AI provider.
10Put passwords and keys in the project’s Secrets panel.Project → 🔐 SecretsNever in a ticket’s text or in the chat.
11Install updates.Updates (the server, its containers, the AI tools) · Settings → 📦 Manual Update (CodeHero)Known faults get fixed.
12Make a backup and download it to another machine.Project → Backup & Restore → Backup History → DownloadA copy on the same server is lost with the server.

What CodeHero already does

ProtectionSince
Every new install generates the panel’s and the databases’ passwords. There is no default password.5.7.0
The upgrade replaces the old published database passwords with new random ones, only where they are still in use. A password you chose is never changed.5.7.0
A sign-in with the old panel password admin123 opens only «Set your password». It asks for a one-time setup code that only the upgrade’s output and the server’s root show (not asked after 2FA).5.7.0
A new panel password ends every other sign-in, its open terminals and «Remember this device». The upgrade to 5.7.0 ends every sign-in from before.5.7.0
Wrong passwords: 5 for one account from one address lock that account at that address for 30 minutes. 20 from one address lock that address. Other addresses are not locked.5.7.0
2FA with an authenticator app (TOTP). 5 wrong codes lock. The code page is valid for 5 minutes.2FA before 5.7.0; the limits 5.7.0
The panel answers only over HTTPS. With a domain and a real certificate the browser keeps to HTTPS (HSTS).5.7.0
nginx removes the panel’s login cookie from every request to a project. A change (POST, PUT, DELETE) is taken only from the panel’s own pages.5.7.0
phpMyAdmin opens only from a signed-in panel.before 5.7.0
The server’s MySQL answers only on the server itself and to its containers. An upgraded server got it unless a database account needed another host; then the panel shows a notice and you decide.before 5.7.0
A preview needs its project’s preview key, on every request — this server’s own requests too. nginx checks it for the path it really serves. A ticket’s tools send only their own project’s key.5.7.0
New containers are hardened: AppArmor without nesting, a seccomp filter, the dangerous capabilities dropped, /proc/sys and /sys read only, no device of the server.5.7.0
The AI’s file reads stay inside its project. Its commands are checked part by part. A search, copy or archive of the whole server or of every project’s folder is refused.5.7.0
A ticket’s browser and web tools reach only its own project’s preview and container, checked on every redirect. The browser trusts only this server’s preview certificate; every other certificate is checked normally.5.7.0
The containers of different projects cannot reach each other, unless a project allows another on its Container tab («Allow access from»). Each container can use only its own address: it cannot pretend to be another container or the server.5.7.0
The Logs menu’s diagnostic ZIP hides every secret value and key shape it knows ([hidden]). If a secret file could not be read, its manifest.json says "sanitized": "partial" and names the file.5.7.0
Your registered secrets are kept out of what the AI sees. A ticket cannot read the platform’s provider keys.before 5.7.0
Every CodeHero release is signed. 📦 Manual Update installs only a signed release, and never an older version.5.7.0
ZIP backups, snapshots and container images. A safety copy before every restore.before 5.7.0

Limits

  • The secrets filter cannot see a value shorter than 8 characters, or a value inside a screenshot.
  • The previews port (9867) is open to whoever your firewall lets in. The preview key protects each project.
What a reviewer will still ask
Can you sign in when the phone with the authenticator is lost?
There are no backup codes. Keep the 2FA «Manual entry code» offline, or add it to a second authenticator. The last resort is the console (see 2FA).
Is there a copy outside the server?
Only the copies you download. Backups to external storage (S3, SFTP) are planned, not built.
Who can reach the panel?
Whoever your firewall lets in. CodeHero does not filter the internet for you.
Can one project harm another?
Containers are hardened, and the containers of different projects cannot reach each other unless you allow it. They still share the server’s kernel. There are no memory or CPU limits per container yet. A project without a container runs its AI commands as claude on the server.

Level 2 — Production

For your customers’ live apps, and for a government app. A government app also needs the organisation’s own risk decision and acceptance; this list alone does not give that acceptance.

What you do

Everything of Dev, and:

#StepWhereWhy
1Write down which data each project holds and which AI providers may see it.Your own recordsYou know what leaves the server. A local LLM on your own device keeps the text in your network.
2Add two VPN devices: your laptop and a spare computer.Devices → + Device → connection CodeHero VPNOne lost laptop is not your only way in.
3Keep «What it reaches» on «The server only» for each device.Devices → the device → ManageA device that is broken into reaches only the server itself.
4Close 9453 and 9454 to the internet, in the safe order.Devices → Use the VPN to close your ports, then your cloud’s firewallOnly your VPN devices reach the panel and phpMyAdmin.
5Decide who must see the previews (9867).Your cloud’s firewallAllow your customers’ IPs where you can. Otherwise show only test data in previews.
6Check each container: «Applied», no nesting unless the project runs Docker, only the port forwards you need, and «Allow access from» ticked only for a project that must reach it.Project → Container tabNesting, open ports and allowed neighbours weaken the separation.
7Build on a staging copy with test data. Change the live project only after a review.A second projectThe live app is not the AI’s test bench.
8Set the live project’s default execution mode to Supervised.Projects → edit the project → Default Execution ModeThe AI asks you before every write.
9Keep encrypted copies of the backups off the server. Test a restore as a new project.Backup History → Download · Projects → 📦 ImportYou know the restore works and how long it takes.
10Turn on automatic security updates and get alerts.Updates → Automatic updates → Critical + security · Settings → TelegramFixes come in without waiting for you.
11Install the WAF. Start in Log only, then choose Block.Packages → WAF Security Setup · Settings → SecurityCommon attacks on the panel and the previews are refused.
12Keep a record of changes, restores and incidents outside the server.Your own recordsA reviewer asks for proof.

Supervised is an approval aid. It is not the project mode or the lock that come in 5.7.1.

What CodeHero already does

Everything of Dev, and:

ProtectionSince
The CodeHero VPN: one key per device. Revoke stops a device at once.5.5.0
«What it reaches» per VPN device, enforced by the server’s own VPN rules. «The server only» is the default, for existing devices too.5.7.0
Use the VPN to close your ports shows the steps and the hosts line. It changes no firewall.5.7.0
Apply security hardens an old container: a copy of its settings, a restart, the checks, the old settings back on any failure (a time-out or a panel restart too). Remove security works only from the panel, on a stopped container too. An AI ticket cannot edit a container’s LXC settings.5.7.0
«Allow access from»: CodeHero’s own rules on the containers’ bridge. A tick lets one project’s container open connections to another’s; nothing ticked = isolated.5.7.0
A container’s MySQL / MariaDB root logs in only from inside the container and from the panel.5.7.0
The Updates page reads Ubuntu’s security notices and installs by importance, by hand or every day.5.4.0
Updates refuse while an old unsigned CodeHero repository list is in a container. Apply security signs it.5.7.0
The WAF (ModSecurity with the OWASP Core Rule Set), if you install it.5.4.0
Imports and backups: names, links, owners and permissions from an archive are checked.5.7.0
An Approve on a ticket allows that exact call only. A ticket cannot give itself device or service tools. A ticket’s «confirmed» on a device counts only after your Approve of that call.5.7.0
Database passwords never appear on the server’s process list during installs, repairs, backups and restores.5.7.0
Device events (who did what, never the content), the ticket history, the update history.before 5.7.0
What a reviewer will still ask
Can the AI change the live app without your approval?
In 5.7.0: Supervised asks before every write; Semi-Autonomous asks for risky steps. A mode where the AI only reads, and a project lock, come in 5.7.1.
Does the server enforce what a VPN device reaches?
Yes. The server’s own VPN rules decide it. A device’s own WireGuard settings cannot widen it.
Is there an audit trail the owner cannot change?
No. The events, the histories and the logs are on the server, and the owner can change them. Send the logs to an outside service if you need that.
Do the backups survive a break-in on the server?
Only the copies you keep elsewhere, with other credentials.
Was the customer’s app tested for security?
A plan can include [SECURITY] tickets. That is not an independent assessment.
Who approves a change?
The owner alone. There is no second approver.
Where does the data go?
Ticket text, code and screenshots go to the ticket’s AI provider. You choose the providers per project. A local LLM keeps the text on your device.
Can one container reach another?
Only when the receiving project allows it («Allow access from»). CodeHero’s own rules on the containers’ bridge enforce it. A port you forward to a container is reachable from everywhere it is open, other containers included. On a kernel that cannot track replies on the bridge, an allowed pair talks both ways. A container cannot use another container’s address or the server’s.

Level 3 — Fortress

For the least exposure. It is still one server, with one owner who can do everything on it.

What Fortress cannot give

  • Separate administrators, or a second person who must approve a change.
  • A separate kernel per project. Containers share the server’s kernel.
  • Service when the server is gone. There is one server; recovery is a restore on a new server.
  • A certificate (ISO 27001, SOC 2) or a government approval. Those come from an auditor.

If a reviewer requires one of these, this installation alone cannot meet it. Use separate machines, for example a build server and a production server.

What you do

Everything of Production, and:

#StepWhereWhy
1Use one admin computer for the panel: disk encryption, its own browser profile, updates on.Your computerThe panel is as safe as the computer that opens it.
2Turn on strong 2FA on your cloud account, your DNS account and your email.Those providersThese accounts can go around the panel.
3Close 9453, 9454 and 9867 to the internet. Customers see previews through the VPN, or on another server.Your cloud’s firewallOnly the VPN and your published sites face the internet.
4Remove the devices you do not use. Choose «The whole VPN» only for a device that needs it.Devices → the device → Manage → Remove…A broken device reaches as little as possible.
5Never use the admin computer as a build device.DevicesA ticket can run commands on its device.
6When 5.7.1 comes: the live project in production mode, and locked.The project page (5.7.1)Every change becomes deliberate.
7Keep backup copies where the server cannot delete them: other credentials, versioning, or offline. Rehearse a rebuild on a new server.Your own storageA break-in cannot erase every copy.
8Watch from outside: your sites, the certificates’ expiry, and that the panel does not answer from the internet.An outside monitoring serviceThe alarm comes even when the server is down.
9Audit Ubuntu against the CIS benchmark on a copy of the server first.A clone of the serverA stricter setting can break LXC, sudo or the VPN.
10Order an independent security assessment. Keep its findings and fixes outside the server.An outside assessorProof for a reviewer.

What CodeHero already does

Everything of Dev and Production. There is no extra «Fortress mode» in the panel.

What a reviewer will still ask
Is the control plane apart from the code the AI writes?
No. One server; the panel has sudo; the containers share the kernel. Use separate machines if this is required.
Is the sign-in phishing-resistant (hardware keys)?
No. The panel has a password and TOTP; the VPN adds a device key. WebAuthn / FIDO2 is not built.
Are logs and backups immutable?
Not by CodeHero. Use outside storage with its own retention.
Can the release key be revoked?
The panel trusts one public key built into CodeHero. There is no revocation list. A release with a new key installs from the console.
Are third-party packages checked?
The release signature covers CodeHero’s own files. Ubuntu, PHP, Node.js and MySQL packages come from their own signed repositories. The AI tools come from their makers’ installers.
Is there high availability?
No. One server.

Do not lock yourself out

Before you close a port, turn on 2FA or change SSH, keep a way in that does not need the panel. The commands in this section are a last resort: they run in the server’s console.

Keep a way in that does not need the panel

  1. Find out how you reach the server’s console today: SSH from your IP, or your cloud’s web console.
  2. If your cloud has no web console, keep SSH open for your own IP. That is your only way back.
  3. Test that way before each change below.

The panel’s web terminal is behind the panel’s login. It does not help when you are locked out of the panel.

Close the panel’s ports behind the VPN — the safe order

  1. Save your cloud firewall’s current rules. A screenshot is enough.
  2. Set the two names and real certificates: Settings → Domains, Settings → Certificates.
  3. Give the VPN a public address of its own: vpn.example.com, or the server’s IP. Never the panel’s name: the hosts line sends the panel’s name into the VPN, and the VPN itself must be reachable from outside it.
  4. Open 51820/udp on your cloud’s firewall. In Devices, on the VPN card: Install VPN, tick VPN on, Save.
  5. Add your laptop: + Device → connection CodeHero VPN → Get the command (or Config file / QR). Keep «What it reaches: The server only».
  6. Add a spare computer the same way, as a device of its own.
  7. Press Use the VPN to close your ports. Copy the hosts line it shows into the hosts file of each of these computers — Windows: C:\Windows\System32\drivers\etc\hosts (Notepad as administrator); macOS and Linux: /etc/hosts (with sudo). Example with the default VPN network: 10.77.0.1 panel.example.com apps.example.com.
  8. With the VPN on, open https://panel.example.com:9453. Sign in again with your password and 2FA. The browser must show no certificate warning. Open phpMyAdmin too.
  9. Do step 8 on the spare computer, from another network (for example a phone’s hotspot).
  10. Only now close 9453 and 9454 on your cloud’s firewall. Close 9867 only if nobody outside the VPN must see the previews. Close a forwarded port only if only VPN devices use it.
  11. Keep 51820/udp open. Keep 80 and 443 open if you publish sites or use Let's Encrypt.
  12. Test from outside with the VPN off: the panel must not open. Turn the VPN on: the panel must open.
  13. If something fails, put the saved rules back on your cloud’s firewall.

While 9453 is closed, a new device cannot join with Get the command: the command needs the panel before the VPN. Give it a Config file / QR, or open 9453 for its IP while it joins.

The hosts line

  • It makes the panel’s name lead to the server’s VPN address (10.77.0.1 with the default network). The certificate still matches the name.
  • If you take the line out, the computer uses the public address again. That works only while the port is open.
  • If you change the VPN network or move CodeHero to another server, change the line on every computer.
  • The panel’s name works only over HTTPS (HSTS). Through the line it stays HTTPS.

2FA

  • There are no backup codes.
  • When you turn on 2FA, the panel shows a QR code and a «Manual entry code». Save that code offline — in a password manager on another device, or on paper in a safe place — or scan the QR code with a second authenticator at the same time.
  • Test a new sign-in in a private browser window before you close the old one.
  • Wrong passwords lock that account at that address for 30 minutes. Wait, or sign in from another address.
  • A lost phone, last resort, in the console: sudo /opt/codehero/scripts/manage-2fa.sh disable, sign in with your password, then Settings → Security → Enable 2FA (a new QR code).
  • A lock, last resort: sudo /opt/codehero/scripts/manage-2fa.sh unlock. It also clears the running panel’s locks.

Passwords

  • /etc/codehero/credentials.conf holds the generated passwords. Only root can read it.
  • Change the panel’s password in Settings → Security → Change Admin Password.
  • A new panel password signs out every other browser and device, and ends «Remember this device». The browser that changed it stays signed in.
  • A lost panel password, last resort: sudo /opt/codehero/scripts/change-passwords.sh. It accepts only 8 to 128 characters: letters, digits and . _ @ % + = : , / ! ^ * - (no spaces or quotes). A panel password has at most 72 characters.
  • The setup code of «Set your password» (an upgraded server that still had admin123): the upgrade shows it in a box. Lost it: sudo cat /etc/codehero/panel-setup-code. It works once. With 2FA on, it is not asked.
  • If an upgrade stopped half-way while it changed the database passwords, /etc/codehero/db-rotation.journal (root only) keeps both passwords. Run the same upgrade again: it finishes or undoes the change. Nothing to do by hand.
  • Keep a copy of your passwords outside the server.

The release key

  • CodeHero signs every release with its own private key. You keep no key: the panel checks the signature with a public key built into CodeHero.
  • If 📦 Manual Update refuses a ZIP, do not force it. Download it again and compare its SHA-256 with the release notes.
  • 📦 Manual Update never installs an older version. A downgrade runs only from the console: sudo ./upgrade.sh --allow-downgrade. Never go below 5.7.0 with hardened containers: they need its settings files to start.
  • If CodeHero ever announces a new signing key, that release installs from the console, after you checked its SHA-256.

DNS and certificates

  • Let's Encrypt renews over port 80. If you close 80, the certificates stop renewing.
  • HSTS: after a browser opened the panel’s name with a real certificate, it uses only HTTPS for that name, on every port, for one year. A container service forwarded in plain HTTP on that name will not open in that browser: forward it with TLS, or give it another name.
  • If the certificate expires or does not match, the browser refuses that name. Renew the certificate; meanwhile open the panel by an IP address (https://<the server’s IP>:9453, or through the VPN https://10.77.0.1:9453). The browser warns about the certificate; HSTS does not apply to an IP address.
  • Keep your DNS account safe: whoever controls your DNS can send your names to another server.

SSH is your decision

  • CodeHero never changes SSH and never adds a firewall rule.
  • If your cloud has no web console and you close SSH to the internet, a stopped VPN leaves you with no way in. Keep your own IP allowed.
  • If you change SSH yourself (a new port, keys only), keep the old session open, test a new login from a second window, and only then close the old way.

Other traps

TrapThe safe order
Revoking or removing the only VPN deviceTest the spare device first.
A new VPN key for a deviceThe new config replaces the old one at once. Have the spare device ready.
Moving the VPN to another serverDevices → Export / Import first; keep its passphrase elsewhere. Test the new address before you close the old way.
Apply security on a containerMake a backup. Press it when a minute without that site suits you, not while one of its tickets runs. It goes back by itself if the container does not start or a service does not come back.
A container that does not start with the hardeningRemove security works on the stopped container. If it does not start without the hardening either, the hardening comes back: look for another cause.
Two projects that share a container service (a database, a cache)After the upgrade to 5.7.0 the containers are isolated. Tick the client project in «Allow access from» on the serving project’s Container tab.
A script or cron job that calls a preview on this serverFrom 5.7.0 it needs the project’s preview key: the header X-CodeHero-Preview-Key, or ?key=. Or call the production domain. Test it after the upgrade.
Sharing the Logs menu’s diagnostic ZIPIf its manifest.json says "sanitized": "partial", check the ZIP first: the named file’s values may not be hidden.
A backup without the secretsZIP backups leave out .secrets/ by default. Keep the secrets safe yourself, or tick Include the secrets for a move.
Disk encryption with a password at bootA server with no console cannot be unlocked from far away. Check your cloud’s way first.

Ports by level

PortWhatDevProductionFortress
22/tcpSSHYour IPsYour IPs. The VPN only after it is tested and you have a console.Your decision, with a tested way back in
9453/tcpThe CodeHero panelYour IPsOnly through the VPNOnly through the VPN
9454/tcpphpMyAdmin, behind the panel’s loginYour IPsOnly through the VPNOnly through the VPN
9867/tcpThe project previewsWhoever must see themYour customers’ IPs where you can; else test data onlyOnly through the VPN
80/tcp, 443/tcpYour published sites and Let's EncryptOnly if you publish sitesOpen if you publish sitesOpen if you publish sites
51820/udpThe CodeHero VPNOnly if the VPN is onOpenOpen
A port you forward to a containerThat container’s serviceAs the service needsOnly what the service needs; through the VPN if only devices use itThrough the VPN, or closed
Every other portMySQL 3306, the panel’s application 5000, the containers, the databases of the Services tab …ClosedClosedClosed
  • MySQL and the panel’s application already listen only on the server itself. Closing them is a second layer.
  • A VPN device always reaches the server’s own ports (9453, 9454, 9867, the forwarded ports, SSH), whatever «What it reaches» says.
  • A port you forward to a container is reachable from everywhere your firewall lets in, other containers included. «Allow access from» decides only the traffic between containers on the bridge.
  • Before you close a port, keep a way in (above).

Questions people ask

All the articles
Does CodeHero change my firewall or SSH?

No. CodeHero installs no firewall, never adds a firewall rule and never changes SSH. You choose the firewall — your cloud’s or your router’s is the simple choice — and SSH is your own decision.

Can I sign in if I lose the phone with the authenticator?

There are no backup codes. Keep the 2FA «Manual entry code» offline, or add it to a second authenticator when you turn 2FA on. The last resort is a command in the server’s console.

Do my passwords and keys reach the AI company?

Not the ones you store as secrets (eight characters or longer): your application uses them, but their values are not sent to the AI service. A password typed into a chat message or shown in a screenshot cannot be recognised — store every password as a secret. Read the article

What happens to the knowledge about my project?

It is built up and kept inside your installation: decisions, rules, changes and their reasons, next to the code. A new person or a new AI continues from there — the knowledge does not leave with them. Read the article

Why does CodeHero host the applications too?

Because building and running belong together. The application runs where it was built, with its domain, secure connection, backups and recovery — and every later change returns to the same factory. No separate hosting panel to learn. Read the article