{"id":2532,"date":"2026-09-14T07:32:58","date_gmt":"2026-09-14T07:32:58","guid":{"rendered":"https:\/\/ukspeed.co.uk\/blog\/deploy-nextjs-uk-vps-pm2-vs-docker-vs-coolify-2026\/"},"modified":"2026-09-14T08:18:25","modified_gmt":"2026-09-14T08:18:25","slug":"deploy-nextjs-uk-vps-pm2-vs-docker-vs-coolify-2026","status":"publish","type":"post","link":"https:\/\/ukspeed.co.uk\/blog\/deploy-nextjs-uk-vps-pm2-vs-docker-vs-coolify-2026\/","title":{"rendered":"Deploy Next.js on UK VPS: PM2 vs Docker vs Coolify 2026"},"content":{"rendered":"<p>If you want full control over cost, performance and where your data lives, learning to deploy Next.js on a VPS is one of the most useful skills a UK developer can pick up in 2026. Managed platforms like Vercel and Netlify are wonderful for getting started, but as traffic grows the bills climb and your infrastructure choices narrow. In this guide we compare three practical, production-ready ways to run Next.js on a UK VPS \u2014 PM2, Docker and Coolify \u2014 and show how to put Nginx and HTTPS in front of any of them.<\/p>\n\n<h2 class=\"wp-block-heading\">What Is Next.js in Production?<\/h2>\n\n<p>Next.js is a React framework that supports server-side rendering (SSR), static generation, API routes and the App Router. In development you run <code>next dev<\/code>, but that server is not built for real traffic. For production you compile the app with <code>next build<\/code> and then serve it with <code>next start<\/code>, which launches a <a href=\"https:\/\/ukspeed.co.uk\/blog\/self-host-ghost-uk-vps-newsletter-blog-platform-2026\/\">Node.js<\/a> server listening on port 3000 by default. That single process handles SSR, route handlers and serves your pre-built pages.<\/p>\n\n<p>There are two other output modes worth knowing. The <strong>standalone<\/strong> output (set <code>output: 'standalone'<\/code> in <code>next.config.js<\/code>) produces a minimal, self-contained server folder with only the dependencies your app actually uses \u2014 ideal for slim Docker images. A <strong>static export<\/strong> emits plain HTML and is only suitable for fully static sites with no SSR or API routes. Most real apps use the default Node server or standalone output.<\/p>\n\n<h2 class=\"wp-block-heading\">Why Deploy Next.js on Your Own VPS<\/h2>\n\n<p>Managed hosts remove operational work, and that convenience is genuinely valuable early on. But there are solid reasons a growing team looks for a <strong>Vercel alternative<\/strong> and moves onto its own server.<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>Predictable cost at scale<\/strong> \u2014 a fixed monthly VPS price beats per-seat, per-function and bandwidth-metered billing once traffic is steady.<\/li><li><strong>Full control<\/strong> \u2014 run background jobs, a database, a cache and cron on the same box, with any Node.js version and system packages you like.<\/li><li><strong>UK data residency<\/strong> \u2014 keep customer data on UK soil, which matters for compliance and for clients who ask where their data lives.<\/li><li><strong>No vendor lock-in<\/strong> \u2014 your deployment is portable across any provider.<\/li><\/ul>\n\n<p>The trade-off is honest: you become responsible for patching, monitoring and scaling the server yourself. For many UK startups and agencies that control is well worth it, especially on a UK VPS close to their users. A single node from a provider such as UK Speed comfortably runs a small to mid-sized Next.js app.<\/p>\n\n<h3 class=\"wp-block-heading\">What You Need to Deploy Next.js on a VPS<\/h3>\n\n<p>Before you begin, make sure you have the essentials in place. A small Next.js app runs happily on roughly 1\u20132GB of RAM; SSR-heavy apps, or those doing builds on the same box, want 2\u20134GB or more, since <code>next build<\/code> itself is memory-hungry.<\/p>\n\n<ul class=\"wp-block-list\"><li>A UK VPS running a recent Ubuntu or Debian LTS release.<\/li><li>A non-root sudo user and hardened SSH \u2014 see our guide to <a href=\"https:\/\/ukspeed.co.uk\/blog\/how-to-harden-ssh-on-a-linux-vps-10-security-steps-beyond-just-changing-the-default-port\/\">hardening SSH on a Linux VPS<\/a>.<\/li><li>Node.js (an LTS version, installed via nvm) for the PM2 route, or Docker for the container routes.<\/li><li>A domain name with DNS pointed at your server&#8217;s IP, ready for HTTPS.<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">PM2 vs Docker vs Coolify<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/nx1-compare.svg\" alt=\"Deploy Next.js on a VPS: PM2 vs Docker vs Coolify compared on effort, reproducibility and auto-deploy\" class=\"wp-image-2533\" \/><figcaption class=\"wp-element-caption\">PM2 is the simplest, Docker is portable, and Coolify gives the best developer experience with Git auto-deploy.<\/figcaption><\/figure>\n\n\n<p>All three approaches end with a Next.js server running on port 3000 behind a <strong>reverse proxy<\/strong>. They differ in effort, isolation and day-to-day developer experience. The table below summarises the trade-offs.<\/p>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Method<\/th><th>Setup effort<\/th><th>Isolation<\/th><th>Zero-downtime<\/th><th>Best for<\/th><\/tr><\/thead><tbody><tr><td><strong>PM2<\/strong><\/td><td>Low \u2014 bare Node.js, no containers<\/td><td>None (shares host)<\/td><td>Yes (<code>pm2 reload<\/code>)<\/td><td>Single app, minimal moving parts<\/td><\/tr><tr><td><strong>Docker<\/strong><\/td><td>Medium \u2014 write a Dockerfile<\/td><td>High (containerised)<\/td><td>Yes (rolling with Compose)<\/td><td>Reproducible, portable deploys<\/td><\/tr><tr><td><strong>Coolify<\/strong><\/td><td>Low ongoing \u2014 one-time install<\/td><td>High (containers under the hood)<\/td><td>Yes (built-in)<\/td><td>Best DX, Git push-to-deploy<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<p>In short: PM2 is the leanest, Docker is the most portable and reproducible, and Coolify gives you the smoothest ongoing workflow. We compare the self-hosted PaaS route in more depth in our <a href=\"https:\/\/ukspeed.co.uk\/blog\/coolify-vs-vercel-vs-netlify-self-host-paas-on-uk-vps-2026\/\">Coolify vs Vercel vs Netlify<\/a> piece.<\/p>\n\n<h2 class=\"wp-block-heading\">How to Build Next.js for Production<\/h2>\n\n<p>Every method starts from the same production build. Pull your code onto the server (or your CI runner), install dependencies deterministically with <code>npm ci<\/code>, then run <code>next build<\/code>. The reproducible install matters \u2014 it uses your lockfile exactly.<\/p>\n\n<pre class=\"wp-block-code\"><code>git clone https:\/\/github.com\/your-org\/your-app.git\ncd your-app\nnpm ci\nnpm run build   # runs next build\nnpm run start   # runs next start on port 3000<\/code><\/pre>\n\n<p>For the Docker route especially, enable standalone output so the runtime image only ships what it needs:<\/p>\n\n<pre class=\"wp-block-code\"><code>\/\/ next.config.js\nmodule.exports = {\n  output: 'standalone',\n};<\/code><\/pre>\n\n<p>If any step is unclear, the official documentation is excellent \u2014 see <a href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/deploying\" rel=\"noopener\" target=\"_blank\">the official Next.js deployment docs<\/a> for the full self-hosting reference.<\/p>\n\n<h2 class=\"wp-block-heading\">How to Deploy Next.js with PM2<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/nx2-pm2.svg\" alt=\"Deploying Next.js with PM2 on a UK VPS: build, start, save and zero-downtime reload\" class=\"wp-image-2535\" \/><figcaption class=\"wp-element-caption\">PM2 runs next start as a managed process &mdash; auto-restart on crash, boot persistence and zero-downtime reloads.<\/figcaption><\/figure>\n\n\n<p><strong>PM2<\/strong> is a process manager for Node.js that keeps your app running, restarts it on crashes and survives reboots. It is the simplest way to deploy Next.js: no containers, just Node and a small tool. After building, start the app under PM2 and give it a name.<\/p>\n\n<pre class=\"wp-block-code\"><code>npm ci &amp;&amp; npm run build\npm2 start \"npm run start\" --name myapp\n# or run the binary directly:\n# pm2 start node_modules\/.bin\/next --name myapp -- start\n\npm2 save          # persist the current process list\npm2 startup       # generate the boot service, then run the printed command<\/code><\/pre>\n\n<p>To ship a new version with <strong>zero downtime<\/strong>, rebuild and then reload \u2014 PM2 restarts workers gracefully so requests are not dropped:<\/p>\n\n<pre class=\"wp-block-code\"><code>git pull &amp;&amp; npm ci &amp;&amp; npm run build\npm2 reload myapp<\/code><\/pre>\n\n<p>Getting PM2 to reliably relaunch after a server reboot has one or two gotchas; our guide to <a href=\"https:\/\/ukspeed.co.uk\/blog\/pm2-resurrect-node-js-uk-vps-auto-restart-after-reboot-2026\/\">PM2 auto-restart on a UK VPS<\/a> walks through <code>pm2 save<\/code> and <code>pm2 startup<\/code> in detail.<\/p>\n\n<h2 class=\"wp-block-heading\">How to Deploy with Docker and Coolify<\/h2>\n\n<p><strong>Docker<\/strong> packages your app and its runtime into an image that runs identically on any machine. A multi-stage Dockerfile keeps the final image tiny by building in one stage and copying only the standalone output into the runner.<\/p>\n\n<pre class=\"wp-block-code\"><code># deps\nFROM node:20-alpine AS deps\nWORKDIR \/app\nCOPY package*.json .\/\nRUN npm ci\n\n# build\nFROM node:20-alpine AS build\nWORKDIR \/app\nCOPY --from=deps \/app\/node_modules .\/node_modules\nCOPY . .\nRUN npm run build\n\n# runner\nFROM node:20-alpine AS runner\nWORKDIR \/app\nENV NODE_ENV=production\nCOPY --from=build \/app\/.next\/standalone .\/\nCOPY --from=build \/app\/.next\/static .\/.next\/static\nCOPY --from=build \/app\/public .\/public\nEXPOSE 3000\nCMD [\"node\", \"server.js\"]<\/code><\/pre>\n\n<p>Build and run it, or manage it with Docker Compose alongside a database and cache. For a full multi-service pattern, see our <a href=\"https:\/\/ukspeed.co.uk\/blog\/docker-compose-wordpress-production-on-uk-vps-full-stack-setup-guide-2026\/\">Docker Compose on a UK VPS<\/a> walkthrough.<\/p>\n\n<pre class=\"wp-block-code\"><code>docker build -t myapp .\ndocker run -d --name myapp -p 3000:3000 --env-file .env myapp<\/code><\/pre>\n\n<p><strong>Coolify<\/strong> is a self-hosted PaaS you install on the VPS once \u2014 think Heroku or Vercel, but on your own hardware. You connect a Git repository through its web UI, and it builds and deploys your Next.js app automatically on every push, provisions HTTPS for you and manages containers behind the scenes. It offers the best ongoing developer experience of the three, and pairs neatly with a <a href=\"https:\/\/ukspeed.co.uk\/blog\/self-hosted-cicd-uk-vps-gitea-actions-vs-woodpecker-vs-drone-2026\/\">self-hosted CI\/CD<\/a> pipeline if you want tests to run before each deploy.<\/p>\n\n<h2 class=\"wp-block-heading\">Configure Nginx as a Reverse Proxy<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/nx3-proxy.svg\" alt=\"Nginx reverse proxy terminating HTTPS and forwarding to Next.js on localhost:3000 on a UK VPS\" class=\"wp-image-2537\" \/><figcaption class=\"wp-element-caption\">Nginx terminates HTTPS on 443 and proxies to Next.js on localhost:3000 &mdash; keep only 443 public.<\/figcaption><\/figure>\n\n\n<p>Whichever method you choose, your Next.js server listens on localhost:3000. You should not expose that directly. Instead put Nginx (or Caddy) in front on ports 80 and 443 to terminate TLS, forward requests and set the correct proxy headers. Note that Coolify handles this layer for you automatically; the block below is for the PM2 and Docker routes.<\/p>\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    server_name example.co.uk;\n\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n    }\n\n    gzip on;\n    gzip_types text\/css application\/javascript application\/json;\n}<\/code><\/pre>\n\n<p>Add free HTTPS with Let&#8217;s Encrypt via Certbot, which edits the config to listen on 443 and auto-renews:<\/p>\n\n<pre class=\"wp-block-code\"><code>sudo certbot --nginx -d example.co.uk<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">Handling Environment Variables Safely<\/h3>\n\n<p>Store configuration in a <code>.env<\/code> file or your platform&#8217;s environment settings, never in the repository. In Next.js, variables prefixed with <code>NEXT_PUBLIC_<\/code> are baked into the client bundle and visible in the browser, so use that prefix only for non-secret values. Everything else \u2014 API keys, database URLs \u2014 stays server-side. Remember that public variables are read at build time, so rebuild after changing them.<\/p>\n\n<h2 class=\"wp-block-heading\">Choose the Right Deployment Method<\/h2>\n\n<p>There is no single best answer \u2014 the right choice depends on your team and workload:<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>Choose PM2<\/strong> if you run a single app, want the least overhead and are comfortable managing Node.js directly on the server.<\/li><li><strong>Choose Docker<\/strong> if reproducibility and portability matter, you run multiple services, or you want your local, CI and production environments to match exactly.<\/li><li><strong>Choose Coolify<\/strong> if you want a Vercel-like push-to-deploy experience with automatic HTTPS and a web UI, without hand-rolling the plumbing.<\/li><\/ul>\n\n<p>Many teams start with PM2 for its simplicity, then graduate to Docker or Coolify as their needs grow. All three run comfortably on a modest UK VPS, and because the underlying Node.js build is identical, switching between them later is straightforward rather than a rewrite.<\/p>\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n<p>You can deploy Next.js on a UK VPS in production with any of these three approaches, and each is a legitimate Vercel alternative that gives you cost control, full ownership of your infrastructure and UK data residency. PM2 keeps things lean, Docker makes deploys portable and reproducible, and Coolify delivers the smoothest ongoing experience \u2014 all sitting behind an Nginx reverse proxy with free HTTPS.<\/p>\n\n<p>Pick the method that matches your team&#8217;s comfort level today; you can always migrate later, because a VPS keeps your options open.<\/p>\n\n<ul class=\"wp-block-list\"><li>Provision a UK VPS with Node.js or Docker installed and hardened SSH.<\/li><li>Run <code>next build<\/code>, then start your app under PM2, Docker or Coolify.<\/li><li>Put Nginx in front and add HTTPS with Let&#8217;s Encrypt.<\/li><li>Set your environment variables securely and enable zero-downtime reloads.<\/li><\/ul>\n\n\n<div class=\"wp-block-group uks-cta-box has-border-color\" style=\"border-color:#bfdbfe;border-style:solid;border-width:1px;border-radius:14px;background-color:#eff6ff;padding:30px\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n\n<h3 class=\"wp-block-heading has-text-color\" style=\"color:#0f172a\">Deploy your Next.js app on a UK Speed VPS<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color:#334155\">Get the CPU, RAM and full root access to build and run Next.js with PM2, Docker or Coolify on high-performance AMD EPYC hardware, hosted in the UK with predictable pricing.<\/p>\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-text-color has-background wp-element-button\" href=\"https:\/\/ukspeed.co.uk\/vps-high-performance\" style=\"border-radius:8px;color:#ffffff;background-color:#2563eb\">Explore high-performance UK VPS &rarr;<\/a><\/div>\n<\/div>\n\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>If you want full control over cost, performance and where your data lives, learning to deploy Next.js on a VPS is one of the\u2026<\/p>\n","protected":false},"author":3,"featured_media":2543,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[105],"tags":[143,148,147,146,113,136,140],"class_list":["post-2532","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-database","tag-dns","tag-docker","tag-linux","tag-performance","tag-ssl","tag-vps"],"_links":{"self":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2532","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=2532"}],"version-history":[{"count":5,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2532\/revisions"}],"predecessor-version":[{"id":2562,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2532\/revisions\/2562"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/media\/2543"}],"wp:attachment":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=2532"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=2532"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=2532"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}