Authenticated Web VSCode Server
Authenticated web vscode server with Pritunl Zero and Coder Server
This script will create an authenticated Visual Studio code web server with Pritunl Zero allowing for secure access to a vscode editor running in the browser. It can be used on any RHEL9 distribution such as AlmaLinux 9 or Oracle Linux 9 . For other distributions the commands will need to be adjusted. The Coder VS Code Server provides a server to run vscode in the web browser. This script will run this server on the localhost then install and configure Pritunl Zero to provided secure and authenticated access to the web vscode. Additional users can be added to provide a self hosted vscode server for collaborating or sharing code between systems.
First create a server with either a public IPv4 or IPv6 address. If the server is only running on a private network refer to the next section on how to create the Lets Encrypt certificate using DNS CNAME verification. This script will use HTTP verification on port 80 on both the domains configured below.
Before starting the installation configure two domains the ZERO_DOMAIN
for the Pritunl Zero administrator console and the CODER_DOMAIN
for the web vscode domain. Both of these domains should have A or AAAA records for the IPv4 and IPv6 address of the Pritunl Zero server. The ROOT_DOMAIN
is used if WebAuthn tokens are configured, this domain controls the scope of those token validations, it's best to use the highest level domain to allow the tokens to function across multiple sub-domains. A DNS record does not need to be created or modified for the ROOT_DOMAIN
.
This script will store all data in the persistent paths /var/lib/mongo
and /var/lib/coder
. These are the only two paths that need to be maintained when re-initializing the system.
Once the script is completed it will display the default password. This can then be used to login to the admin domain or vscode domain. Open the /logout
path in the vscode domain from the browser URL input to logout.
#!/bin/bash
# persistent paths: /var/lib/mongo /var/lib/coder
set -e
ROOT_DOMAIN="pritunl.demo"
ZERO_DOMAIN="zero.pritunl.demo"
CODER_DOMAIN="coder.pritunl.demo"
get_node_id() {
if [ $# -eq 0 ]; then
echo "Error: File path is required" >&2
echo "Usage: get_node_id <node_id_file_path>" >&2
return 1
fi
local node_id_file="$1"
local node_id
sudo mkdir -p "$(dirname "$node_id_file")"
if [ -f "$node_id_file" ]; then
node_id=$(cat "$node_id_file")
else
node_id=$(echo -n $(printf "%08x" $(date +%s))$(hexdump -n 8 -e '4/4 "%08x" 1 "\n"' /dev/urandom))
echo "$node_id" | sudo tee "$node_id_file" > /dev/null
sudo chmod 444 "$node_id_file"
fi
echo "$node_id"
}
sudo dnf -y update
sudo setenforce 0
sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config
sudo systemctl disable --now firewalld.service
sudo dnf -y install dnf-automatic
sudo sed -i 's/^upgrade_type =.*/upgrade_type = default/g' /etc/dnf/automatic.conf
sudo sed -i 's/^download_updates =.*/download_updates = yes/g' /etc/dnf/automatic.conf
sudo sed -i 's/^apply_updates =.*/apply_updates = yes/g' /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer
sudo tee /etc/yum.repos.d/pritunl.repo << EOF
[pritunl]
name=Pritunl Repository
baseurl=https://repo.pritunl.com/stable/yum/oraclelinux/9/
gpgcheck=1
enabled=1
gpgkey=https://raw.githubusercontent.com/pritunl/pgp/master/pritunl_repo_pub.asc
EOF
sudo tee /etc/yum.repos.d/mongodb-org.repo << EOF
[mongodb-org]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-8.0.asc
EOF
sudo dnf -y install pritunl-zero mongodb-org
sudo systemctl enable --now mongod
NODE_ID=$(get_node_id "/var/lib/mongo/node_id")
sudo tee /etc/pritunl-zero.json << EOF
{
"mongo_uri": "mongodb://localhost:27017/pritunl-zero",
"node_id": "$NODE_ID"
}
EOF
sudo chmod 600 /etc/pritunl-zero.json
sudo dnf -y group install -y "Development Tools"
sudo dnf -y module install nodejs:20
sudo useradd -r -s /sbin/nologin coder
sudo mkdir -p /home/coder
sudo chown coder:coder /home/coder
sudo chmod 700 /home/coder
sudo mkdir -p /var/lib/coder
sudo chown coder:coder /var/lib/coder
sudo chmod 700 /var/lib/coder
sudo mkdir -p /var/lib/coder/local
sudo chown coder:coder /var/lib/coder/local
sudo mkdir -p /var/lib/coder/config
sudo chown coder:coder /var/lib/coder/config
sudo mkdir -p /var/lib/coder/data
sudo chown coder:coder /var/lib/coder/data
sudo ln -snf /var/lib/coder/local /home/coder/.local
sudo chown coder:coder /home/coder/.local
sudo ln -snf /var/lib/coder/config /home/coder/.config
sudo chown coder:coder /home/coder/.config
sudo ln -snf /var/lib/coder/data /home/coder/data
sudo chown coder:coder /home/coder/data
sudo mkdir -p /home/coder/.config/code-server
sudo chown coder:coder /home/coder/.config/code-server
sudo tee /home/coder/.config/code-server/config.yaml << EOF
bind-addr: 127.0.0.1:8000
auth: none
cert: false
EOF
sudo chown coder:coder /home/coder/.config/code-server/config.yaml
sudo -u coder bash -c "cd /home/coder; npm install code-server"
sudo tee /etc/systemd/system/coder.service << EOF
[Service]
User=coder
Group=coder
WorkingDirectory=/home/coder
ExecStart=/home/coder/node_modules/.bin/code-server
TimeoutStopSec=5s
LimitNOFILE=500000
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
ProtectHostname=true
ProtectKernelTunables=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now pritunl-zero
sudo systemctl enable --now coder
sudo pritunl-zero upsert service --name=coder --type=http --role=coder --domain="$CODER_DOMAIN" --server="http://127.0.0.1:8000" --share-session=true --websockets=true --logout-path="/logout"
sudo pritunl-zero upsert certificate --name=pritunl-cert --type=lets_encrypt --acme-domain=$ZERO_DOMAIN --acme-domain=$CODER_DOMAIN --acme-type=http
sudo pritunl-zero upsert node --name=self --mangement=true --proxy=true --management-domain=$ZERO_DOMAIN --webauthn-domain=$ROOT_DOMAIN --add-certificate=pritunl-cert --add-service=coder
sudo pritunl-zero upsert policy --name=pritunl-zero --role=coder --add-service=coder
sudo pritunl-zero upsert user --name=pritunl --role=coder
sudo pritunl-zero default-password
DNS CNAME Verification
Lets Encrypt DNS CNAME verification can be used if the server is going to run on a private network or is configured so that the Lets Encrypt servers are unable to access port 80 on the Pritunl Zero server. To do this replace the last section of the script above with the commands below. This example uses Cloudflare but AWS Router 53 and Oracle Cloud DNS are also supported. Set CLOUDFLARE_SECRET
to the Cloudflare token to access the DNS API for that domain zone. This will allow the Pritunl Zero server to create CNAME records to complete the Lets Encrypt certificate verification.
CLOUDFLARE_SECRET="TOKEN"
sudo pritunl-zero upsert service --name=coder --type=http --role=coder --domain="$CODER_DOMAIN" --server="http://127.0.0.1:8000" --share-session=true --websockets=true --logout-path="/logout"
sudo pritunl-zero upsert secret --name=pritunl-dns --type=cloudflare --cloudflare-token=$CLOUDFLARE_SECRET
sudo pritunl-zero upsert certificate --name=pritunl-cert --type=lets_encrypt --acme-domain=$ZERO_DOMAIN --acme-domain=$CODER_DOMAIN --acme-type=dns --acme-api=cloudflare --acme-secret=pritunl-dns
sudo pritunl-zero upsert node --name=self --mangement=true --proxy=true --management-domain=$ZERO_DOMAIN --webauthn-domain=$ROOT_DOMAIN --add-certificate=pritunl-cert --add-service=coder
sudo pritunl-zero upsert policy --name=pritunl-zero --role=coder --add-service=coder
sudo pritunl-zero upsert user --name=pritunl --role=coder
sudo pritunl-zero default-password
Updated about 4 hours ago