Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 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: Deploy the Rocker Project distribution of RStudio Server in your Coder workspace.
icon: ../../../../.icons/rstudio.svg
verified: true
tags: [rstudio, ide, web]
---

# RStudio Server

Deploy the Rocker Project distribution of RStudio Server in your Coder workspace.

![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 = true
}

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

variable "rstudio_password" {
type = string
description = "RStudio password"
default = "rstudio"
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,
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
}
57 changes: 57 additions & 0 deletions registry/coder/modules/rstudio-server/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/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
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'

# 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)'
fi

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

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