nopCommerce doesn’t ship a Linux quick-start of its own — the official installation path assumes Windows and IIS, so this procedure treats Docker as the port and targets nopCommerce 4.90.6 on Ubuntu 24.04 LTS with Docker 28.1.1. The bundled docker-compose.yml brings up SQL Server and the web app together, but two documented failures sit between docker compose up and a working install page: a startup-race timeout and a credentials mismatch. A completed installer isn’t a sellable store either — no payment method is active until an admin turns one on by hand. Every timing, resource figure and command output below is marked for capture and has not been measured yet — this article states the exact procedure and marks each result as pending rather than inventing one. Timings, command outputs and reproduction results below are marked for capture and have not been measured yet — each is a placeholder rather than a guess.
Confirm the host and pick a database before installing nopCommerce on Ubuntu 24.04
nopCommerce 4.90 targets the .NET 9 runtime, up from the .NET 8 floor of the 4.70 line, per the technology and system requirements doc (opens in a new tab). That runtime ships inside the Docker image, so the Ubuntu host itself needs Docker 28.1.1 and nothing .NET-specific installed directly.
The same requirements doc lists three officially supported databases: SQL Server 2012 or above, MySQL 5.7 or above (since nopCommerce 4.30), and PostgreSQL 9.5 or above (since 4.40). A “SQL Server or MySQL” framing undersells the third option — Postgres has had first-class support for several major versions now.
nopCommerce’s Docker tutorial (opens in a new tab) and the rest of the install docs are written Windows/IIS-first. On Ubuntu, the realistic path is Docker, and the repository root (opens in a new tab) ships three ready-made Compose files: docker-compose.yml for SQL Server, mysql-docker-compose.yml for MySQL, and postgresql-docker-compose.yml for PostgreSQL.
This run installs against SQL Server using docker-compose.yml, which pulls mcr.microsoft.com/mssql/server:2019-latest (opens in a new tab) for the database. That choice determines every command in the sections that follow — switching to MySQL or Postgres means swapping the Compose file, not just the connection string.
graph TD
A[Pick a database for nopCommerce] --> B{Already running one in production?}
B -->|SQL Server| C[docker-compose.yml]
B -->|MySQL 5.7+| D[mysql-docker-compose.yml]
B -->|PostgreSQL 9.5+| E[postgresql-docker-compose.yml]
B -->|None yet, evaluating| C
C --> F[This article's path]
docker --versionExpected output:
git clone https://github.com/nopSolutions/nopCommerce.git nopcommerce-test
cd nopcommerce-test
ls docker-compose.yml mysql-docker-compose.yml postgresql-docker-compose.ymlExpected output:
You should now see: Docker reporting version 28.1.1 or newer, and all three Compose files present at the repository root, confirming docker-compose.yml as this run’s install path.
Start nopCommerce and SQL Server with the bundled docker-compose.yml
Reading docker-compose.yml directly shows two services. nopcommerce_database uses the mcr.microsoft.com/mssql/server:2019-latest image with ACCEPT_EULA: "Y", MSSQL_PID: "Express", and a hard-coded SA_PASSWORD: "nopCommerce_db_password". Treat that password as a value to change before this stack is anything beyond a disposable proof of concept — it’s identical in every clone of the repository.
nopcommerce_web doesn’t pull a pre-built image. It declares build: ., so docker compose up compiles the web app from the repository’s own Dockerfile rather than downloading it. That’s a different cost profile than the outline for this stack assumed: only the database side is a pull, and the web side is a build, which is typically slower and CPU-bound rather than network-bound. A separately published image, nopcommerceteam/nopcommerce (opens in a new tab) on Docker Hub — tag 4.90.6, roughly 232 MB compressed — exists as a faster alternative, but the bundled Compose file doesn’t reference it by default.
The web container is named nopcommerce and publishes port 80 to the host. The database container is named nopcommerce_mssql_server and publishes no port at all — that gap matters in the next section. Watch docker compose logs on the database service until SQL Server itself reports readiness, before opening the install page in a browser.
One more detail worth checking directly rather than assuming: the file declares a top-level volume named nopcommerce_data, but neither service actually mounts it. That means the database’s files live only in the nopcommerce_mssql_server container’s writable layer — docker compose down removes that container, and the data goes with it, unless a volume mount is added by hand first.
docker compose -f docker-compose.yml up -d
docker compose psExpected output:
docker compose logs nopcommerce_databaseExpected output:
You should now see: both containers reporting running, and the database container’s logs confirming SQL Server is accepting connections before the installer is opened.
Fix the installer’s timeout and permission failures against SQL Server
nopcommerce_web declares depends_on: - nopcommerce_database, but plain depends_on in Compose only waits for the database container to start — not for SQL Server inside it to finish its own startup and EULA-acceptance cycle. The file defines no healthcheck, so nothing actually blocks the web container from reaching the install page before the database is ready to accept connections. That’s a structural race, not an incidental bug.
sequenceDiagram
participant Compose as docker compose up
participant DB as nopcommerce_database
participant Web as nopcommerce_web
Compose->>DB: start container
Compose->>Web: start container (depends_on is satisfied)
Web->>DB: attempt install-time connection
DB--xWeb: not yet accepting connections
Note over Web: "Installation failed, timeout expired"
A forum thread (opens in a new tab) reports exactly this: “Installation failed, timeout expired” on the setup page right after docker compose up. The fix is to retry the install page once the previous section’s logs confirm SQL Server is ready — not to change any installer input.
A second forum thread (opens in a new tab) reports “Setup failed: Database does not exist or you don’t have permissions to connect to it.” This comes from installer fields that don’t match the Compose file’s declared values. Enter the server name as nopcommerce_database — the Compose service name, which is how the web container resolves the database over the internal Compose network — with SQL authentication user sa and password nopCommerce_db_password, exactly as declared. Let the installer create the database itself rather than pre-creating one with different credentials.
GitHub issue #6109 (opens in a new tab) collects this same failure class across all three supported databases, with different root causes per report — network isolation, a wrong hostname, an unmapped port. Treat any install-time connection failure as networking or credentials first, and check logs on both containers before re-running the installer.
A host-side SQL client such as sqlcmd or Azure Data Studio can’t reach nopcommerce_database by default, because the Compose file publishes no port for it. Add a 1433:1433 mapping to that service only if host-side inspection is actually needed — the storefront itself connects over the internal network and doesn’t require it.
Server name: nopcommerce_database
Database: (leave blank — let the installer create it)
User: sa
Password: nopCommerce_db_passwordYou should now see: the installer’s database connection step succeeding and proceeding to schema creation, with no timeout or permissions error.
Complete the setup wizard and measure install time and resource footprint
A single top-line install time hides where it’s actually spent. Break it into four stages instead: pulling the mcr.microsoft.com/mssql/server:2019-latest image, building the nopcommerce_web image from the Dockerfile, docker compose up to both containers healthy, and the installer itself — schema creation plus, optionally, sample data.
The installer offers an “Install sample data” checkbox. Enabling it is what makes the storefront and test-order walkthrough later in this article possible, so that choice gets made explicitly here rather than left implicit.
docker stats reports peak and steady-state RAM and CPU for both containers once they’re up. Disk usage needs two numbers per container: the writable layer size for nopcommerce_web, and the writable layer size for nopcommerce_mssql_server — since the previous section confirmed the database has no separate mounted data volume, that one container’s layer is where all of the database’s actual files live.
time docker compose -f docker-compose.yml pull nopcommerce_database
time docker compose -f docker-compose.yml build nopcommerce_web
time docker compose -f docker-compose.yml up -dExpected output:
docker stats --no-stream
docker ps -sExpected output:
| Stage | Command | Wall-clock time |
|---|---|---|
| Database image pull | docker compose pull nopcommerce_database | [pending] |
| Web app image build | docker compose build nopcommerce_web | [pending] |
| Containers up to healthy | docker compose up -d | [pending] |
| Installer (schema + sample data) | browser walkthrough | [pending] |
| Total | [pending] |
Every figure in that table belongs to this exact stack and this exact host. A different CPU, a spinning disk instead of an SSD, or a slower link for the SQL Server pull will move every number in it.
You should now see: a completed version of the table above, with every cell filled from this run, and a peak-versus-idle resource footprint comparable against a different host.
Log into the storefront and admin, then price removing Powered by nopCommerce
nopCommerce ships both a customer-facing storefront and an admin back office out of the box, per the project’s own repository description (opens in a new tab). This run reports that bundled storefront’s out-of-the-box condition rather than pairing it with a separate frontend.
The open-source edition is licensed under the nopCommerce Public License 4.0, described on the licence overview page (opens in a new tab) and set out in full in LICENSE.md (opens in a new tab). Reading that file directly: it’s the GNU AGPLv3 plus a clause requiring “on each user interface screen” the “powered by nopCommerce” text, linked to nopcommerce.com. That’s a licence condition, not a cosmetic default.
Every page of a fresh install — storefront and admin alike — should show that attribution, with no admin setting to turn it off. Removing it requires purchasing a copyright removal key or a separate commercial licence, a distinct paid transaction rather than something priced in the licence text itself. LICENSE.md doesn’t state a figure; it links out to the copyright removal key page (opens in a new tab) instead.
That page refused automated fetches again on 5 August 2026, and third-party summaries disagree with each other on the figure, so no number is repeated here. Check the copyright removal key page directly at the time of budgeting for a live store, rather than trusting any single cited figure.
graph LR
subgraph free["Included at no cost"]
A[Storefront]
B[Admin back office]
C["'Powered by nopCommerce' on every screen"]
end
subgraph paid["Separate paid transaction"]
D[Copyright removal key]
E[Commercial licence]
end
C -.removed by.-> D
C -.removed by.-> E
You should now see: both the storefront and admin authenticating successfully, the mandatory attribution visible on every page, and its removal cost stated honestly rather than guessed.
Activate a payment method before a test order can complete
Bundled payment methods, including Check/Money Order (opens in a new tab), install but stay inactive. Checkout shows no payment option at all until one is turned on — this is the first-run configuration step that closes the gap between “installer finished” and “store can take an order.”
The fix is short: open Configuration → Payment methods in the admin panel, edit Check/Money Order, tick Is active, and save.
graph TD
A[Installer completes successfully] --> B{Any payment method active?}
B -->|No — default state| C[Checkout has no payment option]
B -->|Yes, after admin enables one| D[Checkout can complete]
A -.->|not the same as| E[Store ready to sell]
This is a functional gap, not a bug. A successful installer run and a store that’s actually ready to sell are two different states, and nopCommerce doesn’t collapse them into one. Shipping methods are worth checking for the same inactive-by-default condition on this install, since checkout can stall on either one.
Configuration → Payment methods → Check/Money Order → [x] Is active → SaveYou should now see: Check/Money Order, or whichever method is chosen, appearing as a selectable option at checkout.
Place one test order to confirm the storefront works end to end
Add one sample-data product to the cart, proceed through checkout, and complete the order using the payment method activated in the previous section. This is the step that actually exercises the stack rather than just loading pages in a browser.
Afterward, confirm the order appears in the admin’s order list, with status and totals matching what was entered at checkout. That check is what separates “pages render” from “the platform works” — a checkout that reaches a confirmation screen without a matching order record is a broken store with a working front end.
You should now see: one order placed through the storefront, appearing correctly in the admin order list.
What this nopCommerce install run does not settle before a proof of concept
This run covers one host, one database choice — SQL Server via Docker — and default configuration throughout. It doesn’t test the MySQL or PostgreSQL Compose paths, version upgrades, or production hardening, and nothing above should be read as covering those cases.
The nopCommerce Public License 4.0’s copyright-key economics are a decision to make before committing evaluation time, not after a working demo already exists on the free tier. Confirming the actual removal-key price against the live page (opens in a new tab) belongs at the start of an evaluation, not at the end of one.
docs.nopcommerce.com returned HTTP 403 to direct automated fetches during research for this article. The technology-requirements and Docker-tutorial content cited here came from the nopSolutions/nopCommerce-Docs GitHub mirror (opens in a new tab) instead — reconfirm against the live docs site before relying on either page for a production deployment.
What wasn’t tested, stated plainly: the MySQL and PostgreSQL install paths, multi-node deployment, and behaviour under concurrent orders. One clean install on one host does not imply production readiness.
Limitations
This article covers a single clean install on one host, using nopCommerce 4.90.6, Ubuntu 24.04, Docker 28.1.1, and SQL Server via the bundled docker-compose.yml, with default configuration throughout.
It does not cover the MySQL or PostgreSQL Compose paths, upgrading between nopCommerce versions, running the database on separate hardware, clustering or horizontal scaling, TLS termination, or load under concurrent orders. Timing and resource figures apply to this host only and won’t transfer to a different CPU, memory, disk or network. Where a measurement, error reproduction, or command output couldn’t be confirmed by an actual run at time of writing, it’s marked as pending rather than asserted.