Skip to main content

Recommendations

This guide helps administrators and security teams prepare Posit Connect deployments for production using recommendations drawn from common enterprise security reviews.

A secure deployment depends on your identity provider, network, host operating system, and package sources. Some recommendations rely on that infrastructure, so Connect cannot turn them on for you. Others are settings that Connect leaves off by default because they can block content, publishing workflows, or clients that some deployments rely on. Each recommendation describes what it restricts, so you can choose the controls that match your organization’s security policies and environment. Adapt the example repository URLs, server addresses, email addresses, and Linux user names to your deployment.

Posit delivers security fixes in new Connect releases, so start by keeping Connect up to date with the latest release. A release that is still within its support period does not receive security fixes published after it. Use the release notes and upgrade guidance to plan each upgrade. R, Python, Quarto, content packages, drivers, system libraries, and the host OS also receive security fixes, so update them on a regular schedule. Removing an old R or Python version can affect content that uses it, so plan for publishers to redeploy affected content. To find that content, search for content by runtime version, for example python:<3.10 or r:<4.2. To steer new content to newer versions, restrict publishable versions for R and Python.

Package management

Connect builds each content environment by installing the R and Python packages that the deployment requests. The following controls limit where those packages come from and what package installation can access. They apply only when Connect builds an environment, not to packages that content installs while it runs. They do not make package code trustworthy. See the R package management and Python package management guides for details.

Restrict package sources

By default, Connect installs packages from both your configured repositories and the repositories that published content specifies, so content deploys even before you configure any repositories. To install packages only from repositories you approve, use Posit Package Manager with curated CRAN and Python Package Index (PyPI) repositories. Configure strict repository resolution for both languages so Connect ignores repositories supplied with published content, and define your approved repositories:

/etc/rstudio-connect/rstudio-connect.gcfg
[R]
PackageRepositoryResolution = strict

[RPackageRepository "CRAN"]
URL = https://packagemanager.example.com/cran/latest

[Python]
PackageRepositoryResolution = strict

[PythonPackageRepository "PyPI"]
URL = https://packagemanager.example.com/pypi/latest/simple

Connect fails to start if you enable strict mode for a language without configuring a repository for it. The approved repositories must provide every package and version your content needs, or deployments fail. This includes the R and Python runtime dependencies that Connect installs during deployment. In strict mode, R content cannot change the resolution mode through its manifest.json file, as described in per-content repository resolution overrides.

For Python, the configured repositories replace the default index in the system installer configuration, but extra indexes and find-links locations remain active. Remove extra-index-url and find-links entries from /etc/pip.conf, and [[index]], extra-index-url, and find-links entries from /etc/uv/uv.toml, including those in its [pip] section, so installers use only your approved repositories. In strict mode, Connect ignores the installer environment variables that add a package source. See Additive installer settings for details.

Strict resolution applies only to packages installed from repositories. Content can still install packages from:

  • Git repositories, such as R packages from GitHub or Python git+ requirements.
  • Direct references in a requirements.txt file, such as URLs, local paths, and bundled source archives.

For Python, restrict installation to pre-built wheels to refuse Git requirements and direct references to source code. For R, install pre-built binary packages where Package Manager provides them. Connect has no setting that refuses R packages from Git repositories. To limit what Git dependencies can access, limit Git credentials during package restores.

Restrict Python installation to pre-built wheels

Installing a Python source distribution runs the package’s build code on the Connect server during the environment build. A malicious or compromised package can use that step to run arbitrary code with access to the build environment, including any credentials supplied to it. If you require Python installation from pre-built wheels, set Python.AllowSourceDistributions to false:

/etc/rstudio-connect/rstudio-connect.gcfg
[Python]
AllowSourceDistributions = false

Connect then also refuses requirements that the installer always builds from source, such as editable installs, git+ requirements, source archives, and URLs and local paths that point to source code. A direct reference to a .whl file still installs, whether it is a URL or a local path. Strict repository resolution does not apply to these references, so content can still install a wheel from any host it can reach.

Content fails to build when a dependency has no wheel for the Connect server’s platform and Python version. Pure-Python packages usually publish a universal wheel, such as py3-none-any, that works on any server. Packages with compiled code need a wheel built for the server’s platform, such as manylinux_2_28_x86_64, and Python version, such as cp312. To check a single package, review its list of files on PyPI or in Package Manager. To check a whole requirements.txt file, run pip download --only-binary=:all: --index-url https://packagemanager.example.com/pypi/latest/simple -r requirements.txt on a host with the same operating system and Python version as the Connect server, using your approved repository URL.

Environments built before you change the setting keep running, and the content’s next redeploy or rebuild fails if it requires a source build. See Restricting installation to pre-built wheels for the full list of refused requirements.

