πŸ› οΈ From Code to Craftsmanship: Build and Run a Node.js API on Rocky Linux Like a DevOps Blacksmith

Santosh NcSantosh Nc
4 min read

Whether you're a DevOps beginner or a curious developer diving into APIs and backend services, this guide is your anvil and hammer. We'll shape a simple Node.js REST API and deploy it on Rocky Linux, a robust Red Hat-based distro, and even go a step further: configuring it to run as a systemd service β€” like an untiring background worker in your production workshop.


βš™οΈ Why Node.js and Rocky Linux? (The Dynamic Duo)

Picture Node.js as a nimble messenger, swiftly ferrying data between systems. Rocky Linux? It’s your fortress, built for reliability and security. Together, they form the perfect training ground for modern DevOps workflows.


🧱 Step 1: Laying the Foundation (Project Structure)

Think of this like setting up your blacksmith’s workshop β€” tools in place, blueprints organized, and workbenches labeled.

api_mgmt/
β”œβ”€β”€ server.js         # The main control panel
β”œβ”€β”€ package.json      # Toolbox inventory
β”œβ”€β”€ .env              # Secret blueprints (environment variables)
β”œβ”€β”€ .gitignore        # Privacy rules for Git
β”œβ”€β”€ api_mgmt.service  # Instructions for our tireless worker (systemd)
β”œβ”€β”€ controllers/      # The skilled workers
β”‚   └── healthController.js
β”œβ”€β”€ routes/           # Delivery paths
β”‚   └── items.js
β”œβ”€β”€ models/           # Data blueprints (optional)
└── README.md         # Workshop manual

πŸ”¨ Step 2: Crafting the API (The Code)

server.js (The Control Panel)

const express = require('express');
const morgan = require('morgan');
const cors = require('cors');
const healthController = require('./controllers/healthController');
const itemsRouter = require('./routes/items');

const app = express();
const PORT = process.env.PORT || 3000;

app.use(morgan('dev'));
app.use(cors());
app.use(express.json());

app.get('/api/health', healthController.health);
app.use('/api/items', itemsRouter);

app.listen(PORT, () => {
    console.log(`API server running on http://localhost:${PORT}`);
});

controllers/healthController.js

exports.health = (req, res) => {
    res.json({ status: 'ok', message: 'API is running' });
};

routes/items.js

const express = require('express');
const router = express.Router();

let items = [];

router.get('/', (req, res) => res.json(items));

router.post('/', (req, res) => {
    const item = req.body;
    items.push(item);
    res.status(201).json(item);
});

router.put('/:id', (req, res) => {
    const id = parseInt(req.params.id);
    const index = items.findIndex((item) => item.id === id);
    if (index === -1) return res.status(404).json({ error: 'Item not found' });
    items[index] = req.body;
    res.json(items[index]);
});

router.delete('/:id', (req, res) => {
    const id = parseInt(req.params.id);
    items = items.filter((item) => item.id !== id);
    res.status(204).send();
});

module.exports = router;

🧰 Step 3: Gathering Tools (Dependencies and Configs)

.env

PORT=3000

package.json

{
  "name": "api_mgmt",
  "version": "1.0.0",
  "description": "Simple Node.js API",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "author": "Your Name",
  "license": "ISC",
  "dependencies": {
    "express": "^5.1.0",
    "morgan": "^1.10.0",
    "cors": "^2.8.5"
  }
}

Install everything:

npm install

πŸ”₯ Step 4: Starting the Engine

npm start

Test the health route:

curl http://localhost:3000/api/health

Expected response:

{"status":"ok","message":"API is running"}

🧠 Step 5: Running as a Service (The Tireless Worker)

Systemd is like the foreman in your smithy, making sure your API starts automatically and never misses a shift.

api_mgmt.service

Create this in /etc/systemd/system/api_mgmt.service:

[Unit]
Description=Node.js API Management Server
After=network.target

[Service]
Type=simple
User=yourlinuxuser
WorkingDirectory=/home/yourlinuxuser/api_mgmt
ExecStart=/usr/bin/node server.js
Restart=on-failure
EnvironmentFile=/etc/api_mgmt.env

[Install]
WantedBy=multi-user.target

Copy your .env:

sudo cp .env /etc/api_mgmt.env
sudo chmod 644 /etc/api_mgmt.env

Enable the service:

sudo systemctl daemon-reload
sudo systemctl enable --now api_mgmt
sudo systemctl status api_mgmt

πŸš€ Step 6: Leveling Up Your DevOps Skills

Now that your API is humming like a machine, here’s how you can forge it into a full-fledged production tool:

  • πŸ” Security β€” Add JWT or API key-based auth

  • πŸ“ˆ Monitoring β€” Use Grafana + Prometheus

  • πŸ“¦ Containerization β€” Dockerize your app

  • πŸ“œ Docs β€” Add Swagger (OpenAPI)

  • πŸ”„ CI/CD β€” Automate testing + deployment


βœ… You Built a Background Warrior

You've just leveled up from "hello world" to resilient background service on Linux β€” the bread and butter of backend DevOps workflows.

Stay tuned, because in the next guides, we'll:

  • Dockerize this app

  • Add Swagger UI

  • Deploy it with GitHub Actions


πŸ“¬ Like This Guide?

I publish clean, beginner-friendly DevOps content like this weekly β€” practical, local-first, and hands-on.

πŸ‘‰ Subscribe to my newsletter and never miss a post!

Let’s keep building β€” one command, one service, and one forge-fire at a time.


0
Subscribe to my newsletter

Read articles from Santosh Nc directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Santosh Nc
Santosh Nc

I believe, "Hard work beats Talent when Talent doesn't work hard". A Technophile specialising in DevOps.Currently Employed at DevOps Engineer. Shaping my career with Jenkins,Docker, Automation,Poweshell, Python and other devops tools.