This guide covers a production deployment of PharmaVault on an Ubuntu server using a three-component stack: Docker to containerize and run the Blazor application, a native PostgreSQL installation on the host for persistent data storage, and Nginx as a reverse proxy that terminates SSL and forwards traffic to the container. The Docker container exposes the application on portDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/JReyna217/PharmaVault/llms.txt
Use this file to discover all available pages before exploring further.
8080 internally, which is mapped to port 5010 on the host, and Nginx routes public HTTPS traffic on port 443 to that local port.
Prerequisites
Before proceeding, ensure the following are in place on your Ubuntu server:- Ubuntu server — with SSH access and a user with
sudoprivileges - Docker — installed and the daemon running (
sudo systemctl status docker) - PostgreSQL — installed natively on the host with the
pharmavault_dbdatabase and schema already created (follow the Quickstart SQL steps) - Domain name — a DNS A record pointing to your server’s public IP
- SSL certificate and key — e.g., obtained via Let’s Encrypt / Certbot, stored at a known path on the server
Clone the Repository on the Server
SSH into your production server and clone the PharmaVault source code.
Build the Docker Image
Build the Docker image directly on the host. This ensures the compiled binaries match the server’s CPU architecture and avoids ARM vs. x86_64 conflicts that can arise from images built on a different machine.
How the multi-stage Dockerfile works
How the multi-stage Dockerfile works
The
The final image contains only the runtime and the compiled application — not the .NET SDK, source code, or build tools — keeping it lean and reducing the attack surface.
Dockerfile uses a three-stage multi-stage build to produce a minimal production image:| Stage | Base Image | What it does |
|---|---|---|
build | mcr.microsoft.com/dotnet/sdk:10.0 | Restores NuGet dependencies and compiles the solution in Release mode |
publish | Inherits from build | Runs dotnet publish to produce optimized, self-contained output artifacts |
final | mcr.microsoft.com/dotnet/aspnet:10.0 | Copies only the publish output into a lightweight ASP.NET runtime image, discarding the SDK entirely |
Run the Container
Start the container in detached mode with the flags below. Each flag is explained in the comment next to it.
Replace
| Flag | Purpose |
|---|---|
-d | Run in detached (background) mode |
--restart unless-stopped | Automatically restart the container after a server reboot, unless it was manually stopped |
-p 5010:8080 | Map host port 5010 to the container’s internal port 8080 (the default .NET 8/10 Docker port) |
--add-host=host.docker.internal:host-gateway | Adds a DNS alias inside the container that resolves to the host machine’s IP, allowing the app to reach PostgreSQL on the host |
-e "ConnectionStrings__DefaultConnection=..." | Injects the database connection string as an environment variable (double underscore __ maps to the : separator used in appsettings.json) |
YOUR_DB_USER and YOUR_DB_PASSWORD with your actual PostgreSQL credentials before running the command.Configure Nginx as a Reverse Proxy
A ready-to-use Nginx configuration template is included in the repository at Replace
deploy/nginx/pharmavault.conf. Copy it to the Nginx sites-available directory and customize the two placeholder values.[YOUR_URL] with your domain name and [YOUR_CERT_PATH] with the directory containing your SSL certificate files, then save. The full configuration is shown below for reference:deploy/nginx/pharmavault.conf
The
Upgrade and Connection "upgrade" headers in the Nginx location block are required for Blazor Server to function correctly. Blazor Server uses SignalR, which establishes a persistent WebSocket connection between the browser and the server for real-time UI updates. Without these headers, Nginx will not forward the WebSocket upgrade handshake and the application will fail to initialize.Enable the Site and Reload Nginx
Create a symlink from If
sites-available to sites-enabled, test the configuration for syntax errors, and reload Nginx to apply the changes.sudo nginx -t reports syntax is ok and test is successful, your site is live. Open your domain in a browser — you should be redirected from HTTP to HTTPS and land on the PharmaVault login page.