Install R packages as pre-built binaries

Installing an R source package runs the package’s build code, such as its configure script, on the Connect server during the environment restore. A malicious or compromised package can use that step to run arbitrary code with access to the restore environment, including any credentials supplied to it. Package Manager serves pre-built binary packages for supported Linux distributions, and installing a binary package does not run its build code. After Connect installs a binary package, it loads the package to confirm that the package works on the server, which runs the package’s load code during the restore.

If you require R installation from binary packages, set R.PositPackageManagerURLRewriting to force-binary and R.TestLoadBinaryPackages to false:

/etc/rstudio-connect/rstudio-connect.gcfg
[R]
PositPackageManagerURLRewriting = force-binary
TestLoadBinaryPackages = false

Connect then rewrites Package Manager repository URLs to serve binary packages for the server’s Linux distribution and skips the load test. Without the load test, a binary package that is incompatible with the server fails when content loads it rather than during deployment.

Connect has no setting that refuses R source packages. Connect still installs a package from source when Package Manager has no binary for that package or for the server’s Linux distribution, when the package comes from a Git repository, and when the package comes from a repository other than Package Manager. Use strict repository resolution so that content installs packages only from the Package Manager repositories you configure. See Posit Package Manager URL rewriting for details.

Limit Git credentials during package restores

When RestoreUsesGitCredentials is enabled, Connect supplies its configured GitCredential entries to every package restore, even for content without Git dependencies, so the installer can clone private repositories. Code that runs during the restore, such as package build scripts, can read those credentials. Connect uses the same credentials for Git-backed publishing, so they can grant access to more repositories than your dependencies need.

If content does not install packages from private Git repositories, disable Git restore credentials so that code running during package restores cannot read them:

/etc/rstudio-connect/rstudio-connect.gcfg
[R]
RestoreUsesGitCredentials = false

[Python]
RestoreUsesGitCredentials = false

These settings do not affect Git-backed publishing. Content with private Git dependencies fails to build without restore credentials. To provide private packages without Git credentials, publish them to Package Manager. If content must install packages from Git, limit the credentials to read access for the repositories that package restores and Git-backed publishing require.

Limit access to authenticated repositories

If you use authenticated Package Manager repositories, restrict the integration’s access control list and scopes field to the publishers and repositories that need them.

Authentication and authorization

Use your identity provider

Integrate with your organization’s identity provider (LDAP, SAML, or OpenID Connect) rather than relying on the Connect built-in password authentication. Your identity provider can then apply your organization’s password, multi-factor authentication, and account-deactivation policies to Connect sign-ins.

If your identity provider supports System for Cross-domain Identity Management (SCIM), enable it so that changes in your identity provider update Connect users and groups automatically. When the identity provider deactivates a user, SCIM locks the user’s Connect account. Content that the locked user owns remains available, and their scheduled reports continue to run. For SAML authentication, use the following setting:

/etc/rstudio-connect/rstudio-connect.gcfg
[SAML]
EnableSCIM = true

For OpenID Connect authentication, use the following setting:

/etc/rstudio-connect/rstudio-connect.gcfg
[OAuth2]
EnableSCIM = true

Control account creation

By default, Connect creates an account the first time any user that your authentication provider admits signs in. To limit who gets an account, restrict which users your identity provider admits to Connect. If you require administrator-controlled account creation, set RegisterOnFirstLogin to false in your provider’s configuration section, such as [SAML] or [OAuth2]:

/etc/rstudio-connect/rstudio-connect.gcfg
[SAML]
RegisterOnFirstLogin = false

Administrators must then create each account before that user can sign in. If you enable SCIM, your identity provider creates accounts for the users you assign to Connect, so those assignments control who can sign in. Without SCIM, administrators create accounts through the Connect Server API.

With built-in password authentication, Connect disables self-registration by default, so confirm that your configuration does not set Password.SelfRegistration to true. Connect always allows anyone to create the first password account, which becomes the initial administrator, even when self-registration is disabled. Create that administrator account before you expose the server to users. See password provisioning.

Restrict profile editing

By default, users can edit their own name and email address unless your authentication provider supplies them. When administrators create accounts, users can then change the details that administrators assigned. If you require administrator-managed profiles, set Authorization.UserInfoEditableBy to Admin:

/etc/rstudio-connect/rstudio-connect.gcfg
[Authorization]
UserInfoEditableBy = Admin

Users then cannot correct their own profile details and must ask an administrator. Details that your authentication provider supplies still update when the user signs in.

Limit account-directory visibility

On a new installation, the Viewer role lacks the users:read and groups:read permissions, so viewers cannot browse the list of Connect users and groups. Publishers and administrators can browse it, including names and email addresses.

