Skip to main content

Deploying Next.js on Prostack Cito

Part 3 of our Cito series: how to get a Next.js app live on Cito with nginx and Passenger, plus environment variables, redeploys and the MCP server.

Deploying Next.js on Prostack Cito

Jimmy Crutchfield

· Prostack Cito

This is part three of our Cito series, showing how agencies and developers can get up and running quickly on Cito. You can catch up on parts one and two here:

Next.js is now the default way agencies build anything React-shaped, from marketing sites to full applications. Cito runs Node applications natively through nginx and Passenger, which means you get proper process management without wrestling with PM2, systemd units or reverse proxy configs.

Here’s how to get a Next.js app live on Cito, and what to know once it’s running.

A quick word on how Node works on Cito

Cito serves Node applications via nginx and Passenger. Passenger sits inside nginx and handles the bits you’d normally have to think about yourself: starting your app, restarting it if it crashes, spinning up processes and proxying requests to them. There’s no separate application server or process manager to babysit.

We run Node 22 (the current LTS) by default, with npm and Yarn pre-installed. If you need a different version, Support can install it for you, though bear in mind only one Node version runs on a server at a time.

Creating the site

Log into Cito and click Create Site in the top right, then choose NodeJS as the site type.

Enter your domain without the www, pick an SSH user (or leave it blank and we’ll generate one), and click Create Site. You’ll get:

  • The site’s username and home directory
  • A preview URL, so you can test before touching DNS

Getting your code onto the server

Every Cito site has its own system user and home directory. There are a few ways to deploy your code.

Connect a Git repository. The easiest route. You can link a repo in the Create Site wizard, or from Site Settings for an existing site. Authorise Cito to talk to your GitHub account, pick the repository and branch, and Cito clones it into the site’s document root for you. From then on you can see recent commits in the dashboard and pull the latest changes with one click on Deploy latest, no SSH required. See our Git guide for the details.

If you plan to use this feature, connect the repo through the dashboard rather than cloning it yourself over SSH first. Repos cloned manually won’t show up in Site Settings.

Git sync gets your code onto the server, but Next.js still needs its dependencies and a build. So after a deploy, log in and run:

npm install
npm run build
passenger-config restart-app

Clone it yourself. If you’d rather do the whole thing over SSH:

ssh mysite@your-server
git clone [email protected]:youragency/yourapp.git .
npm install
npm run build

As always on Cito: deploy as the site user, not admin. That goes for CI pipelines too. It keeps permissions clean and saves you a headache later.

Deploy with AI. If you use Claude Code or Cursor, our MCP server can deploy the project for you. More on that below.

The entrypoint

Passenger looks for app.js in your application directory as the entrypoint. Next.js doesn’t ship one, so you’ll add a small wrapper:

// app.js
const next = require('next');
const http = require('http');

const app = next({ dev: false });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  http.createServer((req, res) => handle(req, res)).listen(3000);
});

Don’t worry about the port number. Passenger intercepts the listen() call and wires your app into nginx itself, so nothing actually binds to port 3000.

If you’d rather use a different filename, you can change the passenger_startup_file directive in your site’s nginx config at /etc/nginx/conf.d/<username>.conf (you’ll need to be logged in as admin for that one).

Environment variables

.env files stay on the server; they’re never part of a deployment. Create your .env.production (or .env.local) over SSH or with the built-in File Manager, then rebuild if you’ve changed anything Next.js bakes in at build time. Remember that NEXT_PUBLIC_ variables are compiled into the client bundle, so a rebuild isn’t optional there.

Going live

Test on the preview URL first. It’s on the site creation screen, and it works before any DNS changes.

Point your DNS. An A record aimed at your Cito server’s IP is all you need.

SSL is automatic. Cito issues Let’s Encrypt certificates for any domain that resolves to the server and renews them on its own. If you’re behind Cloudflare or another proxy, we won’t issue a certificate, as those services terminate SSL themselves.

Restarts and redeploys

When you ship new code, rebuild and tell Passenger to restart the app. The tidy way:

npm run build
passenger-config restart-app

Run it without arguments and it’ll ask which app to restart. There’s also the classic Passenger trick of touching tmp/restart.txt in your application directory, which works nicely at the end of a deploy script:

mkdir -p tmp && touch tmp/restart.txt

Passenger notices the timestamp change and restarts the app for you.

Running Next.js another way

Passenger is the path of least resistance, but it’s not the only one. If your setup doesn’t fit (a custom server, a monorepo with odd requirements, or you just prefer containers), Cito’s Reverse Proxy site type lets you run next start under Docker or PM2 on a port of your choosing, with nginx proxying to it. You still get automatic SSL and the same dashboard.

And if your site is fully static (output: 'export'), you don’t need a Node site at all. Just build it and upload the output.

Managing your site with the MCP server

Cito’s MCP server connects Claude Code, Claude, Cursor and other AI tools straight to your Cito server.

Connecting Claude Code is one command:

claude mcp add --transport http Cito https://mcp.prostack.uk/mcp

Then run /mcp in your session to authenticate through the Prostack Portal. From there:

  • Deploy a project. Say “deploy this project to Cito” and the model detects Node, offers to create a site with the right deployment profile, rsyncs your files and runs the relevant post-install commands like npm install. Directories like node_modules and sensitive files like .env are excluded automatically.
  • Spin up staging. “Clone mysite.com to staging.mysite.com” copies the site so you can test safely.
  • Check logs mid-debug. “Show me the last 50 lines of the error log for mysite.com” pulls them into your session. With Passenger, your app’s console output lands in the nginx error log, so this is where your console.error calls end up too.
  • Manage databases. “Create a MySQL database called app_db and add a read-only user to it.”

There are guardrails in place for destructive operations. Deleting sites or databases needs explicit confirmation, deployments use ephemeral SSH keys that never touch disk, and only specific framework-relevant commands can run. It’s a beta and LLMs can misbehave, so review tool calls before approving them.

That’s it

You’ve now got a Next.js app on a managed server, with Passenger keeping the process alive, SSL renewing itself, and an AI assistant on hand for deploys and debugging if you want one.

If there’s something you’d like Cito to do better for Node projects, tell us on our feedback site. And Support are always available if you get stuck.