<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>AWS on Alex Jacobs</title>
    <link>https://alex-jacobs.com/tags/aws/</link>
    <description>Recent content in AWS on Alex Jacobs</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 15 Jun 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://alex-jacobs.com/tags/aws/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Running Jupyter lab behind NGINX--Part 2</title>
      <link>https://alex-jacobs.com/posts/jupyterlab2/</link>
      <pubDate>Wed, 15 Jun 2022 00:00:00 +0000</pubDate>
      
      <guid>https://alex-jacobs.com/posts/jupyterlab2/</guid>
      <description>Part 2: Configuring Jupyter Lab authentication behind NGINX, handling token-based auth bypass, and securing the reverse proxy setup on EC2.</description>
      <content:encoded><![CDATA[<h4 id="if-you-havent-read-part-1postsjupyterlab1-you-may-want-to-start-there">If you haven&rsquo;t read <a href="/posts/jupyterlab1/">part 1</a>, you may want to start there.</h4>
<p>In the <a href="/posts/jupyterlab1/">last post</a>, we left off with a working reverse proxy, but we couldn&rsquo;t access Jupyter lab due to
its auth enforcement. Because of how we&rsquo;re setting this up, we will be handling
authentication upstream of Jupyter Lab, and we don&rsquo;t want to rely on them for handling authentication. What we are going to do here is generally considered &ldquo;unsafe.&rdquo;<br>
Again, if you&rsquo;re looking to do this for your team, check out <a href="https://jupyter.org/hub">Jupyter Hub</a>&ndash;it probably makes more sense
for your use case.</p>
<p>To disable token auth, we will update our Jupyter Lab config.</p>
<p>There is an extensive config file for Jupyter Lab. In a production environment, I recommend using it (you can generate a sample file
by running <code>jupyter notebook --generate-config</code>). But, for this toy example, we will pass
our config as cmd line args. To disable token auth and to allow same-origin requests, we&rsquo;re going to update our Jupyter Lab
Dockerfile Entrypoint to include these arguments</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="s2">&#34;--ServerApp.token=&#34;</span>, <span class="s2">&#34;--ServerApp.password=&#34;</span>, <span class="s2">&#34;--ServerApp.allow_origin&#34;</span>, <span class="s2">&#34;*&#34;</span>
</span></span></code></pre></div><p>Our Dockerfile should now look like</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> ubuntu:20.04</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENV</span> <span class="nv">DEBIAN_FRONTEND</span><span class="o">=</span>noninteractive
</span></span><span class="line"><span class="cl"><span class="k">RUN</span> apt-get update <span class="o">&amp;&amp;</span> apt-get install -y <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-pip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-dev <span class="o">&amp;&amp;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3 -m pip install jupyterlab<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> useradd -ms /bin/bash jupyter<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 8888</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;jupyter&#34;</span><span class="p">,</span> <span class="s2">&#34;lab&#34;</span><span class="p">,</span> <span class="s2">&#34;--ip=0.0.0.0&#34;</span><span class="p">,</span> <span class="s2">&#34;--port&#34;</span><span class="p">,</span> <span class="s2">&#34;8888&#34;</span><span class="p">,</span> <span class="s2">&#34;--allow-root&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.token=&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.password=&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.allow_origin&#34;</span><span class="p">,</span> <span class="s2">&#34;*&#34;</span><span class="p">]</span><span class="err">
</span></span></span></code></pre></div><p>And if we rebuild and start our docker compose again</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose build <span class="o">&amp;&amp;</span> docker compose up
</span></span></code></pre></div><p>We now get through to Juypter!
<img loading="lazy" src="/posts/jupyterlab2/img5.png" type="" alt="jupyter lab"  /></p>
<p>But if we try and open the Python kernel, we&rsquo;ll notice it&rsquo;s having trouble connecting.
<img loading="lazy" src="/posts/jupyterlab2/img3.png" type="" alt="jupyter lab_cant_connect"  /></p>
<p>Opening our browser dev tools shows that there is an issue with how our proxy is handling WebSockets
<img loading="lazy" src="/posts/jupyterlab2/img4.png" type="" alt="jupyter lab_websockets"  /></p>
<p>We&rsquo;ll have to update our Nginx config to address this.<br>
We will add these lines to set headers properly for WebSockets to our / location in the server block.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="k">...</span>
</span></span><span class="line"><span class="cl">  <span class="s">server</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">listen</span>       <span class="mi">8000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server_name</span>  <span class="s">localhost</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">location</span> <span class="s">/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_hide_header</span> <span class="s">&#34;X-Frame-Options&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_pass</span> <span class="s">http://upstream_jupyter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># websocket support
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kn">proxy_http_version</span> <span class="mi">1</span><span class="s">.1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="s">&#34;websocket&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">&#34;Upgrade&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_read_timeout</span> <span class="mi">86400</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">...</span>
</span></span></code></pre></div><p>And now, if we restart our containers using the updated config, we&rsquo;ll see our kernel connects!</p>
<p><img loading="lazy" src="/posts/jupyterlab2/img6.png" type="" alt="jupyter lab_websockets"  /></p>
<p>If you&rsquo;re wondering how we will handle security when we&rsquo;re basically giving whoever is using this a terminal
into our cloud, the answer is using AWS to isolate the instance via IAM roles/ policy. We aren&rsquo;t going to get too much into
that in this post, but it is a valid concern. There isn&rsquo;t much we can do to prevent a privilege escalation/container escape
from a sophisticated user, but we can at least not give root access.</p>
<p>We&rsquo;re going to update our Jupyter Dockerfile to have a new user, &lsquo;jupyter&rsquo;, and we&rsquo;ll run Jupyter Lab as this user.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl">...<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> useradd -ms /bin/bash jupyter<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">USER</span><span class="s"> jupyter</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span>...<span class="err">
</span></span></span></code></pre></div><p>We&rsquo;re also going to update our ENTRYPOINT, so the Jupyter Lab root directory is set to the Jupyter user&rsquo;s home directory</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="s2">&#34;--ServerApp.root_dir&#34;</span>, <span class="s2">&#34;/home/jupyter&#34;</span>, <span class="s2">&#34;--ServerApp.notebook_dir&#34;</span>, <span class="s2">&#34;/home/jupyter&#34;</span>
</span></span></code></pre></div><p>Our Dockerfile should now look like</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> ubuntu:20.04</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENV</span> <span class="nv">DEBIAN_FRONTEND</span><span class="o">=</span>noninteractive
</span></span><span class="line"><span class="cl"><span class="k">RUN</span> apt-get update <span class="o">&amp;&amp;</span> apt-get install -y <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-pip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-dev <span class="o">&amp;&amp;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3 -m pip install jupyterlab<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># add user and switch to them</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> useradd -ms /bin/bash jupyter<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">USER</span><span class="s"> jupyter</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 8888</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;jupyter&#34;</span><span class="p">,</span> <span class="s2">&#34;lab&#34;</span><span class="p">,</span> <span class="s2">&#34;--ip=0.0.0.0&#34;</span><span class="p">,</span> <span class="s2">&#34;--port&#34;</span><span class="p">,</span> <span class="s2">&#34;8888&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.token=&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.password=&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.allow_origin&#34;</span><span class="p">,</span> <span class="s2">&#34;*&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.root_dir&#34;</span><span class="p">,</span> <span class="s2">&#34;/home/jupyter&#34;</span><span class="p">,</span> <span class="s2">&#34;--ServerApp.notebook_dir&#34;</span><span class="p">,</span> <span class="s2">&#34;/home/jupyter&#34;</span><span class="p">]</span><span class="err">
</span></span></span></code></pre></div><p>If we reload our site, we&rsquo;ll see that the working directory is now set to <code>/home/jupyter</code>, and if we try to
write to <code>/</code>, we&rsquo;ll get a permissions error. It&rsquo;s important to note that while this makes it a little more
difficult for a malicious user to take over this &lsquo;instance&rsquo;, we will be giving them access to the internet,
the ability to download and install packages, execute code, etc. It would not be too difficult for someone with mal
intent to get around this. Changing the user and working directory does more to help an innocent user from accidentally breaking
something.</p>
<p>Great! Now we have disabled token authentication, added a system user (who is now running Jupyter), and changed our notebook
directory to our user&rsquo;s directory! In the next post, we&rsquo;ll set up a task definition and deploy to ECS.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Running Jupyter lab behind NGINX--Part 1</title>
      <link>https://alex-jacobs.com/posts/jupyterlab1/</link>
      <pubDate>Sun, 08 May 2022 00:00:00 +0000</pubDate>
      
      <guid>https://alex-jacobs.com/posts/jupyterlab1/</guid>
      <description>This multipart blog will walk through our setup running Jupyter Lab, using Nginx as a reverse proxy using a sidecar pattern to deploy to EC2.</description>
      <content:encoded><![CDATA[<h1 id="background">Background</h1>
<p>Jupyter Lab is an open source web-based IDE for notebooks with Python and R support, geared towards the data science crowd.
It&rsquo;s a powerful, mature application with a potentially complex configuration. Our requirement was to deliver Jupyter Lab to users
so that each user would have their own isolated &ldquo;instance .&rdquo; There is an off-the-shelf solution for this called Jupyter Hub that probably makes
the most sense for your organization. This example will be a proof of concept on how you could roll your solution.</p>
<h2 id="heading"></h2>
<h2 id="step-1--jupyter-lab-docker">Step 1&ndash;Jupyter Lab Docker</h2>
<h5 id="if-you-arent-familiar-with-docker-were-going-to-be-using-it-a-lot-here-so-check-out-some-guides">If you aren&rsquo;t familiar with Docker, we&rsquo;re going to be using it a lot here, so check out some guides</h5>
<p>Our first step will be getting Jupyter Lab up and running in a container.
There are many Docker images available on (Docker hub)[https://hub.docker.com/] for Jupyter Lab, but since we&rsquo;re rolling
everything ourselves, we might as well make our own image. It also gives us more control over our code&ndash;it&rsquo;s also a pretty simple Dockerfile.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> ubuntu:20.04</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENV</span> <span class="nv">DEBIAN_FRONTEND</span><span class="o">=</span>noninteractive
</span></span><span class="line"><span class="cl"><span class="k">RUN</span> apt-get update <span class="o">&amp;&amp;</span> apt-get install -y <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-pip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      python3-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    <span class="o">&amp;&amp;</span> python3 -m pip install jupyterlab<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 8888</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;jupyter&#34;</span><span class="p">,</span> <span class="s2">&#34;lab&#34;</span><span class="p">,</span> <span class="s2">&#34;--ip=0.0.0.0&#34;</span><span class="p">,</span> <span class="s2">&#34;--port&#34;</span><span class="p">,</span> <span class="s2">&#34;8888&#34;</span><span class="p">,</span> <span class="s2">&#34;--allow-root&#34;</span><span class="p">]</span><span class="err">
</span></span></span></code></pre></div><p>There are probably some good arguments for why you should use alpine or something else as the base image here, but I&rsquo;m
a sucker for ubuntu. Since this isn&rsquo;t a Docker tutorial, I&rsquo;m not going to go into great detail here about what each
line in this Dockerfile does, but assume that it installs Jupyter Lab and configures it to run at port 8888.
We&rsquo;ll expand on the Jupyter Lab config (and make some changes) later, but for now, this works fine.</p>
<p>We&rsquo;re going to use Docker compose to run this. Our compose file looks like</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">jupyter</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">context</span><span class="p">:</span><span class="w"> </span><span class="l">.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">dockerfile</span><span class="p">:</span><span class="w"> </span><span class="l">Dockerfile</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">jupyter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">jupyter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">8888</span><span class="p">:</span><span class="m">8888</span><span class="w">
</span></span></span></code></pre></div><p>We can run this with <code>docker compose up</code></p>
<p>This will start our Jupyter Lab container and make it available at <a href="http://127.0.0.1:8888/lab/">http://127.0.0.1:8888/lab/</a></p>
<p><img loading="lazy" src="/posts/jupyterlab1/img1.png" type="" alt="jupyter lab"  /></p>
<h3 id="awesome-were-part-of-the-way-there">Awesome! We&rsquo;re part of the way there!</h3>
<p>Next, we need to put together an Nginx docker file.</p>
<p>While we could use the official Nginx image, in keeping with the theme, we&rsquo;re going to create our own Nginx image (and it&rsquo;s also
<em>really</em> simple)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> ubuntu:20.04</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> apt-get update <span class="o">&amp;&amp;</span> apt-get -y install nginx<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">COPY</span> nginx.conf /etc/nginx/nginx.conf<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 8000</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;/usr/sbin/nginx&#34;</span><span class="p">]</span><span class="err">
</span></span></span></code></pre></div><p>Pretty straightforward. Our config file is also pretty simple. We&rsquo;re going to use port 8000, and we&rsquo;re going to simply
forward all requests directly to Jupyter lab.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="k">daemon</span> <span class="no">off</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">error_log</span> <span class="s">/dev/stdout</span> <span class="s">info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">events</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="k">http</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">access_log</span> <span class="s">/dev/stdout</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">upstream</span> <span class="s">upstream_jupyter</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">jupyter</span><span class="p">:</span><span class="mi">8888</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">server</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">listen</span>       <span class="mi">8000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server_name</span>  <span class="s">localhost</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">location</span> <span class="s">/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_hide_header</span> <span class="s">&#34;X-Frame-Options&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_pass</span> <span class="s">http://upstream_jupyter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The final piece that will tie these together is our docker-compose file. Our docker-compose is pretty simple as well.
By using Docker compose, the networking between the containers is handled for us, and we can point the <code>jupyter</code> as the service
name in our nginx.conf</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">jupyter</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">context</span><span class="p">:</span><span class="w"> </span><span class="l">.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">dockerfile</span><span class="p">:</span><span class="w"> </span><span class="l">Dockerfile</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">jupyter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">jupyter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">8888</span><span class="p">:</span><span class="m">8888</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nginx</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">context</span><span class="p">:</span><span class="w"> </span><span class="l">.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">dockerfile</span><span class="p">:</span><span class="w"> </span><span class="l">nginx.Dockerfile</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">jupyter-nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">8000</span><span class="p">:</span><span class="m">8000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">nginx.conf:/etc/nginx/nginx.conf</span><span class="w">
</span></span></span></code></pre></div><p>Now, let&rsquo;s head to <a href="http://127.0.0.1:8000">http://127.0.0.1:8000</a>, and&hellip;</p>
<p><img loading="lazy" src="/posts/jupyterlab1/img2.png" type="" alt="nginx jupyter lab"  />
Awesome! We&rsquo;re being proxied to Jupyter Lab. But, we see a page requiring token auth. This is because Jupyter is currently
configured to enforce this. In the next post, we&rsquo;ll deal with this and some other things regarding permissions, creating a user, and making a
task definition for deploying this configuration to ECS.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
