code-server 4.145.2
Overview
code-server runs VS Code on a server and serves it to your browser. You get the full editor, an integrated terminal, source control and extensions from any machine with a browser, while the code, the builds and the tools stay on your EC2 instance.
This guide covers the code-server 4.145.2 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud developer and API tools listing on AWS Marketplace. You choose it as the software version when you subscribe and launch.
What you get: code-server running as a private, single-user service.
- HTTPS from the first boot. nginx serves code-server on port 443 with a certificate generated on your instance's first boot. Port 80 only redirects to HTTPS, and a request for any name other than your instance's own gets no answer.
- No default password. The image contains no password, no certificate and no host name. First boot generates them and writes them to
/var/lib/sac/data/code-server-credentials.txt(root only). code-server's configuration keeps only an argon2id hash of the password, never the password itself. - The current editor. code-server 4.145.2 bundles VS Code (Code - OSS) 1.145.2 and Node.js 24.22.1. The bundled
undiciHTTP library is raised to 7.30.2, which fixes every published high-severity advisory for the copy code-server ships. - Rate-limited sign-in. Sign-in attempts are limited per client address, on top of code-server's own limiter. nginx always replaces the
X-Forwarded-Forheader with the address it accepted the connection from, so a client cannot spoof its address. The session cookie is alwaysHttpOnlyandSecure. - A sandboxed editor. code-server runs as its own account,
coder, with no login shell, nosudoand no capabilities. It can write only to its own home directory. Nothing the editor runs, including its terminal and extensions, can reach the EC2 instance metadata service. - Extensions from Open VSX, the open registry code-server uses. Telemetry and update checks are off.
- A patched base. Ubuntu 24.04 LTS is fully patched at build time, with unattended security upgrades switched on.
Image contents: the official code-server 4.145.2 release package (code-server_4.145.2_amd64.deb, checked at build time against the SHA-256 digest GitHub publishes for it), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The build record, code-server's MIT licence and the licence of the GitHub Copilot CLI bundled with VS Code's built-in Copilot extension are in /usr/share/doc/sac-code-server/.
Default user: ubuntu; Architecture: x86_64; Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 443 (the editor), TCP 80 (redirects to HTTPS) and TCP 22 (SSH). The editor gives whoever signs in a terminal on the instance, so open 443 and 22 only to your own networks (for example
<your-mgmt-cidr>) and avoid exposing them to the whole internet. - A modern browser (Chrome, Edge, Firefox or Safari).
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick code-server 4.145.2 on Ubuntu 24.04 as the software version, choose your Region, then choose Launch through EC2.
Select m5.large, your key pair, your subnet and the security group above. VS Code and its language servers use a lot of memory, but a t3.medium is enough for light editing.
Your workspace, settings and extensions all live on the root volume, in /var/lib/code-server. The image's root volume is 16 GiB. Increase it at launch (for example to 50 GiB) if you will clone large repositories or install many tool chains. There is no separate data volume to attach.
To launch with the AWS CLI instead, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":50,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=code-server}]'Attach an Elastic IP to keep the instance's address, and therefore its name and certificate, the same across stops and starts.
Connect to your instance
Connect over SSH as the ubuntu user, the default user for code-server 4.145.2 on Ubuntu 24.04:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot takes under a minute. It sets the server's name, generates the certificate and the password, and only then starts code-server and nginx. Confirm that everything is running:
systemctl is-active code-server-firstboot code-server-egress-guard code-server nginx \
&& sudo test -f /var/lib/sac/data/code-server-firstboot.done && echo FIRSTBOOT_DONEactive active active active FIRSTBOOT_DONEOnly SSH and nginx listen on the network. code-server listens on the loopback address 127.0.0.1:8080 behind nginx, and its processes show up as MainThread:
sudo ss -lntp | awk 'NR>1 && $4 !~ /^127\.0\.0\.5[34]/ {print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u | tee /dev/stderr \
| awk '$1 !~ /^127\./ {sub(/.*:/, "", $1); print $1}' | sort -un | xargs | grep -qx '22 80 443' && echo "network listeners: 22 80 443"0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:8080 users:(("MainThread")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx")) network listeners: 22 80 443Get your address and password
Run sudo cat /var/lib/sac/data/code-server-credentials.txt to see your editor's address and password. The file is root-only and holds these settings, all generated for this instance:
sudo sed -n 's/^\(CODE_SERVER_[A-Z0-9_]*\)=.*/\1/p' /var/lib/sac/data/code-server-credentials.txt | tee /dev/stderr \
| grep -qx CODE_SERVER_PASSWORD && echo "credentials present"CODE_SERVER_URL CODE_SERVER_HOST CODE_SERVER_PASSWORD CODE_SERVER_TLS_CERT CODE_SERVER_TLS_SHA256_FINGERPRINT credentials presentCODE_SERVER_URL is https://<your instance's public DNS name>/ and CODE_SERVER_PASSWORD is the password. Settings that are not secret can be shown on their own:
sudo grep -E '^CODE_SERVER_(URL|TLS_SHA256_FINGERPRINT)=' /var/lib/sac/data/code-server-credentials.txt \
| tee /dev/stderr | grep -q '^CODE_SERVER_URL=https://'CODE_SERVER_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/ CODE_SERVER_TLS_SHA256_FINGERPRINT=49:47:FC:...:32code-server's configuration stores the password only as an argon2id hash, and only root and the coder account can read it:
sudo grep -c -F "hashed-password: '\$argon2id\$v=19\$" /etc/code-server/config.yaml | grep -qx 1 \
&& !
sudo grep -qE '^[[:space:]]*password:' /etc/code-server/config.yaml \
&& sudo stat -c '%U:%G %a' /etc/code-server/config.yaml | tee /dev/stderr | grep -qx 'root:coder 640' && echo "hash only"root:coder 640 hash onlySign in from your browser
Open CODE_SERVER_URL in your browser. The certificate is self-signed and was generated on your instance, so the browser warns about it the first time.
Before you accept it, verify that it is your instance's certificate. The SHA-256 fingerprint in the browser's certificate viewer must match CODE_SERVER_TLS_SHA256_FINGERPRINT. Alternatively, copy the certificate to your machine and compare it there:
scp -i <your-key.pem> ubuntu@<public-ip>:/etc/ssl/code-server/code-server.crt ./code-server.crt openssl x509 -in code-server.crt -noout -fingerprint -sha256To remove the warning permanently, add code-server.crt to your machine's trusted certificates (Keychain Access on macOS, certmgr on Windows). You can also use your own domain and a public certificate (Step 10).
On the code-server sign-in page, enter CODE_SERVER_PASSWORD.
The editor opens on the empty workspace folder, /var/lib/code-server/workspace.
Your session lasts until you select Sign out in the menu at the top left or the password changes. Use File > Open Folder to open another folder under /var/lib/code-server, or select Clone Git Repository on the welcome page to clone a repository.
Use the terminal
Open a terminal with Terminal > New Terminal (or Ctrl+). It is a bash shell on the instance, running as thecoderaccount in your workspace. Everything the editor starts (the terminal, tasks, debuggers, language servers and extensions) runs ascoder, inside the code-server service, and can reach the internet (to install packages, fetch dependencies or push to git) but not the EC2 instance metadata service. The screenshot below is that check, run in the editor's own terminal: the metadata service gets no answer (000) and a public site answers (200`):
You can run the same check over SSH. The metadata service is refused for the coder account and still answers for ubuntu (your SSH account), and the extension registry answers for coder:
{
sudo -u coder curl -s -m 5 -o /dev/null -w 'coder -> metadata: %{http_code}\n' -X PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 60'
sudo -u coder curl -s -m 20 -o /dev/null -w 'coder -> open-vsx.org: %{http_code}\n' 'https://open-vsx.org/api/-/search?size=1' curl -s -m 5 -o /dev/null -w 'ubuntu -> metadata: %{http_code}\n' -X PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' } | tee /dev/stderr | xargs | grep -qx 'coder -> metadata: 000 coder -> open-vsx.org: 200 ubuntu -> metadata: 200' && echo "metadata blocked for the editor"coder -> metadata: 000 coder -> open-vsx.org: 200 ubuntu -> metadata: 200 metadata blocked for the editorTwo things enforce this: the code-server service's own network filter (systemd IPAddressDeny) and an nftables rule that rejects the metadata addresses for the coder account anywhere on the instance. So a command, extension or dependency you run in the editor cannot read the instance's IAM role credentials. If your code needs AWS credentials, configure them for the coder account yourself (for example with aws configure in the editor's terminal); give them only the permissions that code needs.
The editor's terminal can reach your VPC and other private addresses, like any shell on the instance: code-server itself makes no outbound requests on anyone else's behalf (its port proxy in Step 9 reaches only this instance), so the image does not fence private networks.
The coder account has no sudo. To install system packages, use your SSH session as ubuntu (sudo apt-get install ...); tools that install per user (pip install --user, npm with a prefix, rustup, nvm) work in the editor's terminal.
Install extensions
Open the Extensions view (the blocks icon on the left). Extensions come from Open VSX, the open extension registry that code-server uses. It carries most popular extensions, including Python, Go, Rust, Java, Prettier, ESLint and GitLens.
Extensions install into /var/lib/code-server/.local/share/code-server/extensions.
Some Microsoft extensions are published only on the Microsoft Marketplace, whose terms allow them only in Microsoft's own VS Code products. If you need one of them, download its .vsix from the publisher and install it with Extensions > ... > Install from VSIX.
Run the self-test
The image ships a self-test. It verifies that:
- the services and listening ports are as expected
- a request without a session gets the sign-in page and no editor connection
- a wrong password is refused
- the password in the credentials file signs in over HTTPS with this instance's certificate, with an
HttpOnlyandSecuresession cookie - the session opens the editor with Open VSX as its gallery
- the editor's WebSocket connection is accepted from the editor's own page and refused from any other site
Run it:
sudo code-server-selftest | tail -n 1 | tee /dev/stderr | grep -q '^CODE_SERVER_SELFTEST_OK 'CODE_SERVER_SELFTEST_OK wrong password refused, the note's password logs in over https://ec2-203-0-113-10.compute-1.amazonaws.com/ (HttpOnly+Secure session), workbench + same-origin WebSocket 101, cross-origin WebSocket 403, no session = login pagecode-server's own sign-in limiter allows two failed sign-ins a minute. If you have just mistyped the password, wait a minute between runs.
Preview web apps through the port proxy
Start a web app in the editor's terminal, for example python3 -m http.server 3000. Then open it in your browser at one of two routes:
https://<your instance's name>/proxy/3000/: the app sees paths without the/proxy/3000prefix.https://<your instance's name>/absproxy/3000/: for apps that expect their full path.
The proxy reaches only this instance, and both routes require you to be signed in. Without a session they answer 401 or redirect to the sign-in page. The session cookie is never passed on to the app over plain HTTP.
A page served through the proxy comes from the same site as the editor. Run only apps you trust there, and do not open untrusted pages through it. The browser treats such a page as part of the editor's site, so it could act on your signed-in session. The session cookie itself stays HttpOnly, so the page cannot read it.
Change the password or use your own domain
To give the editor a new random password, run the command below. The old password and every session signed in with it stop working at once. Then read the new CODE_SERVER_PASSWORD with sudo cat /var/lib/sac/data/code-server-credentials.txt:
sudo code-server-rotate-passwordThe new password is hashed with argon2id. Only the hash goes into /etc/code-server/config.yaml, and the password never appears on a command line or in a log.
To use your own domain, point a DNS name at the instance (an Elastic IP keeps the address stable), then set it as the server's name. This generates a new certificate for that name and pins nginx to it:
sudo code-server-set-site code.example.comTo use a certificate from a public CA instead, for example one issued by certbot with a DNS challenge, run code-server-set-site first. Then replace /etc/ssl/code-server/code-server.crt (full chain) and /etc/ssl/code-server/code-server.key (mode 0600), and run sudo systemctl reload nginx. Browsers then show no warning.
What the front door refuses
nginx answers only for the server's own names and passes requests to code-server on loopback:
H="$(sudo sed -n 's/^CODE_SERVER_HOST=//p' /var/lib/sac/data/code-server-credentials.txt)" { curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/code-server/code-server.crt --resolve "$H:443:127.0.0.1" "https://$H/healthz" curl -s -o /dev/null -w '%{http_code}\n' -k -H 'Host: someone-else.example' https://127.0.0.1/ curl -s -o /dev/null -w '%{http_code}\n' --resolve "$H:80:127.0.0.1" "http://$H/" curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/code-server/code-server.crt --resolve "$H:443:127.0.0.1" -X POST -H 'Origin: https://evil.example' "https://$H/healthz" } | xargs | tee /dev/stderr | grep -qx '200 000 301 403' && echo "front door OK"200 000 301 403 front door OK- Sign-in limits. Requests to
/loginare limited to 6 a minute per client address (bursts of 10), on top of code-server's own limiter; the rest of the editor to 50 requests a second (bursts of 1000), with at most 128 connections per address. Over the limit, nginx answers429. The limit applies to every spelling of the path (//login,/LOGIN,/%6Cogin,/login;xand so on), because nginx matches it after normalising the path. - X-Forwarded-For. nginx replaces any
X-Forwarded-Forheader with the address it accepted the connection from and blanksX-Real-IP,Forwardedand similar headers, so a client cannot change the address the limits and code-server's failed-sign-in log use. If you put a load balancer in front of the instance, every client then shares the load balancer's address for the limits. - Cross-site requests. A request that changes something (anything but
GET,HEADorOPTIONS) and every editor WebSocket connection must come from the editor's own page: with another site'sOriginheader nginx answers403, and code-server refuses a cross-site WebSocket as well. - Sizes and methods. Uploads are limited to 256 MiB and the sign-in form to 4 KiB;
TRACEand other unusual methods get405. - Headers. Responses carry
Strict-Transport-Security,X-Content-Type-Options: nosniff,X-Frame-Options: SAMEORIGIN, aContent-Security-Policyofframe-ancestors 'self',Referrer-Policy: same-originand aPermissions-Policythat turns off the camera, microphone, location, payment and USB APIs, and nginx does not advertise its version.
What is logged: nginx's access log (/var/log/nginx/access.log) records the client address, request path and status, without query strings. nginx's error log records only start-up problems, not refused requests, so a password in a rejected request never reaches the disk. code-server logs failed sign-ins (with the client address nginx saw, never the password) to the journal: journalctl -u code-server.
Back up and restore
Everything the editor keeps, including your workspace, settings, extensions and terminal history, is in /var/lib/code-server. Take an EBS snapshot of the root volume, or copy the directory off the instance:
sudo tar -C /var/lib/code-server -czf code-server-$(date +%F).tar.gz .To restore into a new instance of this image, stop code-server, unpack the archive into /var/lib/code-server as coder, and start code-server again: sudo systemctl stop code-server && sudo -u coder tar -C /var/lib/code-server -xzf - < code-server-<date>.tar.gz && sudo systemctl start code-server.
Keep your code in git as well. A repository pushed to a remote is the best backup.
Security notes and the build record
The certificate generated at first boot is a server certificate only: it cannot sign other certificates.
openssl x509 -in /etc/ssl/code-server/code-server.crt -noout -ext basicConstraints,keyUsage,extendedKeyUsage | tee /dev/stderr | grep -q 'CA:FALSE'X509v3 Basic Constraints: critical CA:FALSE X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server AuthenticationThe package is the 4.145.2 release, checked against GitHub's published digest at build time, and the editor's account has no login shell and no sudo:
dpkg-query -W -f='${Package} ${Version}\n' code-server | tee /dev/stderr | grep -qx 'code-server 4.145.2' sed -n '1,3p' /usr/share/doc/sac-code-server/BUILD-INFO.txt getent passwd coder | cut -d: -f1,6,7 | tee /dev/stderr | grep -qx 'coder:/var/lib/code-server:/usr/sbin/nologin' \
&& sudo -l -U coder 2>&1 | grep -q 'not allowed to run sudo' && echo "coder: no login shell, no sudo"code-server 4.145.2 code-server 4.145.2 (github.com/coder/code-server release v4.145.2, 2026-11-07), MIT (code-server-LICENSE) code-server_4.145.2_amd64.deb sha256 7eddbdeaab34380bde3ac3bbadce58fe2f5722c4877f331ea593ae797c2517e1 (= GitHub's published asset digest) bundles Code - OSS 1.145.2 (commit 302bc77436721f5a474e06d1fe34cf8f86195d5e) and Node.js v24.22.1 coder:/var/lib/code-server:/usr/sbin/nologin coder: no login shell, no sudocode-server runs as coder with no capabilities and NoNewPrivileges, sees the rest of the system read-only (ProtectSystem=strict, writable only under /var/lib/code-server), has private /tmp and /dev, and cannot see other users' processes. It cannot read the credentials file or the TLS key. Before every start, code-server-config-check refuses a configuration that turns authentication off, stores a plaintext password, listens anywhere but loopback, or sets proxy-domain, trusted-origins, skip-auth-preflight, cert or link, and refuses PASSWORD, HASHED_PASSWORD or a Microsoft extension gallery in the service's environment. A refused configuration stops code-server once and for all instead of retrying it in a loop: fix the file, then run sudo systemctl restart code-server. A crash, by contrast, restarts it automatically. Some sandbox settings are deliberately relaxed because an IDE needs them: JIT compilation (no MemoryDenyWriteExecute), any system call (no SystemCallFilter, so debuggers and compilers work), a full /proc for its own processes, and netlink sockets.
Do not run the code-server command yourself as ubuntu or root: with no --config it writes a new configuration with a generated password into that account's home. Manage the service with systemctl and the code-server-* helpers instead.
code-server is MIT licensed; its licence is in /usr/share/doc/sac-code-server/code-server-LICENSE. VS Code's built-in Copilot extension (off until you sign in to GitHub) bundles the GitHub Copilot CLI, redistributed unmodified under its own licence, which is in the same directory. nginx comes from Ubuntu's main archive.
Keep it up to date
Ubuntu security updates, including nginx, install automatically. To apply all pending updates now, run:
sudo apt-get update && sudo apt-get upgrade -yNew code-server releases arrive as new versions of the AWS Marketplace listing. Launch the new version, restore /var/lib/code-server into it (Step 12), and run sudo code-server-set-site with your domain if you use one.
code-server is installed from its release package, not from an apt repository, so apt-get upgrade does not change it.
Support
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
Other versions on this listing are covered in the developer and API tools guide.
Deploy on AWS
Launch code-server 4.145.2 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com