An upgrade keeps the Viewer role’s existing permissions, so check them on the People > Roles page. Revoke the Viewer role’s users:read and groups:read permissions to limit Viewer access to other users and groups. The Viewer role holds users:read, and you cannot revoke it, while current user execution uses the Connect nameservice.

To hide other users’ email addresses from non-administrators, revoke the users:read-email permission from the Viewer role, then from the Publisher role.

Limiting account-directory visibility makes it harder for users to find people to share content with. It does not change content authorization.

Apply least privilege

Publishers deploy code that runs on the Connect server, and administrators manage users, content, and server settings. Grant the Publisher and Administrator roles only to people who need them, and review role assignments periodically. Viewers can request Publisher permissions from the dashboard, so review those requests against the same standard. See user roles for each role’s capabilities.

Require Git-backed or trusted publishing

To trace every deployment to a source repository or CI/CD workflow, require Git-backed publishing or trusted publishing. Git-backed content requires Connect to reach each repository, and private repositories require Git credentials. Revoke the bundles:upload permission from the Publisher role, as described in Customizing user roles.

Publishers can then no longer deploy by uploading bundles themselves, including push-button publishing from an IDE, command-line tools such as rsconnect, and CI/CD pipelines that authenticate with an API key. Trusted publishers can still upload bundles to the content items they’re bound to. To block a workload, remove its trusted publisher from the content item. To block all trusted publishing, disable trusted publishing on the server.

Limit session duration

Connect ends idle and long-lived sessions by default, with limits that balance security and convenience for most deployments. If your organization’s session policy requires shorter limits, set Authentication.Inactivity and Authentication.Lifetime to match it. For example, a policy can require a 30-minute inactivity limit and a 12-hour maximum lifetime:

/etc/rstudio-connect/rstudio-connect.gcfg
[Authentication]
Inactivity = 30m
Lifetime = 12h

Shorter limits reduce unattended browser access but interrupt interactive work and require users to sign in more often. See Limit session lifetime for the default limits.

Encryption and TLS

Serve Connect over HTTPS

HTTPS encrypts passwords, session cookies, API keys, and content traffic between clients and Connect. Always serve Connect over HTTPS in production, using a certificate from a trusted certificate authority. See Configuring SSL certificates for setup instructions.

Terminate TLS either at Connect itself or at a reverse proxy. If the proxy terminates TLS, configure Connect to generate HTTPS URLs and secure cookies, as described in Terminate TLS at a proxy.

Require TLS 1.2 or later

By default, Connect accepts TLS 1.0 and 1.1, which have known weaknesses, so that older clients can connect. After you confirm that your clients support TLS 1.2, set HTTPS.MinimumTLS to 1.2 or later:

/etc/rstudio-connect/rstudio-connect.gcfg
[HTTPS]
MinimumTLS = 1.2

Clients that support only TLS 1.0 or 1.1 can then no longer connect. See Set the minimum TLS version for client compatibility and proxy configuration.

Enable HTTP Strict Transport Security

HTTP Strict Transport Security (HSTS) tells browsers to connect to Connect only over HTTPS, so they cannot fall back to plain HTTP after their first visit. How you enable it depends on where TLS terminates.

If Connect terminates TLS and you will always serve Connect over HTTPS with a valid certificate, set HTTPS.Permanent to true:

/etc/rstudio-connect/rstudio-connect.gcfg
[HTTPS]
Permanent = true

Browsers that visit the server then refuse plain HTTP for the HSTS max-age period, so users cannot reach Connect if you later serve it without a valid certificate. See Require HTTPS permanently for what else the setting changes.

If a proxy terminates TLS, do not set HTTPS.Permanent. Connect fails to start if you enable the setting without an HTTPS listener. The HTTP.ForceSecure setting from Terminate TLS at a proxy already adds the HSTS header.

Network

Limit inbound traffic

Expose only the ports that users and administrators need, typically 443 for HTTPS and 22 for Secure Shell (SSH) management. Use a firewall or security group to block all other ports from outside the trusted network.

Use a reverse proxy

Place a reverse proxy (such as NGINX or Apache) in front of Connect rather than exposing Connect directly. The proxy gives you one place to terminate TLS and apply your organization’s network controls, such as request filtering and IP allow lists. Block direct access to the Connect default port (3939) so that every request passes through the proxy.

Use a dedicated server

Run Connect on a dedicated server so that content cannot reach the data or processes of other services on the same host.

Secrets management

Protect the encryption key

Connect uses its encryption key to encrypt sensitive data at rest, including application environment variables and encrypted configuration properties. Anyone who can read the key and Connect’s data can decrypt those values. Ensure the key file has 0600 permissions.

