Skip to content

add: rstudio module #327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .icons/rstudio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added registry/coder/.images/rstudio-server.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions registry/coder/modules/rstudio-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
display_name: RStudio Server
description: A module that deploys Rocker Project distribution of RStudio Server in your Coder template.
icon: ../../../../.icons/rstudio.svg
verified: true
tags: [rstudio, ide, web]
---

# RStudio Server

A module that deploys Rocker Project distribution of RStudio Server in your Coder template.

![RStudio Server](../../.images/rstudio-server.png)

```tf
module "rstudio-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/rstudio-server/coder"
version = "0.9.0"
agent_id = coder_agent.example.id
}
```
123 changes: 123 additions & 0 deletions registry/coder/modules/rstudio-server/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
terraform {
required_version = ">= 1.0"

required_providers {
coder = {
source = "coder/coder"
version = ">= 2.5"
}
}
}

# Add required variables for your modules and remove any unneeded variables
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}

variable "docker_socket" {
type = string
description = "(Optional) Docker socket URI"
default = ""
}

variable "rstudio_server_version" {
type = string
description = "RStudio Server version"
default = "4.5.1"
}

variable "disable_auth" {
type = bool
description = "Disable auth"
default = false
}

variable "rstudio_user" {
type = string
description = "RStudio user"
default = "rstudio"
sensitive = true
}

variable "rstudio_password" {
type = string
description = "RStudio password"
default = "rstudio"
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a hardcoded default password 'rstudio' creates a security vulnerability as it's easily guessable. Consider generating a random password by default or requiring users to explicitly set this variable without providing a weak default.

Suggested change
default = "rstudio"

Copilot uses AI. Check for mistakes.

sensitive = true
}

variable "project_path" {
type = string
description = "The path to RStudio project, it will be mounted in the container."
default = null
}

variable "port" {
type = number
description = "The port to run rstudio-server on."
default = 8787
}

variable "enable_renv" {
type = bool
description = "If renv.lock exists, renv will restore the environment and install dependencies"
default = true
}

variable "renv_cache_volume" {
type = string
description = "The name of the volume used by Renv to preserve dependencies between container restarts"
default = "renv-cache-volume"
}

variable "share" {
type = string
default = "owner"
validation {
condition = var.share == "owner" || var.share == "authenticated" || var.share == "public"
error_message = "Incorrect value. Please set either 'owner', 'authenticated', or 'public'."
}
}

variable "order" {
type = number
description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
default = null
}

variable "group" {
type = string
description = "The name of a group that this app belongs to."
default = null
}

resource "coder_script" "rstudio-server" {
agent_id = var.agent_id
display_name = "rstudio-server"
icon = "/icon/rstudio.svg"
script = templatefile("${path.module}/run.sh", {
DOCKER_HOST : var.docker_socket,
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DOCKER_HOST environment variable is set but never used in the run.sh script. The script uses the default docker commands without specifying a custom socket. Either remove this variable or update the script to use DOCKER_HOST when provided.

Suggested change
DOCKER_HOST : var.docker_socket,

Copilot uses AI. Check for mistakes.

SERVER_VERSION : var.rstudio_server_version,
DISABLE_AUTH : var.disable_auth,
RSTUDIO_USER : var.rstudio_user,
RSTUDIO_PASSWORD : var.rstudio_password,
PROJECT_PATH : var.project_path,
PORT : var.port,
ENABLE_RENV : var.enable_renv,
RENV_CACHE_VOLUME : var.renv_cache_volume,
})
run_on_start = true
}

resource "coder_app" "rstudio-server" {
agent_id = var.agent_id
slug = "rstudio-server"
display_name = "RStudio Server"
url = "http://localhost:${var.port}"
icon = "/icon/rstudio.svg"
subdomain = true
share = var.share
order = var.order
group = var.group
}
58 changes: 58 additions & 0 deletions registry/coder/modules/rstudio-server/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env sh

set -eu

