From c67844d3566986be0dcc56a7b5a1a78b84d3f9b0 Mon Sep 17 00:00:00 2001 From: jhalek90 Date: Sun, 28 Jul 2019 10:35:52 -0500 Subject: [PATCH 01/11] update README.md Removed linked to coder.com/enterprise,(404) replaced with link to coder.com --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99d24b30..c03acdef 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Development guides are coming soon. ## Enterprise -Visit [our enterprise page](https://coder.com/enterprise) for more information about our enterprise offering. +Visit [our website](https://coder.com/) for more information about our enterprise offering. ## Commercialization From bdd9d65146a1c6b48be9eae97cb893d8f1461d32 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Fri, 2 Aug 2019 14:08:33 +1000 Subject: [PATCH 02/11] Add DigitalOcean button to README --- README.md | 2 ++ doc/assets/do-new-droplet-btn.svg | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 doc/assets/do-new-droplet-btn.svg diff --git a/README.md b/README.md index c03acdef..830c9d50 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ docker run -it -p 127.0.0.1:8443:8443 -v "${PWD}:/home/coder/project" codercom/c ## Getting Started +[![Create a Droplet](./doc/assets/do-new-droplet-btn.svg)](https://marketplace.digitalocean.com/apps/code-server?action=deploy) + ### Run over SSH Use [sshcode](https://github.com/codercom/sshcode) for a simple setup. diff --git a/doc/assets/do-new-droplet-btn.svg b/doc/assets/do-new-droplet-btn.svg new file mode 100644 index 00000000..72808c9b --- /dev/null +++ b/doc/assets/do-new-droplet-btn.svg @@ -0,0 +1,23 @@ + + + + do-btn-blue-ghost + Created with Sketch. + + + + + + + + + + + + + Create a Droplet + + + + + \ No newline at end of file From 7d35144952882f0080af0e675eeaafcc1634e5cd Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Tue, 6 Aug 2019 12:39:39 +1000 Subject: [PATCH 03/11] Add GitHub fonts to DigitalOcean button --- doc/assets/do-new-droplet-btn.svg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/assets/do-new-droplet-btn.svg b/doc/assets/do-new-droplet-btn.svg index 72808c9b..ecbb3f24 100644 --- a/doc/assets/do-new-droplet-btn.svg +++ b/doc/assets/do-new-droplet-btn.svg @@ -14,10 +14,11 @@ - + + Create a Droplet - \ No newline at end of file + From 3667b16cba851c7aef46f41b2f5462ca707a811f Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 7 Aug 2019 18:18:01 -0500 Subject: [PATCH 04/11] Add link to v2 preview --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 830c9d50..eaf4c5bc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -# code-server +# code-server [!["Open Issues"](https://img.shields.io/github/issues-raw/cdr/code-server.svg)](https://github.com/cdr/code-server/issues) [!["Latest Release"](https://img.shields.io/github/release/cdr/code-server.svg)](https://github.com/cdr/code-server/releases/latest) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cdr/code-server/blob/master/LICENSE) [![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/zxSwN8Z) -[!["Open Issues"](https://img.shields.io/github/issues-raw/cdr/code-server.svg)](https://github.com/cdr/code-server/issues) -[!["Latest Release"](https://img.shields.io/github/release/cdr/code-server.svg)](https://github.com/cdr/code-server/releases/latest) -[![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cdr/code-server/blob/master/LICENSE) -[![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/zxSwN8Z) +**code-server v2 is almost out!** +[Get the preview here](https://github.com/cdr/code-server/releases/tag/2.preview.1-vsc1.36.1). +(Linux builds only at the moment.) `code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser. From 8c39e085f487deb479260acb018724377ee894e8 Mon Sep 17 00:00:00 2001 From: Asher Date: Thu, 8 Aug 2019 13:40:01 -0500 Subject: [PATCH 05/11] Use generic releases link for v2 message --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eaf4c5bc..94cc9dea 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # code-server [!["Open Issues"](https://img.shields.io/github/issues-raw/cdr/code-server.svg)](https://github.com/cdr/code-server/issues) [!["Latest Release"](https://img.shields.io/github/release/cdr/code-server.svg)](https://github.com/cdr/code-server/releases/latest) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cdr/code-server/blob/master/LICENSE) [![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/zxSwN8Z) **code-server v2 is almost out!** -[Get the preview here](https://github.com/cdr/code-server/releases/tag/2.preview.1-vsc1.36.1). +[Get the preview here](https://github.com/cdr/code-server/releases). (Linux builds only at the moment.) `code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser. From 7caef7f49c30841fddf3a1c008a9b98b3c498c60 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Sat, 17 Aug 2019 05:46:37 +1000 Subject: [PATCH 06/11] Rewrite and update documentation --- doc/admin/install/aws.md | 162 ++++++++----- doc/admin/install/digitalocean.md | 151 +++++++++--- doc/admin/install/google_cloud.md | 133 +++++++---- doc/assets/aws_ubuntu.png | Bin 44981 -> 49223 bytes doc/assets/digitalocean_ubuntu.png | Bin 0 -> 43101 bytes doc/security/code-server.fail2ban.conf | 4 - doc/security/fail2ban.md | 6 +- doc/security/index.md | 8 + doc/security/ssl-certbot.md | 63 +++++ doc/security/ssl.md | 49 ++-- doc/self-hosted/cros-install.md | 56 +++-- doc/self-hosted/index.md | 317 +++++++++++++++++++------ 12 files changed, 703 insertions(+), 246 deletions(-) create mode 100644 doc/assets/digitalocean_ubuntu.png create mode 100644 doc/security/index.md create mode 100644 doc/security/ssl-certbot.md diff --git a/doc/admin/install/aws.md b/doc/admin/install/aws.md index b9a92cb9..b38078fa 100644 --- a/doc/admin/install/aws.md +++ b/doc/admin/install/aws.md @@ -1,66 +1,116 @@ -# Deploy on AWS +# Deploy on AWS EC2 -This tutorial shows you how to deploy `code-server` on an EC2 AWS instance. +This tutorial shows you how to deploy `code-server` on an AWS EC2 instance. -If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. +If you're just starting out, we recommend +[installing code-server locally](self-hosted-docs). It takes only a few minutes +and lets you try out all of the features locally. + +If you get stuck or need help at anytime, [file an issue](create-issue), +[tweet (@coderhq)](twitter-coderhq) or [email](email-coder). + +[self-hosted-docs]: ../../self-hosted/index.md +[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+AWS+quickstart+guide +[twitter-coderhq]: https://twitter.com/coderhq +[email-coder]: mailto:support@coder.com?subject=AWS%20quickstart%20guide --- -## Deploy to EC2 +### Creating an Instance using the AWS Launch Wizard -### Use the AWS wizard +1. Click **Launch Instance** from your [EC2 dashboard](ec2-home). +2. Select the "Ubuntu Server 18.04 LTS (HVM), SSD Volume Type" AMI.. +3. Select an appropriate instance size (we recommend t2.medium/large, depending + on team size and number of repositories/languages enabled), then **Next: + Configure Instance Details**. +4. Select **Next: ...** until you get to the **Configure Security Group** page, + then add a **Custom TCP Rule** rule with port range set to `8443` and source + set to "Anywhere". + > Rules with source of 0.0.0.0/0 allow all IP addresses to access your + > instance. We recommend setting [security group rules](ec2-sg-docs) to allow + > access from known IP addresses only. +5. Click **Launch**. +6. You will be prompted to create a keypair. + > A key pair consists of a public key that AWS stores, and a private key file + > that you store. For Linux AMIs, the private key file allows you to + > securely SSH into your instance. +7. From the dropdown choose "create a new pair", give the key pair a name. +8. Click **Download Key Pair**. This is necessary before you proceed. A `.pem` + file will be downloaded. make sure you store is in a safe location because it + can't be retrieved once we move on. +9. Finally, click **Launch Instances**. + +[ec2-home]: https://console.aws.amazon.com/ec2/v2/home +[ec2-sg-docs]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console -- Click **Launch Instance** from your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home). -- Select the Ubuntu Server 18.04 LTS (HVM), SSD Volume Type -- Select an appropriate instance size (we recommend t2.medium/large, depending on team size and number of repositories/languages enabled), then **Next: Configure Instance Details** -- Select **Next: ...** until you get to the **Configure Security Group** page, then add a **Custom TCP Rule** rule with port range set to `8443` and source set to "Anywhere" - > Rules with source of 0.0.0.0/0 allow all IP addresses to access your instance. We recommend setting [security group rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console) to allow access from known IP addresses only. -- Click **Launch** -- You will be prompted to create a key pair - > A key pair consists of a public key that AWS stores, and a private key file that you store. Together, they allow you to connect to your instance securely. For Windows AMIs, the private key file is required to obtain the password used to log into your instance. For Linux AMIs, the private key file allows you to securely SSH into your instance. -- From the dropdown choose "create a new pair", give the key pair a name -- Click **Download Key Pair** - > This is necessary before you proceed. A `.pem` file will be downloaded. make sure you store is in a safe location because it can't be retrieved once we move on. -- Finally, click **Launch Instances** --- -### SSH Into EC2 Instance -- First head to your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home) and choose instances from the left panel -- In the description of your EC2 instance copy the public DNS (iPv4) address using the copy to clipboard button -- Open a terminal on your computer and use the following command to SSH into your EC2 instance - ``` - ssh -i "path/to/your/keypair.pem" ubuntu@(paste the public DNS here) - ``` - >example: `ssh -i "/Users/John/Downloads/TestInstance.pem" ubuntu@ec2-3-45-678-910.compute-1.amazonaws.co` -- You should see a prompt for your EC2 instance like so -- At this point it is time to download the `code-server` binary. We will of course want the linux version. -- Find the latest Linux release from this URL: - ``` - https://github.com/cdr/code-server/releases/latest - ``` -- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page): - ``` - wget https://github.com/cdr/code-server/releases/download/{version}/code-server{version}-linux-x64.tar.gz - ``` -- Extract the downloaded tar.gz file with this command, for example: - ``` - tar -xvzf code-server{version}-linux-x64.tar.gz - ``` -- Navigate to extracted directory with this command: - ``` - cd code-server{version}-linux-x64 - ``` -- If you run into any permission errors, make the binary executable by running: - ``` - chmod +x code-server - ``` - > To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md) -- Finally, run - ``` - ./code-server - ``` -- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your AWS instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**. - > For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed +### Installing code-server onto an AWS Instance - --- -> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide). +1. First head to your [EC2 dashboard](ec2-home) and choose **Instances** on the + left sidebar. +2. Select the instance you just created, and in the description tab at the + bottom of the screen copy the **Public DNS (IPv4)** address using the copy to + clipboard button. +3. Open a terminal on your computer and use the following command to SSH into + your EC2 instance. If you're using Windows, you can use [PuTTY](putty-guide) + to open an SSH connection. + ``` + ssh -i "path/to/your/keypair.pem" ubuntu@(paste the public DNS here) + ``` + > For example: `ssh -i "/Users/John/Downloads/TestInstance.pem" ubuntu@ec2-3-45-678-910.compute-1.amazonaws.co` +4. If you get a warning about an unknown server key fingerprint, type "yes" to + approve the remote host. +5. You should see a prompt for your EC2 instance like so: + +6. At this point it is time to download the `code-server` binary. We will, of + course, want the linux version. Find the latest code-server release from the + [GitHub releases](code-server-latest) page. +7. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the + SSH terminal, run the following command: + ``` + wget (paste the URL here) + ``` +8. Extract the downloaded file with the following command: + ``` + tar -xvzf code-server*.tar.gz + ``` +9. Navigate to extracted directory with this command: + ``` + cd code-server*/ + ``` +10. Ensure the code-server binary is executable with the following command: + ``` + chmod +x code-server + ``` +11. Finally, to start code-server run this command: + ``` + ./code-server + ``` +12. code-server will start up, and the password will be printed in the output. + Make sure to copy the password for the next step. +13. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` + is your AWS instance's public IP address). You will be greeted with a page + similar to the following screenshot. code-server is using a self-signed SSL + certificate for easy setup. In Chrome/Chromium, click **Advanced** then + click **proceed anyway**. In Firefox, click **Advanced**, then **Add + Exception**, then finally **Confirm Security Exception**. + + +[putty-guide]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/putty.html +[code-server-latest]: https://github.com/cdr/code-server/releases/latest + +--- + +### Post Installation Steps + +To ensure the connection between you and your server is encrypted, view our +guides on [securing your setup](security-guide). + +For instructions on how to keep the server running after you end your SSH +session please checkout [how to use systemd](systemd-guide). systemd will run +code-server for you in the background as a service and restart it for you if it +crashes. + +[security-guide]: ../../security/index.md +[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ diff --git a/doc/admin/install/digitalocean.md b/doc/admin/install/digitalocean.md index 292679e1..0d758a7c 100644 --- a/doc/admin/install/digitalocean.md +++ b/doc/admin/install/digitalocean.md @@ -2,47 +2,124 @@ This tutorial shows you how to deploy `code-server` to a single node running on DigitalOcean. -If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. +If you're just starting out, we recommend +[installing code-server locally](self-hosted-docs). It takes only a few minutes +and lets you try out all of the features locally. + +If you get stuck or need help at anytime, [file an issue](create-issue), +[tweet (@coderhq)](twitter-coderhq) or [email](email-coder). + +[self-hosted-docs]: ../../self-hosted/index.md +[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+DigitalOcean+quickstart+guide +[twitter-coderhq]: https://twitter.com/coderhq +[email-coder]: mailto:support@coder.com?subject=DigitalOcean%20quickstart%20guide --- -## Use the "Create Droplets" wizard +### Recommended: Using the Marketplace -[Open your DigitalOcean dashboard](https://cloud.digitalocean.com/droplets/new) to create a new droplet +[![Create a Droplet](../../assets/do-new-droplet-btn.svg)](https://marketplace.digitalocean.com/apps/code-server?action=deploy) -- **Choose an image -** Select the **Distributions** tab and then choose Ubuntu -- **Choose a size -** We recommend at least 4GB RAM and 2 CPU, more depending on team size and number of repositories/languages enabled. -- Launch your instance -- Open a terminal on your computer and SSH into your instance - > example: ssh root@203.0.113.0 -- Once in the SSH session, visit code-server [releases page](https://github.com/cdr/code-server/releases/) and copy the link to the download for the latest linux release -- Find the latest Linux release from this URL: - ``` - https://github.com/cdr/code-server/releases/latest - ``` -- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page): - ``` - wget https://github.com/cdr/code-server/releases/download/{version}/code-server{version}-linux-x64.tar.gz - ``` -- Extract the downloaded tar.gz file with this command, for example: - ``` - tar -xvzf code-server{version}-linux-x64.tar.gz - ``` -- Navigate to extracted directory with this command: - ``` - cd code-server{version}-linux-x64 - ``` -- If you run into any permission errors when attempting to run the binary: - ``` - chmod +x code-server - ``` - > To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md) -- Finally start the code-server - ``` - ./code-server - ``` - > For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed -- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your Digital Ocean instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**. +1. On the **Create Droplets** page, choose a plan for your new code-server + instance. We recommend picking an instance with at least 4 GB of RAM and 2 + CPU cores, or more depending on team size and number of + repositories/languages enabled. +2. Optionally enable backups and add block storage. +3. Choose the closest available region to your physical location to reduce + latency. +4. Select an SSH key that you already have in your account, or click **New SSH + Key** and follow the tutorial on how to make your own SSH key. +5. Click **Create Droplet**, then click on the droplet to expand it. +6. While you're waiting for the droplet to deploy, copy the **IPv4** address. +7. Once the droplet is ready, connect using SSH with the key you specified or + created earlier. You should be greeted with information on how to access your + code-server instance and how to view/change the password. + > You can SSH into your server using PuTTY or by running + > `ssh root@(paste ipv4 address here)`. +8. In the droplet's terminal, run `cat /etc/code-server/pass` to view the + code-server password. +9. Open your browser and visit `https://$public_ip` (where `$public_ip` + is your Droplet's public IP address). You will be greeted with a page similar + to the following screenshot. code-server is using a self-signed SSL + certificate for easy setup. In Chrome/Chromium, click **Advanced** then + click **proceed anyway**. In Firefox, click **Advanced**, then **Add + Exception**, then finally **Confirm Security Exception**. + --- -> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide). + +### Using the "Create Droplets" Wizard + +If you used the Marketplace to set up code-server, you don't need to follow this +section. + +[Open your DigitalOcean dashboard](create-droplet) to create a new droplet. + +1. **Choose an image:** Select the **Distributions** tab and then choose + **Ubuntu 18.04.3 (LTS) x64**. +2. **Choose a size:** We recommend at least 4GB RAM and 2 CPU, or more depending + on team size and number of repositories/languages enabled. +3. Select an SSH key that you already have in your account, or click **New SSH + Key** and follow the tutorial on how to make your own SSH key. +4. Click **Create Droplet**, then click on the droplet to expand it. +5. While you're waiting for the droplet to deploy, copy the **IPv4** address. +6. Once the droplet is ready, connect using SSH with the key you specified or + created earlier. You should be greeted with information on how to access your + code-server instance and how to view/change the password. + > You can SSH into your server using PuTTY or by running + > `ssh root@(paste ipv4 address here)`. +7. If you get a warning about an unknown server key fingerprint, type "yes" to + approve the remote host. +8. You should see a prompt for your Droplet like so: + +9. At this point it is time to download the `code-server` binary. We will, of + course, want the linux version. Find the latest code-server release from the + [GitHub releases](code-server-latest) page. +10. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the + SSH terminal, run the following command: + ``` + wget (paste the URL here) + ``` +11. Extract the downloaded file with the following command: + ``` + tar -xvzf code-server*.tar.gz + ``` +12. Navigate to extracted directory with this command: + ``` + cd code-server*/ + ``` +13. Ensure the code-server binary is executable with the following command: + ``` + chmod +x code-server + ``` +14. Finally, to start code-server run this command: + ``` + ./code-server + ``` +12. code-server will start up, and the password will be printed in the output. + Make sure to copy the password for the next step. +13. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` + is your Droplet's public IP address). You will be greeted with a page + similar to the following screenshot. code-server is using a self-signed SSL + certificate for easy setup. In Chrome/Chromium, click **Advanced** then + click **proceed anyway**. In Firefox, click **Advanced**, then **Add + Exception**, then finally **Confirm Security Exception**. + + +[create-droplet]: https://cloud.digitalocean.com/droplets/new +[code-server-latest]: https://github.com/cdr/code-server/releases/latest + +--- + +### Post Installation Steps + +To ensure the connection between you and your server is encrypted, view our +guides on [securing your setup](security-guide). + +For instructions on how to keep the server running after you end your SSH +session please checkout [how to use systemd](systemd-guide). systemd will run +code-server for you in the background as a service and restart it for you if it +crashes. (Note: this doesn't apply for users of the Marketplace Droplet image.) + +[security-guide]: ../../security/index.md +[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ diff --git a/doc/admin/install/google_cloud.md b/doc/admin/install/google_cloud.md index bf228e1f..2fa3caa7 100644 --- a/doc/admin/install/google_cloud.md +++ b/doc/admin/install/google_cloud.md @@ -1,66 +1,101 @@ -# Deploy on Google Cloud +# Deploy on Google Cloud Platform -This tutorial shows you how to deploy `code-server` to a single node running on Google Cloud. +This tutorial shows you how to deploy `code-server` to a single node running on +Google Cloud Platform. -If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. +If you're just starting out, we recommend +[installing code-server locally](self-hosted-docs). It takes only a few minutes +and lets you try out all of the features locally. + +If you get stuck or need help at anytime, [file an issue](create-issue), +[tweet (@coderhq)](twitter-coderhq) or [email](email-coder). + +[self-hosted-docs]: ../../self-hosted/index.md +[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+Google+Cloud+quickstart+guide +[twitter-coderhq]: https://twitter.com/coderhq +[email-coder]: mailto:support@coder.com?subject=Google%20Cloud%20quickstart%20guide --- ## Deploy to Google Cloud VM -> Pre-requisite: Please [set up Google Cloud SDK](https://cloud.google.com/sdk/docs/) on your local machine -- [Open your Google Cloud console](https://console.cloud.google.com/compute/instances) to create a new VM instance and click **Create Instance** -- Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, more depending on team size and number of repositories/languages enabled) -- Choose Ubuntu 16.04 LTS as your boot disk -- Expand the "Management, security, disks, networking, sole tenancy" section, go to the "Networking" tab, then under network tags add "code-server" -- Create your VM, and **take note** of its public IP address. -- Visit "VPC network" in the console and go to "Firewall rules". Create a new firewall rule called "http-8443". Under "Target tags" add "code-server", and under "Protocols and ports" tick "Specified protocols and ports" and "tcp". Beside "tcp", add "8443", then create the rule. -- Copy the link to download the latest Linux binary from our [releases page](https://github.com/cdr/code-server/releases) +> Pre-requisite: Please [set up Google Cloud SDK](gcloud-sdk) on your local +> machine. + +[Open your Google Cloud console](create-instance) to create a new VM instance. + +1. Click **Create Instance**. +2. Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, or + more depending on team size and number of repositories/languages enabled). +3. Choose **Ubuntu 16.04 LTS** as your boot disk. +4. Expand the **Management, security, disks, networking, sole tenancy** section, + go to the **Networking** tab, then under network tags add `code-server`. +5. Create your VM, and **take note** of its public IP address. +6. Visit **VPC networks** in the console and go to **Firewall rules**. Create a + new firewall rule called `http-8443`. Under **Target tags**, add + `code-server`, and under **Protocols and ports** tick **Specified protocols and + ports** and **tcp**. Beside **tcp**, add `8443`, then create the rule. + +[gcloud-sdk]: https://cloud.google.com/sdk/docs/ +[create-instance]: https://console.cloud.google.com/compute/instances --- ## Final Steps -- SSH into your Google Cloud VM -``` -gcloud compute ssh --zone [region] [instance name] -``` + -- Find the latest Linux release from this URL: -``` -https://github.com/cdr/code-server/releases/latest -``` +1. SSH into your Google Cloud VM: + ``` + gcloud compute ssh --zone [region] [instance name] + ``` +2. At this point it is time to download the `code-server` binary. We will, of + course, want the linux version. Find the latest code-server release from the + [GitHub releases](code-server-latest) page. +3. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the + SSH terminal, run the following command: + ``` + wget (paste the URL here) + ``` +4. Extract the downloaded file with the following command: + ``` + tar -xvzf code-server*.tar.gz + ``` +5. Navigate to extracted directory with this command: + ``` + cd code-server*/ + ``` +6. Ensure the code-server binary is executable with the following command: + ``` + chmod +x code-server + ``` +7. Finally, to start code-server run this command: + ``` + ./code-server + ``` +8. code-server will start up, and the password will be printed in the output. + Make sure to copy the password for the next step. +9. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` + is your Instance's public IP address). You will be greeted with a page + similar to the following screenshot. code-server is using a self-signed SSL + certificate for easy setup. In Chrome/Chromium, click **Advanced** then + click **proceed anyway**. In Firefox, click **Advanced**, then **Add + Exception**, then finally **Confirm Security Exception**. + -- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page): -``` -wget https://github.com/cdr/code-server/releases/download/{version}/code-server{version}-linux-x64.tar.gz -``` - -- Extract the downloaded tar.gz file with this command, for example: -``` -tar -xvzf code-server{version}-linux-x64.tar.gz -``` - -- Navigate to extracted directory with this command: -``` -cd code-server{version}-linux-x64 -``` - -- Make the binary executable if you run into any errors regarding permission: -``` -chmod +x code-server -``` - -> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md) - -- Start the code-server - ``` - ./code-server - ``` -- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your Compute Engine instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**. - -> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed +[code-server-latest]: https://github.com/cdr/code-server/releases/latest --- -> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide). +### Post Installation Steps + +To ensure the connection between you and your server is encrypted, view our +guides on [securing your setup](security-guide). + +For instructions on how to keep the server running after you end your SSH +session please checkout [how to use systemd](systemd-guide). systemd will run +code-server for you in the background as a service and restart it for you if it +crashes. + +[security-guide]: ../../security/index.md +[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ diff --git a/doc/assets/aws_ubuntu.png b/doc/assets/aws_ubuntu.png index 2a7e76c84d71612074e700842fc55c9530cbf62e..0b7f16fa756453f23b92872d4e70dafc3e695379 100644 GIT binary patch literal 49223 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 SniomZORr>AUX)0`_Wd7bOjvUO literal 44981 zcmc$`c{tW-8#iudnlf$HQW9B05(!zO?Af;>l#=Xa-?CL?4M~zMgKP;S$regCl6{XX zQOHhYU*6BHnR%M({r&Yjj`x0!<9R$4?)&;)*Li-n^YT+wmfg0Qb~6bH$+nYnQtBim zzsZu2{Bo4^SNzF-A@>OU&j#ZYN+(E2vVylPU-%vWf8RwpbtMv#tE?m>*Sttb7V$^d zK9P{vA0{CgK2Jg-e4m7b#wxl%O%#8z(Lg~~ie!!WpFfL|L-8+3PD-87bm|!Gn$y>4 z>mixkb9f)AwD;ECe`v_;V!cI5n#8Gb+<|G|d2(O%UpD>z+sj`l$u9|#s~$IOmdPTQ z*&=uRvBdR{%Sv@*$u*&tHk1iDr{C2r^^@6%E_GI|II&6pg5Uaoe=VCgnDE7ve6q5! z*}P@_wSD`l$J82RiHeFo)p%Z1#P7M7_xqD4PdUsb~CfH4%XHS@eWjuj*cr_5qVX+DpOPITU(Fbp)xhUxTWHE zk{4P@@$pQ;!X2+(NpkL#m696mDbeTLDIzHNX;4vFd3BvW z$#H)2LYB70rAs$GIA3$iojloVlTSu3`d3!gf^2~obMW1})LGiqAEx;Ho;`b38YMev9Zf3PEt}*N=i!R<|Aa{%eU{|eK@URkR`~;S^e7j>~hJi4I}&a?>}(h zz*?xf4pZyJOP6*~QmU(~+l+PO;D>c|=zNGH36xPdc``L4qu68OoQ@8ywA#SHfUDTr z(nQI`r%xs(CcXgyueKydYW2f%Uv%XmO;Mii!T7u?@mjuEFYmK#!-Gy`v zcZrMj7wI! z12Urbe5K;Eva%ebCa{u0fq|EdjXm@x{mF%`-jl3Ol?Bi^j(1j8RW&IuSD%e<8fs~2 z2@MS;jcaW^t@Njcni`LQKpVdH$S=;$<~@A)wsvQGyYu<;@B3$}78e(XhD`JI=qV}V zS5!#j?%bhd_7Qj}W0U`UNkvUf&HG4ZM#iw$XDoZ}l`dL3Iw{hX`47SPdU$m7X?Av@ z?O<)4_!?)394#&FmG0-Jq7SR8t6iu1%3k@9nVXqe4Q6L&8yg!hEiLV#r4<$y{`~p# zWa&v3O4sG`EwXw_V{d-@?Khg8J9Xaa)YQ~`5eeQa;-JV8*75G$TGyWR163EUDl?B< zd9zW5lenAaROTjnWJwQDZ`Rd)_b%5`fSPm&U^RnnVOm=CMG5;$25v{x3#s6NZIqz9y)sTSxSl=3+0ZFG+y4` z>eOY1N2aHztE#G09*FLyrhx(QFFifI$zX2%;?eQ(a<#KgPEHOE&*WJ8rWcHijJ9r+ z+(&NW9z59Jf78n=ub^P_&C+Yvu04K?Rlge&a^cDq2-foCaOhm-c`}c>%#Dd7pOif=V7Y+{(A3bNe z&r3O0?6QeO@xs6!x{9SW)1G2C?;{7p-aL3fKSoVPMrLU_(cG-*rD|`VgQdkQFtBDq zSNFq*51Y2r{gs_PJu}1iq*q#2wyv&@OqA|?cDvIpd~8&(P^wT03JM1Y2SwJVmX;md zor{ZCrKG%!dVSMU_tv~Ne6q0M?BU^IFc=dPb5r7iwY4>V2WvGrEYd<;Z zTZ?CL7b5fMk_P#njG_-IOF0!4?t=#p9ynB4S;?ar z7kAQKc-79@nuncTjw6i83%?orC@z{1A;8PKg_Ja}qcL8SLwvmCGR`g8u3fw4Pp&q- zcy--zqC5RSSdYir%A2$uw1KDf^f<$-mNqSVEDk02_FmZNd4c_rg0eFGo;`bZ?;aW- zcSk)udD73*Q_{s{X|#H@{{8!zfT7jZ)fX>btop3r7~9&~$|rtaU0G64P+(?emZ5D7 z2@hurtt6LdYHB(Xp~xDV)ox)R$w1rERqWM%!L; z&VT&)R#iVo*c%bYaYbb%Wktp6ni^>t8OlN_&MPLLry{(|%A{*f%r&QKkTPCBuBxrA zefsphJ9iAQxj0>xX2%39yR~(6J}47*&8`{$FqyYmJ}3Ro$8a;h%dlafAr|l zjpbh%7#NuM__?3=`hC-;58Y;^zJqnK+=mW@-MxD_Lh-|%b2zz{B`Zm8i)>t6+Zi== zbRLyh;rL+Ta{l`3@cu{mnD5@c6+9qnnlin0V?uVet$~4oz5OZM!286#AZqjRb!VrZ zv2n7GkF1;9%5vv&2(#?gZB2y!!^e{2>;DGx*=26rH1-8{--GDryH))e z85!QS*ZT(tgM))rl$B>^XEM^${iNc{%F56`FIEH{2zygdAiQalPfN=wZyHIa5K))e z$7yM4$;rvNxoxU-+mvk3Q(IeGThg@fXAIkpJ;}`#a0}-_E2wsHa#B=L5%*Z73!)~u zmia2jyzS_@l5^+IxzBtG(Mfk-o}VHRywcJ}(!#W|{o6Y`JGanq?ep^Y_xDxX8>1Xv z)xY^B(}4qiWd>7D&wYJ;tE&~mWWldlU3NAI_bm(LzCL?m&WFMMxY^97hJ=ui5H^(u&z+|F z=BGXo)PXQic-q?L&~MJ3J&V1VDR9om%L^ZS?#q|_!oodd+h@nS-ZeF$$4rj4XX|^c zzXFJsJB^jBS0(Lg9XRsgGth=UktX2s|**Oy?&D}4y?nq{T)7@R1oNRpM%J$eR zZP7i$BO_6YHDs?RayDR z_MO-h$4{LK(@F2{>MGmxSFUA`gS~y?!-wy!WILF~K7D%I-X0>yLP)7?YNBGa%jthq zYr4yeJcx1@3t3RGxV$i3nOfP}$Syu6GWgXb?L7g!r3V*H$uSuJM3@D*C| zW540a%D5tzxksmlGcvgF=Sf5OZAXtDr7WDGNhlZ|Hgly`l$RHF7=4Rf`0*o4R&#=E z@Ll;!=H>^B_kEceYRbvU398-hRgXQayjg|GtH7necG@OT@AhUgvcV}Qx1u7moPxjp zn#`27r5PG7+E8EL=f1Kn zUiF_FpTzNMQ%gq_qx7?6h)Ap98^)J4WMzG37dXbYRjXS2$IHvhcNe=wg@-4*sb{C9 zDa5H78X1{Ue%VvH#{8zHrfj!nVIgYK1Ri)~WNGgB0!-f`hT$?-y5*+ZHrUJUq9k=<-8Grk0G&Yn$+R2{-1oc#D;M;!|*#zLW>< z5q$LO#04v>zvL6mEG$sxrAVEfuc}d(8D+Pa<*+_#5{>X>;9+#|)9#!}*{*-Hx$_-x zCaSbNXG=$if3wNOiwSvoc>FXU0wd%KR!MVaLgnW;yqCF_ZdCl51?~H zd+I9yLIap4uqSjX=+JHY&<()N_>1gj^@pqHyhXzyst#;Q?}98ev4oJWu$Fvbae8l z)llPpKyicGxmqknx_si|r@_u&NZx1r`}!UyJ+%DfxEgh_OTnLiUVC}|xyzg~Yv{uK z{QTnLXD88`li|S4={>pk6=pI7}hmyWa#3>dk(ii)}2kBQlf^28_TTgTZaSv-*M^W}@Zl4f$#egkXC zR~HWNQe?Hgbg3VZ7C5V{?9$rm3Vx}iq@*G%@4kKKuU=goYDyN&j*ab!;5FtWyZgT4 z9$Lrq=g;qihMwYR0kI+ngxX7d1#)YiExO9j!SM!*Uy=um;_CVwK&!A&MC>?i{&2D; zhmVhs=bE9pxx%gC*@>Rm+qd5j4jP+Z3}7zHHm;+6G>uR9rsWh}$VK#~x>#|2ZSD6q z`6xxgYB8Rko_buer1r!O)70I)ie=IW)evT@+iFiQYme2K_p@9t?{D77bA%PUuPlP3 z>AU4DnwY$Tx&f9wv2pAfMH=L+8H5`~~e+d=_yudx3evgFY&#Hz73dWiDFMsooN6n*< zz+VEc({P{F)6oGv8XX=6VQSVpmv1+8M?UdRrD5dSXEg4*0|WSPl#7Y3LM{Bu@o_Oe zzL_fS5>W19*9CR1@a*q@<)oM@OfpAHse)nb?T#JtC0NQ|PF&kDPoD z)6SXCpYK%li?1!)0t=yxpDT79nwW@dzgI94(%8&iU6uYLsL_~*euitz~;M^hJ%ml)aI2d1oj+>cwAVx z)Rw4UvNSGIlV$5-T$rD~d(FhsQvC4Yzn(pF=zp^#Uym!iifpg&!&JJu?Ag#w!ewVT zTbq(q(9H4jSojhi7stqKxqyw|f_Bgo8=sJ1y%;CyLoTtfurOZ%)C;x*q*fKqC4P0r z#M-(6MB??yKD2g}Rg;q64;?sQ3KHRDxJ&%*p)mQnXd%z$Vew~AACGo*b%7F6X-z-< zG*e#gy=oijE$lH+z1vF_{Ilz(uz$R-f}&mxdLFQBb8D-Pwl-)resEF}>j&ADIWBCd zz|18Vfy0tzB`dSKUbklhuZYr<_57L^AuJjExS+7GuC|tg+8>WO?qytCras8gJJ1|P zue!RH=H~ZfgsP^Ip|?%CxmWlF1jx2-MNQaqRe{O+PE2&P`|?ypM8xh?O<_L4r+@u* zZO(D!taqiM_cHhMC*BTRebpbXJa?O$?JEngdWe>?7qy*_`#|8WThsw%^HTzBY{{ji zrKma`kvcU8H?sTt_m;n(yL(zw^F1|cdGoB@#Y zN$nw4BH63fEo;vgcgQ|fWYyr@nfvV7QGWjZfz`D`VirdW6BBRN4Vs&gl97q8tt>4`0Z1*PKw(JXyK++*S~b%(hfzNmfg% z4WxCCz?IJD&e?Hsy#zlhnPH+NVf~>zDsWqf9QEG4>CSB<*z9En*1Eb;P*xNb(c`V~ z?pN8O+>Y+pv12~0bTMsVWv&MT$*}mENy_wmdbUB9Ham4+p1y~lUs~nh^g#}e$twmx zN0fec62E*tXJjWN#-1EvFL3EM=AD4PI|9nCY+75B4uc*ioXHB9Ake%swl1?oGg#mu zu)A1nu)b~JE2-xR&VY`i*_Cy502_DZSct!$US4tsC7TcHQIyrrM&WS!X5}uQt-K2MO!I#U;#CoL?-MUR` z7cKNE;g-fBI{-6tb90SHE!^(!U;L8mc_nsoxbeX;m(J}45%W9;H+ljNp)jLb+0A@X zQz`%%@$so}DOvn8I}#7fqv_zywLY^*B1l{Q)4pwvCLq+Y*X=0lb|0C9q2-MEeSEYv zU0r7fC252Us~vmXv=&SF$lCUFIaw9scwYDbB}?+X_EM1pMri7UN+sjTJyx1{=i7hC`T_?yY#=`UXr zn}*7#>rMD*182GS0}| zW!tuuxy$y%kJeMVF6m}~GSLheStrHZ@JZ zUtNJ9;QA=YI=>U&f$ik_;1F@`=l$C|-kvLTNPqThCu1`d+xnNQA?`lO&K4IQ%(__dP(8J%XvKJZ7GIM~FfuZ-&Nj_la8E&L2N-L8 zb{c}l3gP2NL%a(h4Ms{oe0TTd;w4Qt$N-Y0dj+lDPg^h&m!NHL%Q2_P^R~8Bj8D;e zMk|c5`DEg61Fhhvp+eR;Mge0{OY=ljgAqYm3}sXC_VMYh{z0favTN)0-=7 zSs)a%u#n!AxPF|RmR1K!$Nl?qYIhS8FX`y$n3@iyY9s?bvipPY@7R3vmtTH4bLI?F z2s<_W_)u>?!?}|u8IMzy9Rv~G ztd%}>)z>%uLp6ja$aCc}%f2Z=6(3B8A2tmU+$pId6qAnco1C4+LEPyl z%BLXKW7XNvknr+lTv3smgOP)YmDOUI9gxxa^ZTULAd6kRcoC!@ZI+BdjPt;OlL`tN z9AQD*gYuq*_4mV2_^DpSN1L9Pr_B{UM>exI)1-nuy>+AK&y=Wv{(fkpUiC9GXc>@4 zEsjRXB>bS(Fc~PL47Ill@$h676gC!Ynjjr(Q_JSO5?R@RF-8F8npShmCb~I;shk{v)AV96Xcz#Hh(*W?u6{97 zPzcD(oN!41PJT{z6xgp!^4Ya{Vk6Tz!2t2Z*C!t1J&qUgw%a}pPanBda5QkE=W3> zCTSdY!<+TjpMUP#=$Vz5CnzT7&NQ;Y=apJov$u`TnKN1KqeM35#izE{T8hwW?S3?> ztGW4ZWaOf?T8u*sbQt3DS?6Wv<=sa;Q&qi2j&4saeTbVIsxa&h$n0KT8+&}tCxqPNeor}(mk1;ImhcuggleKW%n3eZ&Wqpq_`8T~*k+Txuds1!^7Y1ohGs%# z65!OF$$w;+-7d5Kp+iDaluKe6s9T1p1t?o0j>IO(+7k{%={ znVXts{q@&z(z1#Qm;sk9EvLWH8Q6GuD01m{&Q`d&Km}{{qIh)n)Y-E!Nkq!*MP6J@ zvwL^y=`?sUzCwP)r!AwiW|9=_d*AofUOL?kn>M9sa?lZ+TwG{&?69}91J1Z5w!4gm z;DN#pG>@P%s(G6o%jK_+zgI{@A1bU zf6xqbEw3(32nh*EOG}dy6=Jle4;8@^FpqL_8ir9PhfjjSlYu!$WaE9{}4Er4KGM7!u_vC@#(rGAj9wP5*kG zgi#aB@b>M=`G$*Lw^?u1SElZ50o2IL&sU?CrV9yaU0GhPjTV}2P*J#lgvo$uyQ3i8 z_VB8(N<(nwsi~>i*;yDuP~+*gCl?j%RT0dJ#UBMTh(CyoMsH}b^SduM%4QwNr`FXv zp^IM7)TBYxf?a`azEgrzx!QEml@gRns`HMYE~&MGw>~W@aj_~m4rv^N$MRHVD4Y1| z{6!a+!lI%gw7B~EdhU|t#&_?QKKCo+>jh*J2nLT;#6WzzIAAb)LDk74m%8noE zz0n7|4-NjZfpWC(!~rnb$Azl0YShF%LqodZoya>p69$3Uq+7(@6N4ua(m-)jqM^S2 z{N>AI{X<{uMu*aMb5Rn}ZUzPi`MEc=4h@<%3BJ2Y*`9~Lo6a9x+Q`<$wSj8VNLLV$u-1UcHZd?-w0Qp8`d3-`<5&@mc{YH z3AowTi!f1P+>DHjq}81=|Mk}&*pMlo4s-W&>=`nWgcj`nJFo^oevu`%AXPjaw{KrzJDXOfzlI)rKl!EJst zvPLWlkOkU?pOm_q8XA3usd92GQNw~5HM?ba>wendyUgU+1~&!zzQ+5SIS~=`Rz-;^=pG=}jL6A^2D_xQC9%Nv zi`?f}Sy#*Wk2I?EHB;o03&&*WFMB@Qzp}um8J!oosQY=-Wg=!HA=$Y1*i}0NgHjar z#XpFDFuB9l#>PJ&U`eEwVpU*i{m+Ph{@+)DtDD=9opALlW1?}tbLZ^M>U{LD%*@Q% zi`jz2j*p7O$*DL!Tv)<%_^|3yKkM4>SFT*aDP@>a5&}O~5uC=4T&03vfE|m*zJ0GS z;r!vPmk#3l4jgJ&emyu1cctx%k;M~lNXr9L!^gxwa;y zIrsjhXHAWgS3RCmHbbnbnCPR6*47jrt9Rm|9i@P8dEL&*;g3-c4hT5N&d$!owR7`L z&Ye~8U_C7M9XzPOLV3y1@V(Uuaklj|L??469==Ah@*gUjr#4k!`!_W<$}1?S#0cLM ze-m-{?%mtB!6$zI^#tM)XU^uKJSYyWd#{yo)E3n}7^h z0i02D#>U|F9-{P{cNKGYA^ooh+rVdRa^Ft)ENf^@T^%t!aPo0xW}Dw3MSaJy{b0ic zwY^!fKfrv-JxBN)Rsvs=Q{f9H*3gL9SbcQV&mSu%Cl5>N#{7fHTV0K3J#_^5rjvr@ zN@BfdnXz-${8MUM9nPOe4co>z1C#QY%dFz`5SxMK-1360aEyEQ7^?&+qv6Gip|P>z z=s-e3?eCfjpFLxx^vl!BP)~ghxbd<1BY{BZ?4(;&40Tubk8f;hiWPM}f}8^W>60hw zT3WIR4LA(_HqL9u*Hpw;_(Vmk&mUf7n1v--TT=rM63#UIQm8WIwv@VcRaIzrq;Uvo z5Ut)yt9kI0f5EP7d;v^OCHT4c=DNBMnWZChq4%-R!{jf?%2r^fO2pldh!LA_Zg2$(TP}JJj}Pi zimyU`=2##9FF1G8kMT?QP}NMQ-m7xcOaDbCjGp%J?;5I@u4wJ>vrQwz|Qbr|BVSCEIt>(17kw4b(&dV_4hTW~Zk9!H8VS4RWFn<_sS!@?vkk z?Vwd3SPha0Qw>^d#%5-lB~qR*2T%NonyZl5h$NP4^}T0uBErJZTfvsFexE+2bO|_+ z#zA-c>OjWa4}B}VDx$vTQE(I+F4#$GDpbloX-E zaPtALda`Ze`@AM|N?yN~%h5Tjq2U>9g*}+}9!B7P%9DW2?#dx@UgUi?`P9-kpJ=0- zs;Azq8)WtZRjjJJ`#~HJ2-p-RI*L1K9DE-XO=Q#zPzpWhIZt5+>c95#FcG(>v^Mk% zZh!gmB}dq19}4Iw03a||kcdf8k%5=C&3+#%tC5>qQBu-Ck>BF_ZeeEP;>n5?c%k&>0AHaJuZ`^ZmBDUtE(%t8?hAozUnA3rms81<~MZEXylHvv=x(^kZBmQ zyL#aQqr~f;9uEhH({ZY|09dzeFM{_pJNAwU+8JxkFeR$DBab*fo)O#B&_E2|1>jL8 zBtY4ie-sfB(O#xN1AHzF-?X4$x}?og zuf%cU!9cp{uh-A7dnyaOb%Q>$>qp4V&5b#MdGpQqxVV>a5P$R+%+H-q`i^Yc!?u-0L3$Nqc=$@5L!T`F5zvzT~x505o}|IL8Ux*7ot zbr0G7Ym9QAKAl`xt`m)A=unA~qHE{l=Z`t&a#TcQPwd(3c4PEy{WE6{gvfDlaG){s z*9>i)hN+mDp5Ef@$Hzkv&|B_X2Jv4{P3^jdqW&C2%I5^0&ii-n+`+q$T;YQ$tD-^^ zP)6zZ@X@0;^+uBG9q}oF^{AnV6zUq-JWxuem{y?YdFHg;6cpE!mD#D?RY$yyx@Rbc z=9=o=iQ?+=OQYDpDVNV%`xTXx(o<6@Hs2f?8fwcptE;Quw1J0O8XF7&toxejl^_)e z8MRenAuJ5m#MxHd&Di>0mseFOh?By12h?1w^DrT60?b=0LOx36$vE`Aq`4+owrppU z8JRB%Jmnz|pD)_B`$R$mw%*#C+*7OaBT2!ZGUur9UJh3_B*?nJ7G8gi_mp@n&J1xM zE?6{3zVa2tmv6^EyXNr#>L~P0loDv9PEL6PE@bbEU`?W4tVW%f^l%=(>`2 zj6wQHiucje)8j93LVdRHH8{LW#>U&r3rJKC0ySRGp3P1(Gy_&oImWO44k4Ug)X8e{ z{Rt|ch1{UC|7Lh6ln8lx;{f~?78a|&r)v`-8*Y{RDlvp>Dt7%#PSZkpvy0EdT;Q?8htWaea?(#Nr5h2Xwk?sXqp>wRH7l1W*M3kvu!lQ(7TQ7B=rN|7QlA+|IXG4Luu_;Gr=M^6VWoPDeJ*I@Cl za_skfNlv;UGA#>gKModbw0-1IXVBmSq?p8FEscz16tU?m4MDKO!^4RvQ*=2vI041x zv(s}Rf1FBxDR2PxO`A5chWa(9q^9~2Q>ThG=Bnu42zst8h<{u>881v942xnvr5|D} zpX`LK?-QgXrz_7N#t}itMP6RP#>R%PW_RR%;TW#aO8mN&l@&if!v6K3YM#RgAsQ0* zJTF<~1u%XpSz@4Y)`U+7s|;c*$HMWNn{?Z@{Z|mYJ_$((`NVzXh|b=_uViJVr4{)v zGnwaof=KqiB;@jyEAokrI93R%DeXrWm58fH)Vd^Z=%PTPeeX%esG1~pz``Sk4y8YR zI)nJ4ewPuElTG|Y?dIz_(}*rVg)kMc38Kz53(tx9c=e%AlNCO9PTvd1=bisvDu(<| zkb}?|l0<&u&Ql+_?vetdgWkDk@dPrS=ZC zqLxO?4x1F+HIwI2At)e#6kf~AqN^PRtB0|Y3lG`l|C=_{YKo3K1Jd<(5|SM;Siwhy zZcERIs|^U5s@a`yYiwg?191*XHji;d4=F;Qw-L9HkTcfZ(C{I|BnTt$IS7|i*DkE# z7j||=gQIw?ts?FC`ZcLFpw}UBaSt>`8=EJ&$&QyVE3r_jQHMQvu==qw6kLg!Jfc0KDxCXgQ2xr@8Y5))5|fhL1J$6&{7WE++V%xXD!=KIYR&%* z^VRdoM(>9iny-iOlx22ZxoZ57f?{>5cs0_1#0{<-EsV1eUbSPhw7NR<@V+T0SXqS2 zrg$Q@wi#E&;bCd=HD^=|uv!)@k9aTL2TytM-~nk|+99nRD!+G)Kcx_Y zigZyp@_h`a*7JEPN=he4!@|Qq5P(cmH4Cs|g~~eNNud8A_glL-j9hDc`U_CAJ_k- z%2>tz9A?|OV+W%bF}{7{Mi7HIrbL=rTfGwskepj|bNUasSF!&a+#ht)k(fUIVsWux z;I<0g`qn@UkN3!t<&_m7I%O9Zk#n?tobB)4iMua5nc2uM{cb^!Y6`y(ALs%kaS@f| zCYk{nG!uLaN{}|^z1Ua=Yu(7`NDIgVYI}<>Tf4YK2|^~i_8n>A;pgAcwws2=ac=x9 z60*ah$Bu=`CrZR2K?{h^quDu=71b^5`O;}_JVudq8prO-m;NcI`F!H=*!$l$Y}|Xpy(f3yZGR*495C{|(0s>QC6cdz86}Kg7lQ4x>8( zEbQ1^23NoSeLa{hoG>Jf=aDfgLoBkP0rp_-M7J5eK)&^djS?oKL%ZA?_O2J5M0?k) zmg?%!zQh3J@uAWIdLghEIr0o^cr8`$>{&1uXbjfV12w=zRBXzs)EK4!P(U-pMq*-S zMrsBjPr>&lW@f@Jvlb2xN5z;WfLMm%pFstH%-%Bih<{TDydS-i?cad;wEXs~J$mY^-N zxClvIokJ~-5G z^9Ya->8h<&UV0!(XXWJVY|0?$=NFmx5`gh;+Y19g4#*1~2k@j>yQ$}QG%zGN#7`|C zjo#+rD&=yov#Se-&i)8FcFC=VA-k3JPni_gN7#Rqm$zwm>VbE6LN0WSW;a-tfj$xf zQI2M^MyOF^zo#8u^Xs(ZlO;W#@C!Bv3;Hty`dsf`Ck7S;n=Zb_!xL$2us{; zai(OVgbV+;*beF=1TbOQeFjYPPeZq^Dxpky-naqU1gL=+3qOO#|I26&2}$gx80ERy z*=O0=OHsp)-==Oxa(>^q5oLZ=x2<%26!L*g!tTni7KBW4lX%7-;PD8&eNb}UC?h-> z#+5beKC_U!P~yT(1oMf!0s>&WMB7GIRu&$Uo?diFH3EVlEDR0uI1ef+b)Hak!64d} zI72H@5@Zo@+e~Lj03q zLs{=L`uf4-K)=g{;q%lV8MMW?Be2UwpXSZp3-=jYHUK)ZL+emA~M?O`?q|3 zF(!5q!*3kH=;+_(ZLE;7{+6Z;F}VF8@SAP_C@d@Zov`m8ziX@a@qL(eCG18B$Z8be zvG!PLO;weM{ctlx-w&#C_2to0U2IiiBGvb?oE2y&H8Z{7^^;HCs)K-rNZV2~l2Hq*0C>aUHm{X}krteBYDY@U$C zydZB%-Cs3Sa|V+3l(G*?s&=*CfzwSK?K3=z?Xk>@H%%@94kXNT24iu0ToVkR)`pT} zkyhEgRpxsRL*^p&6FY#umyV7O@}04gNMZLT{X2DL{B`OqK4oTR26IG^ zI=;-#0LJX{8~!ePbHJae6*8N)7Ws4^AHyo z+5tVLMN>85YX}JnKF-J}FDtWma6o&<*Jk5F%&ow3-x?%vL|jcY9pP+`U7$4f`&kT$ zve3|^*B3y@0i9md=^A-sw05I@--GT4a3IXNWO8$IFj|IG2%yV<2g#V4mVhB=0!E&~ z7A6`!ofL{a!D8=@s#wHmC&y6?O&pPVW_bPhUpYBQ3vVb9$FM;a#1xG2+I%FHR)co< z>-G2Oj$qT7r_a@J7-4rHj0^n3!2yOLD7K59o~STAe!O+_W~Nr`h<=-Vi8!Qwpjlz( zF)`h6@&c*&(Lwl^V9Bl%tirrJgy#^}iH@e*?t>P-hgq%bzZB?Cc7JWQAPYDNcoSPT zZzh*8$U;VL6dvIZtSd@P0R#<=2m<5$3+IooLm-3$dK`^%`!akA!HY-h4y&2_&L13b-&mNJvooYMeZ$W5eLt9>3x5Q$nF zW`oD-f-$B(comspcreCrMbNi2m^{TwATCcFMO0S4Vqt*+hHH5Qbe~v_YCIdnvk~MW zj=Dk85Znr3t4s)-D-z~`J0Q8Pz!PTjIc7RCx7BY~Z~h)~bMwLC$G4G?9EbKPL3*~( zL224CRrAf@G=&6mEB(fArefiGij!RjV-m(ND6nS994SidZCW7_kq^u(sLG({*d-Ja z=N_D!e|$|R9lIP^M^Z+va0N9@_5gV2mslQ6&(3mja14L?gl4hJ?Fj9zU2>19WRK3z zqsKf}PespyTtZwu3s=RG-;%1;&z|i9B!uBEBU6s(bn(-t&7kZoa6+(T7cO{o_RcMS zF_-*B7EZMU`@Vf7Yx9`o!cf1bpkg2AZd18r>^uV3!qSrEgauOBPoF)5k;?3KM8%L+ zr|&QkDUUgW^q=n2B^%kw~yy1IMBVs2ymejN}ZX5*BVl*)wA zIEa?c(n*Uh1h|o6?dgeq)e98);gPTX_wI~}BFii~8O*6KOXuHkA{(&JtF^Ta0%hzm z7jJSi6BFd+zPc$}TT-XDj)DTlrEC|l)3NJVzZ?Q8h4bQ!Y2RVLY{Q4xn#7qBuitXu z8Dcr%{LR9O0EqOy_ZDfXR80(2;2pdALEhZw1x*+UV|wwcx5zQ4!uR!52ab|1E`{iE z#m2@42L{?(Sqa*Gx;?P{`PUX_5CgvuS1RZ}`8w0|-V_Owc}n1ONHE)jx9S(z{lP$n zddGFHAP?IE{l2AzUr;b5UvK}ne2v+%?oDm&1C45Y8?@$br1EST<`NacH95i*SrJ zTmsb0o@RJ!OT_*AzGzh%Y8+wS885CnJEKV<(3@Xeyow(JmvClo4$~{G3@Ev`_#P6c z#SFq(Sy@qWPzOwrSeL;-I^f(Kf)Y;&7^*l<8hC6kGQwot7MNE0jz(U-D(+WifAp}c zY2*6-2YY%T>TH8?Wu#CLFRFV+L?8cqG)OFTw?onM)_(xhydV2DPn#1F&rms*dH-Ag zp-2}t)MA23UrmiMM9$3Ij6XMI2q60##>R2<=+5K{tBYWT+MF3FDK8Fu>%7!_m}2*j zZ!kd!4s%a%0x`u5y(}bJ&OiP~{zgdpFOA&nnoW_VO!orX;NQkkkFyN%K*VkovF`J7 zXHbmT4?>)!eQSb%>lMfY%77r}W0{zkCOQAODIsZ(l}9Xq7#y<#32IS%B1RwV*jsv& zIOCFM^-IskAYD<2f3yD_j@>$fZu=AWR|GS(EhC)l+Y@SG;`gOTt9o#Hgu4ao_DTEb z`Ur_7amBwQmqS#NA~&X1QdVt>29CXmy%5DVUgkaA%s^os&hunHhRE*S+bI@HRw4wX zvE|a0E91Sranr|sgH?!vv_edP5$yKj(cz1UqO{2M;StES=4>79?Y%T*rrFP)wN@HE zR9;E4A13?~4VS?oh9Jef!dFT-v$&7pEOA;CVF$Z&4`h>@zW7K+J2w^1#FdF(^~0(z zhq({`jA(AJ*fvIr#0^ryu^#L1_?{%h>$Bzcrw2zzm$go>N7x8K^v8sGcrGBO(JeKp z|8^Hj-nSN&sjm)z?6pj9>>Y5f+LuxHNmsvo$2$XE1&H?m{p7WJem!JHWOyEh(0GJ{ z2Pml4#J(C(Ye6b3y{Xx`xoacLkaGiqgV&;)K09VE^$0UD$NWnlo1U|eXOeE++Wb5O z6o+IV>E_K>C*QvWZuzoy0DIKKWw^+X;l#TA^jnF0t5aW(PgTE|)8vct@_|gv ~* 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 Mrz-nM`rOt33yFE0ApigX diff --git a/doc/assets/digitalocean_ubuntu.png b/doc/assets/digitalocean_ubuntu.png new file mode 100644 index 0000000000000000000000000000000000000000..132ca20ed2262b47356ecd2e306153e1db83bc13 GIT binary patch literal 43101 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

