FastAPINginxInterserver

    Deploying My FastAPI Application on an Ubuntu VPS: From Uvicorn to HTTPS

    Recently, I was setting up one of my backend applications on an Ubuntu VPS from InterServer . I thought the deployment would be simple: upload the project, install the dependencies...

    Sep 5, 2026
    6 min read
    10 views
    Deploying My FastAPI Application on an Ubuntu VPS: From Uvicorn to HTTPS

    Recently, I was setting up one of my backend applications on an Ubuntu VPS from InterServer. I thought the deployment would be simple: upload the project, install the dependencies, run Uvicorn, and that's it.

    But while doing it, I came across a few things which I had to understand properly, especially Uvicorn, DNS, Nginx, ports, HTTPS, and virtual environments.

    So I'm writing down the process here, mainly for myself and anyone who is also doing this for the first time.

    1. Running FastAPI with Uvicorn

    My application is a FastAPI application.

    After setting up the virtual environment and installing the dependencies, I ran the application using:

    bash
    uvicorn app.main:app --host 0.0.0.0 --port 8000

    Here:

    • app.main:app means my FastAPI app is inside app/main.py
    • --host 0.0.0.0 means it can accept connections from outside the server
    • --port 8000 means Uvicorn is running on port 8000

    I could then access my application using:

    text
    http://162.35.175.67:8000

    And the Swagger documentation:

    text
    http://162.35.175.67:8000/docs

    But there was one problem.

    If I close the SSH connection, the application can also stop because it is attached to that terminal session.

    So I used nohup:

    bash
    nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > app.log 2>&1 &

    Now Uvicorn runs in the background and continues running after closing the SSH session.

    I checked it using:

    bash
    ps aux | grep uvicorn

    and I could see Uvicorn running.


    2. Connecting a Domain to the Server

    I didn't want to use the IP address every time.

    I wanted something like:

    text
    api.pocket-flow.jotech.in

    My VPS is hosted on InterServer, but I manage the DNS for the domain through GoDaddy.

    So I added an A record in GoDaddy DNS:

    text
    Type:  A
    Name:  api.pocket-flow
    Value: 162.35.175.67
    TTL:   600

    After adding it, I checked from my computer:

    bash
    nslookup api.pocket-flow.jotech.in

    It returned:

    text
    api.pocket-flow.jotech.in
    162.35.175.67

    So the DNS was working.

    One thing I learned here is that DNS doesn't care about the port.

    For example, this is not what you put in the DNS record:

    text
    162.35.175.67:8000

    The DNS record only points to the IP address:

    text
    162.35.175.67

    The port is handled separately.


    3. Understanding the Port

    This was something I wanted to understand properly.

    If I open:

    text
    http://api.pocket-flow.jotech.in:8000

    the browser first uses DNS to find the IP:

    text
    api.pocket-flow.jotech.in
    162.35.175.67

    Then it connects to port 8000:

    text
    162.35.175.67:8000

    My Uvicorn application is listening on that port.

    So the request reaches:

    text
    Uvicorn
    FastAPI

    But if I open:

    text
    http://api.pocket-flow.jotech.in

    I don't specify a port.

    For HTTP, the browser uses the default port:

    text
    80

    So the request goes to:

    text
    162.35.175.67:80

    But my Uvicorn application is running on:

    text
    162.35.175.67:8000

    So something needs to receive the request on port 80 and pass it to my application.

    That's where Nginx comes in.


    4. Installing Nginx

    I installed Nginx on my InterServer Ubuntu VPS:

    bash
    sudo apt update
    sudo apt install nginx -y

    Then checked:

    bash
    sudo systemctl status nginx

    It showed:

    text
    Active: active (running)

    So Nginx was running successfully.


    5. Configuring Nginx

    I created a configuration file:

    bash
    sudo nano /etc/nginx/sites-available/pocket-flow

    Then added:

    nginx
    server {
        listen 80;
        server_name api.pocket-flow.jotech.in;
    
        location / {
            proxy_pass http://127.0.0.1:8000;
    
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    Then I checked the Nginx configuration:

    bash
    sudo nginx -t

    It returned:

    text
    syntax is ok
    test is successful

    Then I enabled the site:

    bash
    sudo ln -s /etc/nginx/sites-available/pocket-flow /etc/nginx/sites-enabled/

    and reloaded Nginx:

    bash
    sudo systemctl reload nginx

    Now I could access my API using:

    text
    http://api.pocket-flow.jotech.in/docs

    I didn't need to add :8000 anymore.


    6. Understanding What Nginx Is Doing

    This was probably the most useful thing I understood from the setup.

    When I open:

    text
    http://api.pocket-flow.jotech.in/docs

    the request reaches my server on port 80.

    Nginx receives the request and passes it to Uvicorn, which is running on port 8000.

    The basic flow is:

    text
                             Internet
                                │
                                ↓
                  api.pocket-flow.jotech.in
                                │
                                ↓
                         162.35.175.67
                                │
                                ↓
                             Nginx :80
                                │
                                ↓
                        Uvicorn :8000
                                │
                                ↓
                             FastAPI

    Nginx is acting as a reverse proxy.

    The browser doesn't need to know that my FastAPI application is running on port 8000.

    This also gives me a proper place to handle things like HTTPS, request routing, headers, and other web-server related configuration.


    7. Adding HTTPS

    The next thing I wanted was:

    text
    https://api.pocket-flow.jotech.in

    instead of:

    text
    http://api.pocket-flow.jotech.in

    For this, I used Let's Encrypt with Certbot.

    I installed Certbot and then ran:

    bash
    sudo certbot --nginx

    Certbot configured the SSL certificate with Nginx.

    After that, I could access:

    text
    https://api.pocket-flow.jotech.in/docs

    The architecture now looks like:

    text
                             Internet
                                │
                                ↓
                  api.pocket-flow.jotech.in
                                │
                                ↓
                         162.35.175.67
                                │
                                ↓
                            Nginx :443
                                │
                                ↓
                        Uvicorn :8000
                                │
                                ↓
                             FastAPI

    Nginx handles the HTTPS connection, while Uvicorn continues running the FastAPI application.

    So I don't need to configure SSL directly inside Uvicorn.


    8. One Small Mistake I Made With the Virtual Environment

    This was a simple mistake, but I think it's worth mentioning.

    After changing my .env, I wanted to restart Uvicorn.

    I stopped the old process and tried:

    bash
    nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > app.log 2>&1 &

    But it failed with:

    text
    Exit 127

    Then I noticed that my terminal prompt was:

    text
    root@vps3602820

    instead of:

    text
    (venv) root@vps3602820

    I had closed SSH and opened it again, so the virtual environment was not activated.

    I fixed it with:

    bash
    source /root/projects/backend/venv/bin/activate

    Then:

    bash
    nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > app.log 2>&1 &

    worked again.

    This reminded me that the virtual environment stays on the server, but it is not automatically activated in every new SSH session.


    9. What I Have Now

    My current setup is basically:

    text
                             Internet
                                │
                                ↓
                  api.pocket-flow.jotech.in
                                │
                                ↓
                         162.35.175.67
                                │
                                ↓
                            Nginx :443
                                │
                                ↓
                        Uvicorn :8000
                                │
                                ↓
                             FastAPI

    And my API is accessible through:

    text
    https://api.pocket-flow.jotech.in

    instead of directly using:

    text
    http://162.35.175.67:8000

    There is still one thing I want to improve.

    Right now, I'm using nohup to keep Uvicorn running. For a proper production setup, I should configure systemd for the FastAPI application.

    That would allow the application to:

    • Start automatically after a server reboot
    • Restart if the application crashes
    • Be managed using systemctl
    • Avoid manually activating the virtual environment every time

    For now, this setup helped me understand something I had seen many times but never properly understood.

    DNS, ports, Nginx, reverse proxy, Uvicorn and HTTPS are different pieces, and they work together to make a backend application available through a proper domain.

    J
    Written by

    Jobi S S

    Portfolio

    admin

    Sharing technical insights, engineering concepts, and practical modern software development guides.

    Community Discussion

    Enjoyed this read? Show your support or share your thoughts.

    Comments (0)

    No comments yet. Be the first to comment!

    📬 Enjoyed this article?

    Get new posts on Django, FastAPI, and system design straight to your inbox. No spam — unsubscribe whenever you want.