BOLD='\033[0;1m'
RESET='\033[0m'

printf "$${BOLD}Starting RStudio Server (Rocker)...$${RESET}\n"

# Wait for docker to become ready
max_attempts=10
delay=2
attempt=1

while ! docker ps; do
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docker readiness check only verifies that docker ps succeeds but doesn't handle potential authentication or permission issues. Consider redirecting stderr to /dev/null and adding a more specific check like docker ps > /dev/null 2>&1 to avoid cluttering output with error messages during the retry loop.

Suggested change
while ! docker ps; do
while ! docker ps > /dev/null 2>&1; do

Copilot uses AI. Check for mistakes.

if [ $attempt -ge $max_attempts ]; then
echo "Failed to list containers after $${max_attempts} attempts."
exit 1
fi
echo "Attempt $${attempt} failed, retrying in $${delay}s..."
sleep $delay
attempt=`expr "$attempt" + 1`
delay=`expr "$delay" \* 2` # exponential backoff
done


# Pull the specified version
IMAGE="rocker/rstudio:${SERVER_VERSION}"
docker pull "$${IMAGE}"

# Create (or reuse) a persistent renv cache volume
docker volume create "${RENV_CACHE_VOLUME}"

# Run container (auto-remove on stop)
docker run -d --rm \
--name rstudio-server \
-p "${PORT}:8787" \
-e DISABLE_AUTH="${DISABLE_AUTH}" \
-e USER="${RSTUDIO_USER}" \
-e PASSWORD="${RSTUDIO_PASSWORD}" \
-e RENV_PATHS_CACHE="/renv/cache" \
-v "${PROJECT_PATH}:/home/${RSTUDIO_USER}/project" \
-v "${RENV_CACHE_VOLUME}:/renv/cache" \
"$${IMAGE}"

# Make RENV_CACHE_VOLUME writable to USER
docker exec rstudio-server bash -c 'chmod -R 0777 /renv/cache'
Comment on lines +46 to +47
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting permissions to 0777 (world-writable) creates a security risk by allowing any user to modify the renv cache. Consider using more restrictive permissions like 0755 or 0775, or setting ownership to the specific user instead.

Suggested change
# Make RENV_CACHE_VOLUME writable to USER
docker exec rstudio-server bash -c 'chmod -R 0777 /renv/cache'
# Make RENV_CACHE_VOLUME owned and writable by USER (not world-writable)
docker exec rstudio-server bash -c 'chown -R "${RSTUDIO_USER}":"${RSTUDIO_USER}" /renv/cache && chmod -R 0775 /renv/cache'

Copilot uses AI. Check for mistakes.


# Optional renv restore
if [ "${ENABLE_RENV}" = "true" ] && [ -f "${PROJECT_PATH}/renv.lock" ]; then
echo "Restoring R environment via renv..."
docker exec -u "${RSTUDIO_USER}" rstudio-server R -q -e \
'if (!requireNamespace("renv", quietly = TRUE)) install.packages("renv", repos="https://cloud.r-project.org"); renv::restore(prompt = FALSE)'
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The R command execution lacks error handling. If the renv::restore() command fails, the script continues without indication of failure. Consider adding error checking or using set -e behavior by checking the exit code of the docker exec command.

Suggested change
'if (!requireNamespace("renv", quietly = TRUE)) install.packages("renv", repos="https://cloud.r-project.org"); renv::restore(prompt = FALSE)'
'if (!requireNamespace("renv", quietly = TRUE)) install.packages("renv", repos="https://cloud.r-project.org"); renv::restore(prompt = FALSE)'
if [ $? -ne 0 ]; then
echo "Error: renv::restore() failed inside the container."
exit 1
fi

Copilot uses AI. Check for mistakes.

fi

[ "${DISABLE_AUTH}" != "true" ] && echo "User: ${RSTUDIO_USER}"

printf "\n$${BOLD}RStudio Server ${SERVER_VERSION} is running on port ${PORT}$${RESET}\n"