Back up the key securely and separately from Connect’s data. If you lose the key, Connect cannot decrypt the values it protects. See Troubleshooting key mismatch error.

Restrict file permissions

Ensure the Connect license file has 0600 permissions, readable only by the Connect service account. Restrict filesystem permissions so the Connect service account only has access to the directories it needs, such as Server.DataDir, Database.Dir, Server.TempDir, /etc/rstudio-connect/, and any directories the RunAs user needs.

Keep credentials out of content source code

Credentials in source code reach everyone who can read the code, its bundles, or its Git history. Encourage publishers to store credentials as environment variables set through the Connect dashboard or API instead.

For databases and external APIs, encourage publishers to use service account, viewer, or Workload Identity integrations. Integrations obtain tokens from an identity provider, so content does not need stored passwords or long-lived keys. Administrators must configure these integrations before publishers can use them.

Observability

Export telemetry with OpenTelemetry

Metrics, traces, and logs help you detect unusual load, resource usage, and errors before they affect users. Connect exports them through OpenTelemetry to any observability platform that accepts the OpenTelemetry Protocol (OTLP). To set it up, follow Getting started with OpenTelemetry. When the receiver runs on another host, use an HTTPS endpoint and configure authentication tokens with EncryptedHeader rather than Header, which Connect stores as plaintext. See the OpenTelemetry operational guide for what to monitor and the alerting recommendations for alert thresholds.

Monitor the audit log

Connect records audit events, such as sign-ins, failed sign-in attempts, and administrative changes, in its database. To send them to your Security Information and Event Management (SIEM) or log management system, also write them to a JSON file and forward it with your log collection agent:

/etc/rstudio-connect/rstudio-connect.gcfg
[Logging]
AuditLog = /var/log/rstudio/rstudio-connect/rstudio-connect.audit.log
AuditLogFormat = JSON

The file duplicates the database records and uses disk space on each server. In a clustered installation, collect the file from every server. Restrict access to the collected logs and protect them from unauthorized changes. See Auditing for output options, the list of audited events, and the audit log API.

User isolation

Separate untrusted publishers

Within one deployment, content from every publisher shares the host or cluster, the RunAs account, cached environments, and network access. Package curation and off-host (Kubernetes) execution reduce some risks but do not isolate publishers from each other.

If you require separation between mutually untrusted publishers, use separate Connect deployments with independent hosts, writable storage, and credentials. Separate deployments add infrastructure and administration costs.

Keep content on an unprivileged account

Connect runs content as the unprivileged rstudio-connect account by default and never runs deployed code as root. If you change Applications.RunAs, use another unprivileged account that can access only the files content needs. Do not grant the RunAs account sudo access or membership in privileged groups.

Publishers cannot override the RunAs account for their content unless you grant the content:update-runas permission, as described in Customizing user roles. Grant it only to publishers who need per-content accounts. See Unix accounts and process execution.

Public-facing servers

Connect servers that serve content on the open internet need the following additional configuration.

Public access requirements

Unless your license includes unrestricted public access, Connect periodically verifies that content set to “Anyone - no login required” is reachable from the public internet. For this public access verification to work:

  • Allow Connect outbound access to the URL validation server at https://verify.pct.posit.co/url-validator on port 443.

  • Make sure no proxy edits or removes the X-Content-Signature and Date HTTP headers, because the URL validation server requires them.

  • Set Server.Address to the server’s publicly accessible URL.

    /etc/rstudio-connect/rstudio-connect.gcfg
    [Server]
    Address = https://connect.example.com

Additional hardening

Protect sign-in with CAPTCHA

A Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA) slows brute-force and dictionary attacks on the sign-in form. Enable it on a public server that uses Pluggable Authentication Modules (PAM), LDAP, or built-in password authentication:

/etc/rstudio-connect/rstudio-connect.gcfg
[Authentication]
ChallengeResponseEnabled = true

Users then solve a visual or audio challenge each time they sign in with a user name and password. See Protect sign-in from brute-force and dictionary attacks.

Hide the server name

To stop the Server HTTP header from telling automated scanners which software to target, set Server.ServerName to a generic name:

/etc/rstudio-connect/rstudio-connect.gcfg
[Server]
ServerName = Web

The default header, Posit Connect, never includes the version or build, so a generic name only makes automated fingerprinting harder. It does not hide Connect from anyone who visits the site. See Server header.

Next steps

Security is an ongoing practice rather than a one-time configuration. Revisit these recommendations when you upgrade Connect, change your identity provider or network, or onboard new groups of publishers. Review role assignments, audit events, and telemetry on a regular schedule so you notice changes before they become problems. If your security review raises a question these recommendations do not answer, contact Posit Support.