2>f77QxTv(?sAGM;q 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

u> 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 literal 0 HcmV?d00001 diff --git a/doc/security/code-server.fail2ban.conf b/doc/security/code-server.fail2ban.conf index 3f4edae4..a3cad4e5 100644 --- a/doc/security/code-server.fail2ban.conf +++ b/doc/security/code-server.fail2ban.conf @@ -1,10 +1,7 @@ # Fail2Ban filter for code-server -# -# [Definition] - failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"remote_address\":\"\" ignoreregex = @@ -12,4 +9,3 @@ ignoreregex = datepattern = "timestamp":{EPOCH}}$ # Author: Dean Sheather - diff --git a/doc/security/fail2ban.md b/doc/security/fail2ban.md index a9ad8681..9b98b690 100644 --- a/doc/security/fail2ban.md +++ b/doc/security/fail2ban.md @@ -1,4 +1,7 @@ -# Protecting code-server from bruteforce attempts +# Protecting code-server from Bruteforce Attempts + + +### **NOTE: FAILED LOGIN ATTEMPT LOGGING IS NOT IN THE CURRENT VERSION AND WILL BE RELEASED IN V2.** code-server outputs all failed login attempts, along with the IP address, provided password, user agent and timestamp by default. When using a reverse @@ -39,4 +42,3 @@ authentication attempts for many applications through regex filters. A working filter for code-server can be found in `./code-server.fail2ban.conf`. Once this is installed and configured correctly, repeated failed login attempts should automatically be banned from connecting to your server. - diff --git a/doc/security/index.md b/doc/security/index.md new file mode 100644 index 00000000..9844b990 --- /dev/null +++ b/doc/security/index.md @@ -0,0 +1,8 @@ +# Security Guides + +We recommend users running code-server setup SSL and fail2ban on their +instances for improved security and resilience to attacks. + +* [Self-signed SSL guide](./ssl.md) +* [Let's Encrypt SSL guide](./ssl-certbot.md) +* [Fail2Ban setup guide](./fail2ban.md) diff --git a/doc/security/ssl-certbot.md b/doc/security/ssl-certbot.md new file mode 100644 index 00000000..8c84dad1 --- /dev/null +++ b/doc/security/ssl-certbot.md @@ -0,0 +1,63 @@ +# Generate a Certificate Using Let's Encrypt πŸ”’ + +To get around the certificate warnings in Chrome, you might want to install a +certificate from a trusted Certificate Authority (CA). Luckily, there are CAs +like [Let's Encrypt](lets-encrypt) which provide certificates for free. + +[lets-encrypt]: https://letsencrypt.org/ + +--- + +### Using Certbot + +[Certbot](certbot) is the program we'll be using to issue certificates from +Let's Encrypt. + +> Pre-requisites: You will need a domain name or subdomain pointed to the IP +> address of your server. + +1. Install Certbot by heading to the [instructions page](certbot-instructions). + Select **None of the above** for the software and the right operating system + for your setup. +2. Follow the installation instructions, and stop once you get up to the part + where you run the `certbot certonly` command. +3. Ensure your code-server instance isn't running, and any other webservers that + could interfere are also stopped. +4. Run the following command, replacing `code.example.com` with the + hostname/domain you want to run your server on, to issue a certificate: + ``` + sudo certbot certonly --standalone -d code.example.com + ``` +5. Follow the prompts, providing your email address and accepting the terms + where required. +6. Once the process is complete, it should print the paths to the certificates + and keys that were generated. You can now restart any webservers you stopped + in step 2. + +[certbot]: https://certbot.eff.org/ +[certbot-instructions]: https://certbot.eff.org/instructions + +--- + +### Starting code-server with a Certificate and Key + +Just add the `--cert` and `--cert-key` flags when you run code-server: + +```shell +./code-server --cert=/etc/letsencrypt/live/code.example.com/fullchain.pem --cert-key=/etc/letsencrypt/live/code.example.com/privkey.pem +``` + +You can now verify that your SSL installation is working properly by checking +your site with [SSL Labs' SSL Test](ssl-labs-test). + +[ssl-labs-test]: https://www.ssllabs.com/ssltest/ + +--- + +### Next Steps + +You probably want to setup automatic renewal of your certificates, as they +expire every 3 months. You can find instructions on how to do this in +[Certbot's documentation](certbot-renew-docs). + +[certbot-renew-docs]: https://certbot.eff.org/docs/using.html?highlight=hooks#renewing-certificates diff --git a/doc/security/ssl.md b/doc/security/ssl.md index c5a86da7..de859aa4 100644 --- a/doc/security/ssl.md +++ b/doc/security/ssl.md @@ -1,24 +1,33 @@ -# Generate a self-signed certificate πŸ”’ +# Generate a Self-signed Certificate πŸ”’ -code-server has the ability to secure your connection between client and server using SSL/TSL certificates. By default, the server will start with an unencrypted connection. We recommend Self-signed TLS/SSL certificates for personal use of code-server or within an organization. +code-server has the ability to secure your connection between client and server +using SSL/TSL certificates. By default, the server will start with an +unencrypted connection. We recommend Self-signed TLS/SSL certificates for +personal use of code-server or within an organization. -This guide will show you how to create a self-signed certificate and start code-server using your certificate/key. +This guide will show you how to create a self-signed certificate and start +code-server using your certificate/key. ## TLS / HTTPS -You can specify any location that you want to save the certificate and key. In this example, we will navigate to the root directory, create a folder called `certs` and cd into it. +You can specify any location that you want to save the certificate and key. In +this example, we will navigate to the root directory, create a folder called +`certs` and cd into it. ```shell mkdir ~/certs && cd ~/certs ``` -If you don't already have a TLS certificate and key, you can generate them with the command below. They will be placed in `~/certs` +If you don't already have a TLS certificate and key, you can generate them with +the command below. They will be placed in `~/certs`. ```shell openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ~/certs/MyKey.key -out ~/certs/MyCertificate.crt ``` -You will be prompted to add some identifying information about your organization +You will be prompted to add some identifying information about your +organization: + ```shell You are about to be asked to enter information that will be incorporated into your certificate request. @@ -35,19 +44,27 @@ Organizational Unit Name (eg, section) []:Docs Common Name (e.g. server FQDN or YOUR name) []:hostname.example.com Email Address []:admin@example.com ``` ->If you already have a TLS certificate and key, you can simply reference them in the `--cert` and `--cert-key` flags when launching code-server + +> If you already have a TLS certificate and key, you can simply reference them +> in the `--cert` and `--cert-key` flags when launching code-server. -## Starting code-server with certificate and key +## Starting code-server with a Certificate and Key -1. At the end of the path to your binary, add the following flags followed by the path to your certificate and key like so. Then press enter to run code-server. - ```shell - ./code-server --cert=~/certs/MyCertificate.crt --cert-key=~/certs/MyKey.key - ``` -2. After that you will be running a secure code-server. +Just add the `--cert` and `--cert-key` flags when you run code-server: -> You will know your connection is secure if the lines `WARN No certificate specified. This could be insecure. WARN Documentation on securing your setup: https://coder.com/docs` no longer appear. +```shell +./code-server --cert=~/certs/MyCertificate.crt --cert-key=~/certs/MyKey.key +``` -## Other options +> You should check that the +> `WARN No certificate specified. This could be insecure` are no longer visible +> in the output. -For larger organizations you may wish to rely on a Certificate Authority as opposed to a self-signed certificate. For more information on generating free and open certificates for your site, please check out EFF's [certbot](https://certbot.eff.org/). Certbot is a cli to generate certificates using [LetsEncrypt](https://letsencrypt.org/). +## Other Options + +For larger organizations you may wish to rely on a trusted Certificate Authority +as opposed to a self-signed certificate. For more information on generating free +and open certificates for your site, please check out EFF's +[certbot](https://certbot.eff.org/). Certbot is a cli to generate certificates +using [LetsEncrypt](https://letsencrypt.org/). diff --git a/doc/self-hosted/cros-install.md b/doc/self-hosted/cros-install.md index 44460189..623df2c4 100644 --- a/doc/self-hosted/cros-install.md +++ b/doc/self-hosted/cros-install.md @@ -1,20 +1,31 @@ -# Installng code-server in your ChromiumOS/ChromeOS/CloudReady machine +# Installng code-server on a ChromeOS/CloudReady machine -This guide will show you how to install code-server into your CrOS machine. +This guide will show you how to install code-server on your CrOS machine. ## Using Crostini -One of the easier ways to run code-server is via [Crostini](https://www.aboutchromebooks.com/tag/project-crostini/), the Linux apps support feature in CrOS. Make sure you have enough RAM, HDD space and your CPU has VT-x/ AMD-V support. If your chromebook has this, then you are qualified to use Crostini. +One of the easier ways to run code-server is via [Crostini](crostini), the Linux +apps support feature in CrOS. Make sure you have enough RAM, HDD space and your +CPU has VT-x/AMD-V support. If your Chromebook has this, then you are qualified +to use Crostini. -If you are running R69, you might want to enable this on [Chrome Flags](chrome://flags/#enable-experimental-crostini-ui). If you run R72, however, this is already enabled for you. +If you are running R69, you might want to enable this on +[Chrome Flags](r69-flag). If you run R72, however, this is already enabled for +you. -After checking your prerequisites, follow the steps in [the self-host install guide](index.md) on installing code-server. Once done, make sure code-server works by running it. After running it, simply go to `penguin.linux.test:8443` to access code-server. Now you should be greeted with this screen. If you did, congratulations, you have installed code-server in your Chromebook! +After checking your prerequisites, follow the steps in [the self-host install +guide](self-hosted-guide) on installing code-server. Once done, make sure +code-server works by running it, then simply go to `penguin.linux.test:8443` to +access code-server. You should be greeted with the following screen. If it +works, congratulations, you have installed code-server in your Chromebook! ![code-server on Chromebook](../assets/cros.png) -Alternatively, if you ran code-server in another container and you need the IP for that specific container, simply go to Termina's shell via `crosh` and type `vsh termina`. +Alternatively, if you ran code-server in another container and you need the IP +for that specific container, simply go to Termina's shell via `crosh` and type +`vsh termina`. -```bash +``` Loading extra module: /usr/share/crosh/dev.d/50-crosh.sh Welcome to crosh, the Chrome OS developer shell. @@ -28,9 +39,11 @@ Load it by using the Ctrl+Shift+P keyboard shortcut. crosh> vsh termina (termina) chronos@localhost ~ $ ``` -While in termina, run `lxc list`. It should output the list of running containers. -```bash +While in termina, run `lxc list`. It should output the list of running +containers. + +``` (termina) chronos@localhost ~ $ lxc list +---------+---------+-----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | @@ -40,14 +53,29 @@ While in termina, run `lxc list`. It should output the list of running container (termina) chronos@localhost ~ $ ``` -For this example, we show the default `penguin` container, which is exposed on `eth0` at 100.115.92.199. Simply enter the IP of the container where the code-server runs to Chrome. +For this example, we show the default `penguin` container, which is exposed on +`eth0` at 100.115.92.199. Simply enter the IP of the container where code-server +is running into Chrome to access code-server. + +[crostini]: https://www.aboutchromebooks.com/tag/project-crostini/ +[r69-flag]: chrome://flags/#enable-experimental-crostini-ui +[self-hosted-guide]: ./index.md ## Using Crouton -[Crouton](https://github.com/dnschneid/crouton) is one of the old ways to get a running full Linux via `chroot` on a Chromebook. To use crouton, enable developer mode and go to `crosh`. This time, run `shell`, which should drop you to `bash`. +[Crouton](crouton) is one of the old ways to get a running full Linux via +`chroot` on a Chromebook. To use crouton, enable developer mode and go to +`crosh`. This time, run `shell`, which should drop you to `bash`. -Make sure you downloaded `crouton`, if so, go ahead and run it under `~/Downloads`. After installing your chroot container via crouton, go ahead and enter `enter-chroot` to enter your container. +Make sure you downloaded `crouton`, if so, go ahead and run it under +`~/Downloads`. After installing your chroot container via crouton, go ahead and +enter `enter-chroot` to enter your container. -Follow the instructions set in [the self-host install guide](index.md) to install code-server. After that is done, run `code-server` and verify it works by going to `localhost:8443`. +Follow the instructions set in [the self-host install guide](self-hosted-guide) +to install code-server. After that is done, run `code-server` and verify it +works by going to `localhost:8443`. -> At this point in writing, `localhost` seems to work in this method. However, the author is not sure if it applies still to newer Chromebooks. +> At this point in writing, `localhost` seems to work in this method. However, +> it might not apply to newer Chromebooks. + +[crouton]: https://github.com/dnschneid/crouton diff --git a/doc/self-hosted/index.md b/doc/self-hosted/index.md index f3a867f1..7e5bd458 100644 --- a/doc/self-hosted/index.md +++ b/doc/self-hosted/index.md @@ -1,38 +1,65 @@ # Getting Started -[code-server](https://coder.com) is used by developers at Azure, Google, Reddit, and more to give them access to VS Code in the browser. +This document pertains to Coder-specific implementation of VS Code: code-server. +For documentation on how to use VS Code itself, please refer to the official +[VS Code documentation](vscode-documentation). + +If you get stuck or need help at anytime, [file an issue](create-issue), +[tweet (@coderhq)](twitter-coderhq) or [email](email-coder). + +[vscode-documentation]: https://code.visualstudio.com/docs +[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+self-hosted+quickstart+guide +[twitter-coderhq]: https://twitter.com/coderhq +[email-coder]: mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide + ## Quickstart Guide -> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide). +It takes just a few minutes to get your own self-hosted server running. If +you've got a machine running macOS or Linux, you're ready to start the +binary which listens on port `8443` by default. -This document pertains to Coder specific implementations of VS Code. For documentation on how to use VS Code itself, please refer to the official [documentation for VS Code](https://code.visualstudio.com/docs) + -It takes just a few minutes to get your own self-hosted server running. If you've got a machine running macOS, Windows, or Linux, you're ready to start the binary which listens on port `8443` by default. +1. Visit the [releases](code-server-releases) page and download the latest + release for your operating system. +2. Extract the archive and double click the executable to run in the current + directory. +3. Copy the password that appears in the output. + +4. In your browser navigate to https://localhost:8443. You will be greeted with + an SSL warning as code-server uses a self-signed certificate (more on that + below). Skip the warning. +5. Login using the password from earlier. - +Be careful about who you share your password with, as it will grant them full +access to your server. + +[code-server-releases]: https://github.com/cdr/code-server/releases -1. Visit [the releases](https://github.com/cdr/code-server/releases) page and download the latest cli for your operating system -2. Double click the executable to run in the current directory -3. Copy the password that appears in the cli -4. In your browser navigate to `localhost:8443` -5. Paste the password from the cli into the login window -> NOTE: Be careful with your password as sharing it will grant those users access to your server's file system +### Security Warnings -### Things To Know -- When you visit the IP for your code-server instance, you will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**. +When you visit your code-server instance, you will be greeted with a warning +page similar to the following screenshot. code-server is using a self-signed SSL +certificate for easy setup. In Chrome/Chromium, click **Advanced** then click +**proceed anyway**. In Firefox, click **Advanced**, then **Add Exception**, +then finally **Confirm Security Exception**. + -## Usage -
code-server --help
-code-server can be ran with a number of arguments to customize your working directory, host, port, and SSL certificate. +## code-server Usage + +You can bring up code-server usage by using `code-server --help`. Arguments let +you customize your working directory, host, port, SSL certificates, and more. + +Flags can be supplied to code-server like `--flag-name value` or +`--flag-name=value`. To supply values with whitespace, use double quotes. ``` +$ code-server --help Usage: code-server [options] Run VS Code on a remote server. @@ -44,7 +71,7 @@ Options: -e, --extensions-dir Override the main default path for user extensions. --extra-extensions-dir [dir] Path to an extra user extension directory (repeatable). (default: []) --extra-builtin-extensions-dir [dir] Path to an extra built-in extension directory (repeatable). (default: []) - -d, --user-data-dir Specifies the directory that user data is kept in, useful when running as root. + -d --user-data-dir Specifies the directory that user data is kept in, useful when running as root. -h, --host Customize the hostname. (default: "0.0.0.0") -o, --open Open in the browser on startup. -p, --port Port to bind on. (default: 8443) @@ -52,74 +79,228 @@ Options: -H, --allow-http Allow http connections. --disable-telemetry Disables ALL telemetry. --socket Listen on a UNIX socket. Host and port will be ignored when set. - --trust-proxy Trust the X-Forwarded-For header, useful when using a reverse proxy. --install-extension Install an extension by its ID. -h, --help output usage information ``` - ### Data Directory - Use `code-server -d (path/to/directory)` or `code-server --user-data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in. +By default, code-server listens on `0.0.0.0:8443`. If you'd like to customize +this, use the `--host` and `--port` flags: +`code-server --host 127.0.0.1 --port 1234`. - ### Host - By default, code-server will use `0.0.0.0` as its address. This can be changed by using `code-server -h` or `code-server --host=` followed by the address you want to use. - > Example: `code-server -h 127.0.0.1` +You can instruct code-server to automatically open itself in your default +browser by using the `-o` or `--open` flag. - ### Open - You can have the server automatically open the VS Code in your browser on startup by using the `code-server -o` or `code-server --open` flags +Use `code-server -d path/to/directory` to specify where code-server stores it's +configuration data. You can specify where extensions are installed using the +`-e`, `--extra-extensions-dir` and `--extra-builtin-extensions-dir` flags. - ### Port - By default, code-server will use `8443` as its port. This can be changed by using `code-server -p` or `code-server --port=` followed by the port you want to use. - > Example: `code-server -p 9000` - ### Telemetry - Disable all telemetry with `code-server --disable-telemetry`. +### SSL Certificates - ### Cert and Cert Key - To encrypt the traffic between the browser and server use `code-server --cert=` followed by the path to your `.cer` file. Additionally, you can use certificate keys with `code-server --cert-key` followed by the path to your `.key` file. -> Example (certificate and key): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.cer --cert-key /etc/letsencrypt/live/example.com/fullchain.key` -> Example (if you are using Letsencrypt or similar): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.pem --cert-key /etc/letsencrypt/live/example.com/privkey.key` +To change the certificate code-server uses for HTTPS connections, specify a +certificate with `--cert` and a private key with `--cert-key`. -> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../security/ssl.md) +If you're using Let's Encrypt, you should be using the `fullchain.pem` file as +the certificate and `privkey.pem` as the private key. - ### Nginx Reverse Proxy - Below is a virtual host example that works with code-server. Please also pass `--allow-http` and `--trust-proxy` to code-server to allow the proxy to connect. You can also use Let's Encrypt to get a SSL certificates for free. - ``` - server { - listen 80; - listen [::]:80; - server_name code.example.com code.example.org; - location / { - proxy_pass http://localhost:8443/; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection upgrade; - proxy_set_header Accept-Encoding gzip; - } +``` +code-server \ + --cert /etc/letsencrypt/live/example.com/fullchain.pem \ + --cert-key /etc/letsencrypt/live/example.com/privkey.pem +``` + +For more information on security and SSL configuration, please visit the +[security documentation](../security). + + +#### Telemetry + +Telemetry can be disabled by using the `--disable-telemetry` flag or by setting +the `DISABLE_TELEMETRY` environment variable to `true`. If telemetry is enabled, +code-server will send the following data along with VS Code's telemetry data: + +- Unique machine ID +- CPU core count and model +- Memory information +- Shell information (which shell you use) +- OS release and architecture + + +### Nginx Reverse Proxy + +The following site configuration file works with code-server. When starting +code-server, be sure to provide the `--allow-http` and `--trust-proxy` flags so +Nginx can connect to code-server properly. + +Some of these directives require a version of Nginx greater than or equal to +`1.13.0`, which might not be available in your distro's repositories. Check out +[Nginx's documentation](nginx-install) for more information on how to install +the latest version of Nginx from the official repository. + +``` +# HTTP configuration +server { + listen 80; + listen [::]:80; + server_name code.example.com code.example.org; + + # If you're using CloudFlare, uncomment the following line. + # real_ip_header CF-Connecting-IP; + + # Other security options. + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + location / { + proxy_pass http://localhost:8443/; + proxy_set_header Accept-Encoding gzip; + proxy_set_header Connection upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } - ``` +} - ### Apache Reverse Proxy - Example of a HTTPS virtualhost configuration for Apache as a reverse proxy. Please also pass `--allow-http` and `--trust-proxy` to code-server to allow the proxy to connect. You can also use Let's Encrypt to get a SSL certificates for free. - ``` - +# HTTPS configuration. Scores an A on SSL Labs' SSL Server Test. +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name code.example.com code.example.org; + + # If you're using CloudFlare, uncomment the following line. + # real_ip_header CF-Connecting-IP; + + # SSL certificate and key. + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/cert-key.pem; + + # Strong TLS configuration. Originally taken from https://cipherli.st/. + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + # ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096 + ssl_ciphers EECDH+AESGCM:EDH+AESGCM; + ssl_ecdh_curve secp384r1; + ssl_session_timeout 10m; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + ssl_stapling on; + ssl_stapling_verify on; + resolver 8.8.8.8 8.8.4.4 valid=300s; + resolver_timeout 5s; + + # Other security options. + # add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + location / { + proxy_pass http://localhost:8443/; + proxy_set_header Accept-Encoding gzip; + proxy_set_header Connection upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +Make sure to set the `proxy_pass` directive to the actual address of your +code-server instance and the `server_name` directive to the hostname/s of your +website. If you're using an SSL certificate, make sure to change the +`ssl_certificate` and `ssl_certificate_key` directives. If not, remove the HTTPS +`server` block entirely. + +[nginx-install]: https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#installing-a-prebuilt-package + + +### Apache Reverse Proxy + +The following virtual host configuration file works with code-server. When +starting code-server, be sure to provide the `--allow-http` and `--trust-proxy` +flags so Apache can connect to code-server properly. + +Some of these directives require a version of Apache greater than or equal to +`2.4.0`, which might not be available in your distro's repositories. You will +also need to enable the following modules: `rewrite`, `proxy`, `proxy_http`, +`proxy_wstunnel`, `ssl`, and `socache_shmcb`. + +``` +# HTTP configuration. + + ServerName code.example.com + + # If you're using CloudFlare, uncomment the following line. + # RemoteIPHeader CF-Connecting-IP; + + # Other security options. + Header always set X-Frame-Options DENY + Header always set X-Content-Type-Options nosniff + + RewriteEngine On + RewriteCond %{HTTP:Upgrade} websocket [NC] + RewriteCond %{HTTP:Connection} upgrade [NC] + RewriteRule .* "ws://localhost:8443%{REQUEST_URI}" [P] + + RequestHeader set X-Forwarded-Proto https + RequestHeader set X-Forwarded-Port 443 + + ProxyRequests off + ProxyPass / http://localhost:8443/ nocanon + ProxyPassReverse / http://localhost:8443/ + + +# HTTPS configuration. Scores an A on SSL Labs' SSL Server Test. + + SSLStaplingCache shmcb:/tmp/stapling_cache(150000) + ServerName code.example.com - RewriteEngine On - RewriteCond %{HTTP:Upgrade} =websocket [NC] - RewriteRule /(.*) ws://localhost:8443/$1 [P,L] - RewriteCond %{HTTP:Upgrade} !=websocket [NC] - RewriteRule /(.*) http://localhost:8443/$1 [P,L] + # If you're using CloudFlare, uncomment the following line. + # RemoteIPHeader CF-Connecting-IP; - ProxyRequests off + # SSL certificate and key. + SSLEngine On + SSLCertificateFile /path/to/cert.pem + SSLCertifcateKeyFile /path/to/cert-key.pem + SSLCertificateChainFile /path/to/chain.pem + + # Strong TLS configuration. Originally taken from https://cipherli.st/. + SSLCipherSuite EECDH+AESGCM:EDH+AESGCM + SSLProtocol -all +TLSv1.2 + SSLHonorCipherOrder On + SSLCompression off + SSLUseStapling on + SSLStaplingCache "shmcb:logs/stapling-cache(150000)" + SSLSessionTickets Off + + # Other security options. + # Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" + Header always set X-Frame-Options DENY + Header always set X-Content-Type-Options nosniff + + RewriteEngine On + RewriteCond %{HTTP:Upgrade} websocket [NC] + RewriteCond %{HTTP:Connection} upgrade [NC] + RewriteRule .* "ws://localhost:8443%{REQUEST_URI}" [P] RequestHeader set X-Forwarded-Proto https RequestHeader set X-Forwarded-Port 443 + ProxyRequests off ProxyPass / http://localhost:8443/ nocanon ProxyPassReverse / http://localhost:8443/ - - ``` - *Important:* For more details about Apache reverse proxy configuration checkout the [documentation](https://httpd.apache.org/docs/current/mod/mod_proxy.html) - especially the [Securing your Server](https://httpd.apache.org/docs/current/mod/mod_proxy.html#access) section + +``` - ### Help - Use `code-server --help` to view the usage for the CLI. This is also shown at the beginning of this section. +Make sure to set the `ProxyPass`, `ProxyPassReverse` and `RewriteRule` +directives to the actual address of your code-server instance and the +`ServerName` directive to the hostname of your website. If you're using SSL, +make sure to change the `SSLCertificateFile`, `SSLCertificateKeyFile`, and +`SSLCertificateChainFile` directives. If not, remove the HTTPS `IfModule` block +entirely. + +For more details about Apache reverse proxy configuration, check out the +[mod_proxy documentation](apache-mod_proxy). + +[apache-mod_proxy]: https://httpd.apache.org/docs/current/mod/mod_proxy.html From c94761f3120e0f2bf2a2c234d8106a82a18e7362 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 19 Aug 2019 21:12:04 +1000 Subject: [PATCH 07/11] Documentation changes --- doc/admin/install/aws.md | 2 +- doc/admin/install/digitalocean.md | 2 +- doc/admin/install/google_cloud.md | 10 +++++----- doc/self-hosted/cros-install.md | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/admin/install/aws.md b/doc/admin/install/aws.md index b38078fa..5112d356 100644 --- a/doc/admin/install/aws.md +++ b/doc/admin/install/aws.md @@ -113,4 +113,4 @@ code-server for you in the background as a service and restart it for you if it crashes. [security-guide]: ../../security/index.md -[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ +[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples diff --git a/doc/admin/install/digitalocean.md b/doc/admin/install/digitalocean.md index 0d758a7c..ae912b29 100644 --- a/doc/admin/install/digitalocean.md +++ b/doc/admin/install/digitalocean.md @@ -122,4 +122,4 @@ code-server for you in the background as a service and restart it for you if it crashes. (Note: this doesn't apply for users of the Marketplace Droplet image.) [security-guide]: ../../security/index.md -[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ +[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples diff --git a/doc/admin/install/google_cloud.md b/doc/admin/install/google_cloud.md index 2fa3caa7..2790a291 100644 --- a/doc/admin/install/google_cloud.md +++ b/doc/admin/install/google_cloud.md @@ -19,9 +19,6 @@ If you get stuck or need help at anytime, [file an issue](create-issue), ## Deploy to Google Cloud VM -> Pre-requisite: Please [set up Google Cloud SDK](gcloud-sdk) on your local -> machine. - [Open your Google Cloud console](create-instance) to create a new VM instance. 1. Click **Create Instance**. @@ -36,13 +33,15 @@ If you get stuck or need help at anytime, [file an issue](create-issue), `code-server`, and under **Protocols and ports** tick **Specified protocols and ports** and **tcp**. Beside **tcp**, add `8443`, then create the rule. -[gcloud-sdk]: https://cloud.google.com/sdk/docs/ [create-instance]: https://console.cloud.google.com/compute/instances --- ## Final Steps +Please [set up Google Cloud SDK](gcloud-sdk) on your local machine, or access +your instance terminal using another method. + 1. SSH into your Google Cloud VM: @@ -83,6 +82,7 @@ If you get stuck or need help at anytime, [file an issue](create-issue), Exception**, then finally **Confirm Security Exception**. +[gcloud-sdk]: https://cloud.google.com/sdk/docs/ [code-server-latest]: https://github.com/cdr/code-server/releases/latest --- @@ -98,4 +98,4 @@ code-server for you in the background as a service and restart it for you if it crashes. [security-guide]: ../../security/index.md -[systemd-guide]: https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/ +[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples diff --git a/doc/self-hosted/cros-install.md b/doc/self-hosted/cros-install.md index 623df2c4..b109b370 100644 --- a/doc/self-hosted/cros-install.md +++ b/doc/self-hosted/cros-install.md @@ -50,7 +50,7 @@ containers. +---------+---------+-----------------------+------+------------+-----------+ | penguin | RUNNING | 100.115.92.199 (eth0) | | PERSISTENT | 0 | +---------+---------+-----------------------+------+------------+-----------+ -(termina) chronos@localhost ~ $ +(termina) chronos@localhost ~ $ ``` For this example, we show the default `penguin` container, which is exposed on From 19541c27ff49edeb1d4c3cf7b4735fabf191e98e Mon Sep 17 00:00:00 2001 From: Paolo Mainardi Date: Sun, 18 Aug 2019 12:52:56 +0200 Subject: [PATCH 08/11] refs #914: Helm chart --- deployment/chart/Chart.yaml | 5 + deployment/chart/README.md | 115 ++++++++++++++ deployment/chart/templates/NOTES.txt | 25 +++ deployment/chart/templates/_helpers.tpl | 43 ++++++ deployment/chart/templates/deployment.yaml | 144 ++++++++++++++++++ deployment/chart/templates/ingress.yaml | 39 +++++ deployment/chart/templates/pvc.yaml | 29 ++++ deployment/chart/templates/secrets.yaml | 18 +++ deployment/chart/templates/service.yaml | 19 +++ .../chart/templates/serviceaccount.yaml | 11 ++ .../templates/tests/test-connection.yaml | 18 +++ deployment/chart/values.yaml | 135 ++++++++++++++++ .../{ => manifests}/aws/deployment.yaml | 0 deployment/{ => manifests}/deployment.yaml | 0 14 files changed, 601 insertions(+) create mode 100644 deployment/chart/Chart.yaml create mode 100644 deployment/chart/README.md create mode 100644 deployment/chart/templates/NOTES.txt create mode 100644 deployment/chart/templates/_helpers.tpl create mode 100644 deployment/chart/templates/deployment.yaml create mode 100644 deployment/chart/templates/ingress.yaml create mode 100644 deployment/chart/templates/pvc.yaml create mode 100644 deployment/chart/templates/secrets.yaml create mode 100644 deployment/chart/templates/service.yaml create mode 100644 deployment/chart/templates/serviceaccount.yaml create mode 100644 deployment/chart/templates/tests/test-connection.yaml create mode 100644 deployment/chart/values.yaml rename deployment/{ => manifests}/aws/deployment.yaml (100%) rename deployment/{ => manifests}/deployment.yaml (100%) diff --git a/deployment/chart/Chart.yaml b/deployment/chart/Chart.yaml new file mode 100644 index 00000000..283eea6d --- /dev/null +++ b/deployment/chart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for code-server +name: code-server +version: 1.0.0 diff --git a/deployment/chart/README.md b/deployment/chart/README.md new file mode 100644 index 00000000..34481eaf --- /dev/null +++ b/deployment/chart/README.md @@ -0,0 +1,115 @@ +# code-server + +[code-server](https://github.com/cdr/code-server) code-server is VS Code running +on a remote server, accessible through the browser. + +## TL;DR; + +```console +$ git clone https://github.com/cdr/code-server.git +$ helm install deployment/chart +``` + +## Introduction + +This chart bootstraps a code-server deployment on a +[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) +package manager. + +## Prerequisites + + - Kubernetes 1.6+ + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm install --name my-release deployment/chart +``` + +The command deploys code-server on the Kubernetes cluster in the default +configuration. The [configuration](#configuration) section lists the parameters +that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and +deletes the release. + +## Configuration + +The following table lists the configurable parameters of the nginx-ingress chart +and their default values. + + +The following table lists the configurable parameters of the code-server chart +and their default values. + +| Parameter | Description | Default | +| --------------------------------- | ------------------------------------------ | --------------------------------------------------------- | +| `image.registry` | Code-server image registry | `docker.io` | +| `image.repository` | Code-server Image name | `codercom/code-server` | +| `image.tag` | Code-server Image tag | `{TAG_NAME}` | +| `image.pullPolicy` | Code-server image pull policy | `IfNotPresent` | +| `nameOverride` | String to partially override code-server.fullname template with a string (will prepend the release name) | `nil` | +| `fullnameOverride` | String to fully override code-server.fullname template with a string | +| `hostnameOverride` | String to fully override code-server container hostname | +| `service.type` | Kubernetes Service type | `NodePort` | +| `service.port` | Service HTTP port | `8443` | +| `ingress.enabled` | Enable ingress controller resource | `false` | +| `ingress.hosts[0].name` | Hostname to your code-server installation | `code-server.local` | +| `ingress.hosts[0].path` | Path within the url structure | `/` | +| `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` | +| `ingress.hosts[0].certManager` | Add annotations for cert-manager | `false` | +| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `code-server.local-tls-secret` | +| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` | +| `ingress.secrets[0].name` | TLS Secret Name | `nil` | +| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | +| `ingress.secrets[0].key` | TLS Secret Key | `nil` | +| `extraArgs` | Additional code-server container arguments | `{}` | +| `extraVars` | Optional environment variables for code-server | `{}` | +| `volumePermissions.enabled` | Enable volume permissions init container | `true` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container | `0` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the container | `1000` | +| `securityContext.runAsUser` | User ID for the container | `1000` | +| `resources` | CPU/Memory resource requests/limits | `{}` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.storageClass` | PVC Storage Class for code-server volume | `nil` | +| `persistence.accessMode` | PVC Access Mode for code-server volume | `ReadWriteOnce` | +| `persistence.size` | PVC Storage Request for code-server volume | `8Gi` | +| `extraContainers` | Sidecar containers to add to the code-server pod | `{}` | +| `extraSecretMounts` | Additional code-server server secret mounts | `[]` | +| `extraVolumeMounts` | Additional code-server server volume mounts | `[]` | +| `extraConfigmapMounts` | Additional code-server server configMap volume mounts | `[]` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm +install`. For example, + +```console +$ helm install --name my-release \ + --set persistence.enabled=false \ + deployment/chart +``` + +The above command sets the the persistence storage to false. + +Alternatively, a YAML file that specifies the values for the above parameters +can be provided while installing the chart. For example, + +```console +$ helm install --name my-release -f values.yaml deployment/chart +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + diff --git a/deployment/chart/templates/NOTES.txt b/deployment/chart/templates/NOTES.txt new file mode 100644 index 00000000..e9af8599 --- /dev/null +++ b/deployment/chart/templates/NOTES.txt @@ -0,0 +1,25 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "code-server.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "code-server.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} + +Administrator credentials: + + Password : $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "code-server.fullname" . }} -o jsonpath="{.data.password}" | base64 --decode) diff --git a/deployment/chart/templates/_helpers.tpl b/deployment/chart/templates/_helpers.tpl new file mode 100644 index 00000000..811252b9 --- /dev/null +++ b/deployment/chart/templates/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "code-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "code-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "code-server.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "code-server.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "code-server.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/deployment/chart/templates/deployment.yaml b/deployment/chart/templates/deployment.yaml new file mode 100644 index 00000000..1d5ca900 --- /dev/null +++ b/deployment/chart/templates/deployment.yaml @@ -0,0 +1,144 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "code-server.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- if .Values.hostnameOverride }} + hostname: {{ .Values.hostnameOverride }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + {{- end }} + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + initContainers: + - name: init-chmod-data + image: busybox:latest + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + chown -R {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /home/coder + securityContext: + runAsUser: {{ .Values.volumePermissions.securityContext.runAsUser }} + volumeMounts: + - name: data + mountPath: /home/coder + {{- end }} + containers: +{{- if .Values.extraContainers }} +{{ toYaml .Values.extraContainers | indent 8}} +{{- end }} + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- end }} + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + {{- if .Values.existingSecret }} + name: {{ .Values.existingSecret }} + {{- else }} + name: {{ template "code-server.fullname" . }} + {{- end }} + key: password + {{- if .Values.extraVars }} +{{ toYaml .Values.extraVars | indent 12 }} + {{- end }} + {{- if .Values.extraArgs }} + args: +{{ toYaml .Values.extraArgs | indent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /home/coder/project + subPath: project + - name: data + mountPath: /home/coder/.local/share/code-server + subPath: code-server + {{- range .Values.extraConfigmapMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + subPath: {{ .subPath | default "" }} + readOnly: {{ .readOnly }} + {{- end }} + {{- range .Values.extraSecretMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: {{ .readOnly }} + {{- end }} + {{- range .Values.extraVolumeMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + subPath: {{ .subPath | default "" }} + readOnly: {{ .readOnly }} + {{- end }} + ports: + - name: http + containerPort: 8443 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "code-server.serviceAccountName" . }} + volumes: + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "code-server.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end -}} + {{- range .Values.extraSecretMounts }} + - name: {{ .name }} + secret: + secretName: {{ .secretName }} + defaultMode: {{ .defaultMode }} + {{- end }} + {{- range .Values.extraVolumeMounts }} + - name: {{ .name }} + persistentVolumeClaim: + claimName: {{ .existingClaim }} + {{- end }} diff --git a/deployment/chart/templates/ingress.yaml b/deployment/chart/templates/ingress.yaml new file mode 100644 index 00000000..1858bb5f --- /dev/null +++ b/deployment/chart/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "code-server.fullname" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: http + {{- end }} + {{- end }} +{{- end }} diff --git a/deployment/chart/templates/pvc.yaml b/deployment/chart/templates/pvc.yaml new file mode 100644 index 00000000..f2930147 --- /dev/null +++ b/deployment/chart/templates/pvc.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ include "code-server.fullname" . }} + namespace: {{ .Release.Namespace }} +{{- with .Values.persistence.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/deployment/chart/templates/secrets.yaml b/deployment/chart/templates/secrets.yaml new file mode 100644 index 00000000..6c600417 --- /dev/null +++ b/deployment/chart/templates/secrets.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "code-server.fullname" . }} + annotations: + "helm.sh/hook": "pre-install" + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +type: Opaque +data: + {{ if .Values.password }} + password: "{{ .Values.password | b64enc }}" + {{ else }} + password: "{{ randAlphaNum 24 | b64enc }}" + {{ end }} diff --git a/deployment/chart/templates/service.yaml b/deployment/chart/templates/service.yaml new file mode 100644 index 00000000..038b6cd0 --- /dev/null +++ b/deployment/chart/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "code-server.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "code-server.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/deployment/chart/templates/serviceaccount.yaml b/deployment/chart/templates/serviceaccount.yaml new file mode 100644 index 00000000..df9e1e37 --- /dev/null +++ b/deployment/chart/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if or .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + name: {{ template "code-server.serviceAccountName" . }} +{{- end -}} diff --git a/deployment/chart/templates/tests/test-connection.yaml b/deployment/chart/templates/tests/test-connection.yaml new file mode 100644 index 00000000..2e67f56e --- /dev/null +++ b/deployment/chart/templates/tests/test-connection.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "code-server.fullname" . }}-test-connection" + labels: + app.kubernetes.io/name: {{ include "code-server.name" . }} + helm.sh/chart: {{ include "code-server.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/deployment/chart/values.yaml b/deployment/chart/values.yaml new file mode 100644 index 00000000..102ef620 --- /dev/null +++ b/deployment/chart/values.yaml @@ -0,0 +1,135 @@ +# Default values for code-server. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: codercom/code-server + tag: 1.1156-vsc1.33.1 + pullPolicy: Always + +nameOverride: "" +fullnameOverride: "" +hostnameOverride: "" + +service: + type: NodePort + port: 8443 + +ingress: + enabled: false + #annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + #hosts: + # - host: code-server.example.loc + # paths: + # - / + + #tls: + # - secretName: code-server + # hosts: + # - code-server.example.loc + +# Optional additional arguments +extraArgs: [] +# - --allow-http +# - --no-auth + +# Optional additional environment variables +extraVars: [] +# - name: DISABLE_TELEMETRY +# value: true + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: true + securityContext: + runAsUser: 0 + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1000 + runAsUser: 1000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 1000Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +## Persist data to a persistent volume +persistence: + enabled: true + ## code-server data Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + # storageClass: "-" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + +serviceAccount: + create: true + name: + +## Enable an Specify container in extraContainers. +##Β This is meant to allow adding code-server dependencies, like docker-dind. +extraContainers: | +#- name: docker-dind +# image: docker:19.03-dind +# imagePullPolicy: IfNotPresent +# resources: +# requests: +# cpu: 250m +# memory: 256M +# securityContext: +# privileged: true +# procMount: Default +# env: +# - name: DOCKER_TLS_CERTDIR +# value: "" +# - name: DOCKER_DRIVER +# value: "overlay2" + +## Additional code-server secret mounts +extraSecretMounts: [] + # - name: secret-files + # mountPath: /etc/secrets + # secretName: code-server-secret-files + # readOnly: true + +## Additional code-server volume mounts +extraVolumeMounts: [] + # - name: extra-volume + # mountPath: /mnt/volume + # readOnly: true + # existingClaim: volume-claim + +extraConfigmapMounts: [] + # - name: certs-configmap + # mountPath: /etc/code-server/ssl/ + # subPath: certificates.crt # (optional) + # configMap: certs-configmap + # readOnly: true diff --git a/deployment/aws/deployment.yaml b/deployment/manifests/aws/deployment.yaml similarity index 100% rename from deployment/aws/deployment.yaml rename to deployment/manifests/aws/deployment.yaml diff --git a/deployment/deployment.yaml b/deployment/manifests/deployment.yaml similarity index 100% rename from deployment/deployment.yaml rename to deployment/manifests/deployment.yaml From 615948c73fd9eca56fe7672a77b5b4acd04f5411 Mon Sep 17 00:00:00 2001 From: Paolo Mainardi Date: Tue, 20 Aug 2019 15:00:59 +0200 Subject: [PATCH 09/11] refs #914: Fix identation for args and vars --- deployment/chart/templates/deployment.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/chart/templates/deployment.yaml b/deployment/chart/templates/deployment.yaml index 1d5ca900..63a84d61 100644 --- a/deployment/chart/templates/deployment.yaml +++ b/deployment/chart/templates/deployment.yaml @@ -56,6 +56,9 @@ spec: runAsUser: {{ .Values.securityContext.runAsUser }} {{- end }} env: + {{- if .Values.extraVars }} +{{ toYaml .Values.extraVars | indent 10 }} + {{- end }} - name: PASSWORD valueFrom: secretKeyRef: @@ -65,12 +68,9 @@ spec: name: {{ template "code-server.fullname" . }} {{- end }} key: password - {{- if .Values.extraVars }} -{{ toYaml .Values.extraVars | indent 12 }} - {{- end }} {{- if .Values.extraArgs }} args: -{{ toYaml .Values.extraArgs | indent 12 }} +{{ toYaml .Values.extraArgs | indent 10 }} {{- end }} volumeMounts: - name: data From 51a82655a925646a05a39a883c7b556fd8bc63d7 Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Thu, 12 Sep 2019 23:12:39 +0800 Subject: [PATCH 10/11] [README] Add volume flag for persisting configs (#969) Fixes GH-965 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94cc9dea..b372163e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Try it out: ```bash -docker run -it -p 127.0.0.1:8443:8443 -v "${PWD}:/home/coder/project" codercom/code-server --allow-http --no-auth +docker run -it -p 127.0.0.1:8443:8443 -v "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server" -v "${PWD}:/home/coder/project" codercom/code-server --allow-http --no-auth ``` - Code on your Chromebook, tablet, and laptop with a consistent dev environment. From 64cc2895f3e2c978ffa0b9b157174e7811fb9d45 Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Thu, 12 Sep 2019 23:27:22 +0800 Subject: [PATCH 11/11] [doc/self-hosted] make XFO same origin in docs (#970) As reported in GH-962, this breaks VSCode's extension details view. Might need further triage if its also a v2 internal issue. --- doc/self-hosted/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/self-hosted/index.md b/doc/self-hosted/index.md index 7e5bd458..de88e257 100644 --- a/doc/self-hosted/index.md +++ b/doc/self-hosted/index.md @@ -148,7 +148,7 @@ server { # real_ip_header CF-Connecting-IP; # Other security options. - add_header X-Frame-Options DENY; + add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block";