Deploying NOAH GPCR in Docker: Pitfalls from DSSP Dependency Conflicts to NVIDIA GPU and Network Proxies
·(edited)· / , , , · reads0AI-written
This article was generated entirely by AI without human authorship. Please read with discretion, or have an AI verify its accuracy.
AI TranslationSimplified ChineseEnglish
Key Insights
The author deployed NOAH, Kojima et al.'s GPCR structure analysis tool, and documented the troubleshooting experience. Build failures traced back to DSSP/libmcfp version incompatibility—both need pinned versions and a simultaneous install. A GPU visible on the host doesn't mean Docker can use it; the NVIDIA Container Toolkit must be configured. Proxy settings must be passed explicitly via --build-arg at build time. The README lacks sufficient parameter documentation; key parameters and output locations need to be documented. License restrictions prevent public distribution of modified versions. Bottom line: pin dependency versions, keep driver-level and container-level GPU layers distinct, and configure network proxies at the appropriate layer—only then do you get a stable, reproducible workflow.
Intro
Yesterday I happened to read a paper by Kojima et al. just published in Nature Structural & Molecular Biology, titled Universal pipeline for high-resolution GPCR structure determination. The article zeroes in on a very practical problem in GPCR structure determination: inactive-state GPCRs — especially the antagonist-bound state — often lack a stabilizing binding partner such as a G protein, so you usually have to try different fusion positions in the TM5-ICL3-TM6 region over and over before finding a construct whose expression, stability, and rigidity are sufficient to support high-resolution cryo-EM reconstruction, which makes the experimental screening expensive.
The authors' solution consists of two complementary parts. NOAH first enumerates TM5-TM6 fusion constructs and predicts their structures with ColabFold, then checks in order whether the linker stays a continuous α-helix, the local pLDDT, the helix phase, and the distance between the fusion protein and the membrane boundary, narrowing a few hundred combinations down to a handful of candidates that are more worth validating experimentally. They then designed ARK1, a ~40 kDa de novo fusion partner with higher rigidity, as a fiducial marker to help cryo-EM particle alignment, and validated it across multiple Class A GPCRs and different ligand states.
This is not a push-a-button route to experimental structures — expression, purification, grid preparation, and cryo-EM are still required afterward, and the systematic validation so far is mostly limited to Class A GPCRs. Even so, for projects working on inactive-state GPCRs or antagonist complexes, or ones that have been stuck on fusion-construct screening for a long time, it could remove a good part of the upfront trial and error. So I decided to reproduce NOAH's computational pipeline first and see whether it can help my own or neighboring projects; this post records the problems encountered during deployment.
As a first step, I tried deploying NOAH on a Linux server with an NVIDIA GPU. NOAH orchestrates GPCRdb data, DSSP, PPM3, and ColabFold to screen candidate constructs. The project already ships a Dockerfile, and it looks like just three commands get it started:
BASH
git clone https://github.com/hekato-lab/noah_gpcr
cd noah_gpcr
docker build -t noah_gpcr .
The actual deployment was far less smooth. One after another, I hit DSSP dependency incompatibilities, Docker failing to use the NVIDIA GPU, unstable access to external resources from the server, and underdocumented runtime parameters. This post records the complete debugging process and the deployment method that ultimately worked and can be reused.
NOAH's current LICENSE only permits non-commercial research and educational use and explicitly forbids redistributing the code to third parties, in original or modified form, including uploading it to a public GitHub repository. I therefore can't share the modified content publicly; what this post shares is the deployment approach and the troubleshooting experience. If you run into similar problems, you can hand this post to an AI as context, and it should make your deployment smoother.
1. Build failure: unstable DSSP and libmcfp version combinations
The first time I ran docker build, the problem was in the DSSP environment: mkdssp and dssp could be found but wouldn't run correctly during version checks or when invoked by Biopython. In other words, the problem wasn't “DSSP not installed” — it was that the binary interface between DSSP and the underlying libmcfp was incompatible.
The original Dockerfile first creates NOAH's Conda environment and installs DSSP, then separately installs gsutil. The two independent Conda solves can update indirect dependencies that were already installed. At the same time, the original PATH puts the ColabFold environment ahead of the NOAH environment, which also increases the risk of calling programs or dynamic libraries from the wrong environment.
In the end, the fix had four parts:
Put dssp, libmcfp and gsutil into a single Conda solve.
Pin versions verified to be compatible: dssp=4.6.1, libmcfp=2.0.1.
Put the NOAH environment ahead of the ColabFold environment.
During the image build stage, run mkdssp --version and dssp --version, letting errors surface early instead of failing only after NOAH has been running for a long time.
2. Seeing the GPU on the host doesn't mean Docker can use it
The second problem was at the GPU layer. nvidia-smi running normally on the server only proves the NVIDIA driver is working; for Docker to expose the GPU to a container, you also need to install and configure the NVIDIA Container Toolkit.
You can first check which runtimes Docker currently knows about:
BASH
nvidia-smi
docker info | grep -i runtime
On Ubuntu or Debian, I followed the official NVIDIA Container Toolkit installation documentation to complete the setup. The version number below is the one listed in the official docs as of 2026-08-30: 1.20.0-1; for future deployments, first confirm the current version on the official page.
nvidia-ctk runtime configure modifies the host's /etc/docker/daemon.json, so Docker can invoke the NVIDIA runtime. After configuring, don't just look at docker info — actually start a temporary container to verify. NVIDIA's official test command is:
BASH
sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi
Only when this command prints GPU information inside the container is the GPU runtime truly configured. The corresponding official verification is described in Running a Sample Workload.
3. Passing a proxy into the Docker build
NOAH's image build needs to reach external services such as Conda, PyPI, GitHub, and Google Cloud Storage. When the server's network is restricted, you can first set the proxy in a terminal on the host:
These export commands only set the proxy for the current host shell and the regular processes it launches, which fixes network access for commands like git clone on the host. However, Docker doesn't automatically pass these environment variables into the Dockerfile's RUN environment during image builds. So you may see this: the host can clone the repository fine, but docker build's wget, Conda, pip, or gsutil still time out.
So when running the build, you also need to explicitly pass the proxy via --build-arg:
Here, $http_proxy, $https_proxy and $all_proxy are taken from the host's current shell and then passed by --build-arg to the build environment. Just replace the placeholders with your own proxy addresses. Docker already predefines HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and other proxy build arguments, so there's no need to add a permanent ENV; otherwise the proxy address may end up baked into the image configuration. See the Docker CLI proxy documentation for details.
4. Supplementing the README
The original README gives the minimal commands but doesn't systematically explain which parameters are required, what the defaults are, or where results are written. Copying the commands verbatim raises several questions: what happens if you don't pass -m? Is -f required? Does --reverse enable or disable reverse screening? You might not even know these parameters exist.
GPCR name; in database mode it must match the database directory name, e.g., v2r.
-p, --ppm
Yes
None
PPM3 code directory, which should contain immers.
-d, --database
Conditional
None
NOAH/GPCRdb database directory; when not using a database, provide both -s and -j.
-s, --structure
Conditional
None
Custom GPCR PDB structure.
-j, --json
Conditional
None
Residue annotations in GPCRdb residues/extended format.
-m, --mode
No
Inactive
Conformation state; only accepts Active or Inactive.
-f, --fp
No
ARK1
Fusion protein; options are ARK1, BRIL, or A2A_BRIL.
-r, --reverse
No
Reverse screening by default
The name is misleading: passing this option actually turns off the reverse helix-phase screening.
Another key point: NOAH has no separate --output parameter; results are written to the current working directory. Different targets, conformations, or fusion proteins should each use a different empty directory; rerunning directly in an existing results directory can fail because some files are created in exclusive mode.
Therefore, I recommend putting the target, conformation, and fusion protein into RUN_ID and explicitly passing -m and -f, instead of relying on the defaults:
Here I use --gpus device=0, exposing only GPU 0 to the container. It's more direct than “exposing all GPUs and then setting CUDA_VISIBLE_DEVICES=0”. Docker's official guidance on specifying GPUs is in GPU access.
Currently, NOAH calls ColabFold one construct at a time, so it won't automatically get near-linear speedup just because the server has multiple GPUs and the command uses --gpus all. If you haven't modified the scheduling logic yourself, allocating a single GPU per task is usually cleaner and makes it easy to spread different tasks across different GPUs.
Once the task is started in the background, you can check progress like this:
BASH
docker logs -f noah_v2r_ark1
nvidia-smi -l 2
5. Why the modified repository isn't public
To keep later users from repeating the same pitfalls, I organized the Docker dependency locking and README parameter documentation, and even committed the changes to my personal fork. However, NOAH's project license explicitly restricts code redistribution and specifically mentions that neither the original nor a modified version may be uploaded to a public GitHub repository. Although GitHub's platform terms have separate provisions for native forks of public repositories, to avoid any conflict in license interpretation and to respect the usage boundaries the authors expressed, I decided not to distribute the modified repository publicly and to keep these changes only in my own internal, non-commercial research environment.
Therefore, this post only shares the deployment process and troubleshooting ideas, without a link to the modified repository. Readers should obtain the code from the original repository and comply with its license; if you need to publish a modified version, distribute it to third parties, or use it commercially, obtain the authors' explicit permission first.
Summary
This NOAH deployment ultimately boils down to four lessons:
Don't fully rely on Conda's dynamic solving for research images; pin verified version combinations for critical binaries and underlying libraries.
Host drivers, Docker Engine, and the NVIDIA Container Toolkit are three distinct layers; nvidia-smi running normally doesn't mean the container can use the GPU.
For network failures, distinguish the three layers — host, Docker daemon, and build container — and configure the proxy at the layer that actually makes the requests.
NOAH's core idea is valuable, but to turn it into a stable, reproducible server workflow, environment locking, GPU runtime, network configuration, and runtime documentation are all indispensable.
Intro
Yesterday I happened to read a paper by Kojima et al. just published in Nature Structural & Molecular Biology, titled Universal pipeline for high-resolution GPCR structure determination. The article zeroes in on a very practical problem in GPCR structure determination: inactive-state GPCRs — especially the antagonist-bound state — often lack a stabilizing binding partner such as a G protein, so you usually have to try different fusion positions in the TM5-ICL3-TM6 region over and over before finding a construct whose expression, stability, and rigidity are sufficient to support high-resolution cryo-EM reconstruction, which makes the experimental screening expensive.
The authors' solution consists of two complementary parts. NOAH first enumerates TM5-TM6 fusion constructs and predicts their structures with ColabFold, then checks in order whether the linker stays a continuous α-helix, the local pLDDT, the helix phase, and the distance between the fusion protein and the membrane boundary, narrowing a few hundred combinations down to a handful of candidates that are more worth validating experimentally. They then designed ARK1, a ~40 kDa de novo fusion partner with higher rigidity, as a fiducial marker to help cryo-EM particle alignment, and validated it across multiple Class A GPCRs and different ligand states.
This is not a push-a-button route to experimental structures — expression, purification, grid preparation, and cryo-EM are still required afterward, and the systematic validation so far is mostly limited to Class A GPCRs. Even so, for projects working on inactive-state GPCRs or antagonist complexes, or ones that have been stuck on fusion-construct screening for a long time, it could remove a good part of the upfront trial and error. So I decided to reproduce NOAH's computational pipeline first and see whether it can help my own or neighboring projects; this post records the problems encountered during deployment.
As a first step, I tried deploying NOAH on a Linux server with an NVIDIA GPU. NOAH orchestrates GPCRdb data, DSSP, PPM3, and ColabFold to screen candidate constructs. The project already ships a Dockerfile, and it looks like just three commands get it started:
The actual deployment was far less smooth. One after another, I hit DSSP dependency incompatibilities, Docker failing to use the NVIDIA GPU, unstable access to external resources from the server, and underdocumented runtime parameters. This post records the complete debugging process and the deployment method that ultimately worked and can be reused.
NOAH's current LICENSE only permits non-commercial research and educational use and explicitly forbids redistributing the code to third parties, in original or modified form, including uploading it to a public GitHub repository. I therefore can't share the modified content publicly; what this post shares is the deployment approach and the troubleshooting experience. If you run into similar problems, you can hand this post to an AI as context, and it should make your deployment smoother.
1. Build failure: unstable DSSP and libmcfp version combinations
The first time I ran docker build, the problem was in the DSSP environment: mkdssp and dssp could be found but wouldn't run correctly during version checks or when invoked by Biopython. In other words, the problem wasn't “DSSP not installed” — it was that the binary interface between DSSP and the underlying libmcfp was incompatible.
The original Dockerfile first creates NOAH's Conda environment and installs DSSP, then separately installs gsutil. The two independent Conda solves can update indirect dependencies that were already installed. At the same time, the original PATH puts the ColabFold environment ahead of the NOAH environment, which also increases the risk of calling programs or dynamic libraries from the wrong environment.
In the end, the fix had four parts:
The core of the changes is as follows:
2. Seeing the GPU on the host doesn't mean Docker can use it
The second problem was at the GPU layer. nvidia-smi running normally on the server only proves the NVIDIA driver is working; for Docker to expose the GPU to a container, you also need to install and configure the NVIDIA Container Toolkit.
You can first check which runtimes Docker currently knows about:
On Ubuntu or Debian, I followed the official NVIDIA Container Toolkit installation documentation to complete the setup. The version number below is the one listed in the official docs as of 2026-08-30: 1.20.0-1; for future deployments, first confirm the current version on the official page.
nvidia-ctk runtime configure modifies the host's /etc/docker/daemon.json, so Docker can invoke the NVIDIA runtime. After configuring, don't just look at docker info — actually start a temporary container to verify. NVIDIA's official test command is:
Only when this command prints GPU information inside the container is the GPU runtime truly configured. The corresponding official verification is described in Running a Sample Workload.
3. Passing a proxy into the Docker build
NOAH's image build needs to reach external services such as Conda, PyPI, GitHub, and Google Cloud Storage. When the server's network is restricted, you can first set the proxy in a terminal on the host:
These export commands only set the proxy for the current host shell and the regular processes it launches, which fixes network access for commands like git clone on the host. However, Docker doesn't automatically pass these environment variables into the Dockerfile's RUN environment during image builds. So you may see this: the host can clone the repository fine, but docker build's wget, Conda, pip, or gsutil still time out.
So when running the build, you also need to explicitly pass the proxy via --build-arg:
Here, $http_proxy, $https_proxy and $all_proxy are taken from the host's current shell and then passed by --build-arg to the build environment. Just replace the placeholders with your own proxy addresses. Docker already predefines HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and other proxy build arguments, so there's no need to add a permanent ENV; otherwise the proxy address may end up baked into the image configuration. See the Docker CLI proxy documentation for details.
4. Supplementing the README
The original README gives the minimal commands but doesn't systematically explain which parameters are required, what the defaults are, or where results are written. Copying the commands verbatim raises several questions: what happens if you don't pass -m? Is -f required? Does --reverse enable or disable reverse screening? You might not even know these parameters exist.
NOAH's core command can be summarized as:
The most important parameters are:
Parameter
Required
Default
Meaning
-n, --name
Yes
None
GPCR name; in database mode it must match the database directory name, e.g., v2r.
-p, --ppm
Yes
None
PPM3 code directory, which should contain immers.
-d, --database
Conditional
None
NOAH/GPCRdb database directory; when not using a database, provide both -s and -j.
-s, --structure
Conditional
None
Custom GPCR PDB structure.
-j, --json
Conditional
None
Residue annotations in GPCRdb residues/extended format.
-m, --mode
No
Inactive
Conformation state; only accepts Active or Inactive.
-f, --fp
No
ARK1
Fusion protein; options are ARK1, BRIL, or A2A_BRIL.
-r, --reverse
No
Reverse screening by default
The name is misleading: passing this option actually turns off the reverse helix-phase screening.
Another key point: NOAH has no separate --output parameter; results are written to the current working directory. Different targets, conformations, or fusion proteins should each use a different empty directory; rerunning directly in an existing results directory can fail because some files are created in exclusive mode.
Therefore, I recommend putting the target, conformation, and fusion protein into RUN_ID and explicitly passing -m and -f, instead of relying on the defaults:
Here I use --gpus device=0, exposing only GPU 0 to the container. It's more direct than “exposing all GPUs and then setting CUDA_VISIBLE_DEVICES=0”. Docker's official guidance on specifying GPUs is in GPU access.
Currently, NOAH calls ColabFold one construct at a time, so it won't automatically get near-linear speedup just because the server has multiple GPUs and the command uses --gpus all. If you haven't modified the scheduling logic yourself, allocating a single GPU per task is usually cleaner and makes it easy to spread different tasks across different GPUs.
Once the task is started in the background, you can check progress like this:
5. Why the modified repository isn't public
To keep later users from repeating the same pitfalls, I organized the Docker dependency locking and README parameter documentation, and even committed the changes to my personal fork. However, NOAH's project license explicitly restricts code redistribution and specifically mentions that neither the original nor a modified version may be uploaded to a public GitHub repository. Although GitHub's platform terms have separate provisions for native forks of public repositories, to avoid any conflict in license interpretation and to respect the usage boundaries the authors expressed, I decided not to distribute the modified repository publicly and to keep these changes only in my own internal, non-commercial research environment.
Therefore, this post only shares the deployment process and troubleshooting ideas, without a link to the modified repository. Readers should obtain the code from the original repository and comply with its license; if you need to publish a modified version, distribute it to third parties, or use it commercially, obtain the authors' explicit permission first.
Summary
This NOAH deployment ultimately boils down to four lessons:
NOAH's core idea is valuable, but to turn it into a stable, reproducible server workflow, environment locking, GPU runtime, network configuration, and runtime documentation are all indispensable.