Your First Cumulus Machine
What is Cumulus?
Cumulus is Linnaeus University's cloud computing platform that provides students with personal virtual machines for course-related projects and exercises. Each student receives:
- A personal Ubuntu Linux server running in the cloud
- Root-level access to install software and configure services
- Public internet connectivity with a unique DNS name (e.g.,
cuXXXX.camp.lnu.se
) - SSH access through the university's VPN network
What you can do with your Cumulus machine:
- Deploy web applications and APIs
- Learn Linux system administration
- Practice server configuration and security
- Host course projects accessible from anywhere on the internet
- Experiment with different technologies without affecting your personal computer
Important limitations:
- Access requires connection to the university VPN
- The machine is for course-related activities only - not personal projects
- Your machine and data may be reset between courses
- Resource usage is monitored and limited
Think of Cumulus as your personal sandbox server where you can safely learn and experiment with real-world server technologies in a controlled environment.
Step 1: Verify SSH Availability
Before you can connect to your Cumulus machine, make sure that the ssh command is available in your terminal.
On Windows
If you're using Windows 10 or later, the built-in PowerShell or Command Prompt usually includes SSH, but use Git Bash as your terminal (this guide assumes you're using a Bash terminal).
To check, open a terminal and run:
If you see a version number (e.g., OpenSSH_9.9p1, OpenSSL 3.2.3 3 Sep 2024), you're good to go.
If SSH is not available, you can:
- Install OpenSSH Client via Windows Features (Settings → Apps → Optional Features).
- Use Windows Terminal with PowerShell or Command Prompt.
- Install Windows Subsystem for Linux (WSL) - provides a complete Linux environment with native SSH support.
- Alternatively, install PuTTY, though this guide assumes OpenSSH command-line tools.
On macOS and Linux
SSH is typically pre-installed. You can verify with:
Step 2: Download and Move Your Identity File
To access your personal machine in the Cumulus cloud via SSH, you need to install your identity file (private key).This file is provided through a GitLab project.
Locate the Identity File in GitLab
- Go to the Secrets project in GitLab
- In this project, you will find:
- Your private key file (named something like
id_cumulus_xxx
) - The IP address of your machine
- The DNS name assigned to your machine
- Your private key file (named something like
Download the private key file (id_cumulus_xxx) to a known location at your computer.
Move the file to your .ssh directory
Create the .ssh directory if it doesn't already exists:
Move the identity file to the .ssh directory:
Set correct permissions on the file
Setting the correct permissions ensures that your private key is only readable by you. SSH will refuse to use the key if it’s accessible by others, as this would pose a security risk.
Note for Windows users: When using Git Bash,
chmod 600
works as expected and ensures your key is accepted by SSH, even though Windows handles file permissions differently under the hood.
Step 3: Connect to Your Cumulus Machine via SSH
Once your identity file is in place and has the correct permissions, you can connect to your personal machine in the Cumulus cloud using SSH.
Use the DNS name (or IP address)
In the GitLab Secrets project, you will find either:
- The DNS name of your machine (recommended), e.g. cuXXXX.camp.lnu.se
- Or the IP address, e.g. 172.27.XXX.XXX
Connect using SSH
Open your terminal (Git Bash on Windows) and run:
Replace:
id_cumulus_xxx
with the actual filename of your private keycuXXXX.camp.lnu.se
with your machine’s DNS name (or IP address)
📌 Example
If this is your first time connecting, you may be asked to confirm the host's fingerprint. Type yes to continue.
🔧 Troubleshooting: Remove a Previously Registered Key
If you’ve connected to your machine before and the host key has changed (for example, due to a reinstallation), SSH may refuse to connect and show a warning about a mismatched key.
To fix this, remove the old key from your known hosts file:
Replace
cuXXXX.camp.lnu.se
with your machine’s actual DNS name or IP address. This command deletes the outdated entry from~/.ssh/known_hosts
, allowing you to reconnect without errors.What Happens When You Successfully Connect
If the SSH connection is successful, you’ll see a welcome message from the Ubuntu operating system, along with system information such as memory usage, IP address, and login history.
You will land in your home directory, typically
/home/ubuntu
, and the prompt will look something like:From here, you can start working on your machine — installing packages, running applications, or setting up web services
Step 4: Update Package Lists
Before installing any software on your Cumulus machine, it's good practice to update the package lists. This ensures that you get the latest available versions of packages from the Ubuntu repositories.
You are logged in as a regular user (ubuntu), so administrative commands like
apt
update
require sudo
.
Run the following command:
This command fetches the most recent information about available packages and updates, which is necessary before installing tools like Node.js, npm, and nginx.
You only need to run this once before installing multiple packages. There's no need to repeat it before each installation unless a significant amount of time has passed or you've added new repositories.
Step 5: Install Node.js and npm
To run JavaScript applications on your Cumulus machine, you need to install Node.js and its package manager npm.
Add the NodeSource Repository
Start by adding the official NodeSource repository for Node.js version 22:
This command downloads and runs a setup script that configures your system to use the NodeSource repository.
Install Node.js
Once the repository is added, install Node.js and npm:
The
-y
flag automatically confirms the installation.Verify the Installation
After installation, check that both Node.js and npm are available:
You should see version numbers printed in the terminal, confirming that the installation was successful.
Step 6: Install and Start nginx
To serve web content from your Cumulus machine, you need to install a web server. We use nginx, a lightweight and high-performance HTTP server.
Install nginx
Run the following command to install nginx:
This installs the nginx package and its dependencies.
Start the nginx Service
Once installed, start the nginx service:
This launches the web server.
Enable nginx to Start on Boot
To make sure nginx starts automatically when the machine boots:
Check nginx Status
You can verify that nginx is running with:
You should see output indicating that the service is active (running).
Step 7: Verify nginx in Your Browser
Once nginx is installed and running, you can verify that it works by accessing your machine in a web browser using HTTP.
Use the DNS Name
Open a browser and enter your machine’s DNS name in the address bar, using http:
Replace cuXXXX.camp.lnu.se with your actual DNS name.
Expected Result
You should see the default Welcome to nginx! page. This confirms that:
- nginx is installed correctly
- the service is running
- your machine is reachable over the network
If you don’t see the page, double-check that:
- VPN is connected
- nginx is running (
systemctl status nginx
) - You used the correct DNS name
What Happens If You Use HTTPS?
At this stage, your nginx server is only configured to serve content over HTTP. If you try to access your machine using HTTPS, like:
…you will likely see a browser warning or error such as:
- "Your connection is not private"
- "This site can’t provide a secure connection"
- "ERR_SSL_PROTOCOL_ERROR"
This is expected, because no SSL/TLS certificate has been installed yet.
You will configure HTTPS and install certificates in the next step.
Step 8: Request and Install a TLS Certificate from LNU FTK Campus CA
To enable HTTPS on your virtual server in the Cumulus network, you can request a certificate using Certbot and the LNU FTK Campus CA.
Prerequisites
- Your server has a floating IP address in the Cumulus campus network.
- You have sudo privileges.
- Nginx is installed and running.
Install the LNU FTK Campus Root CA Certificate
Download and install the root certificate so that Certbot can validate the CA:
Verify that the certificate is installed:
You should see that the system has created a hash-based symlink pointing to a
.pem
file, and another symlink namedLNU_FTK_Campus_Root_CA_2025.pem
pointing to the original.crt
file. This confirms that the certificate has been added to the system trust store and is available for use by Certbot and other tools.Install Certbot
Install Certbot using Snap and make it available via /usr/bin/certbot:
This ensures that Certbot is available system-wide and can be used with plugins like Nginx.
Request and Install the Certificate
Use Certbot to request a certificate from the LNU FTK Campus CA using the Nginx plugin and the custom ACME endpoint. The command below automatically derives the correct FQDN from the server's floating IP:
This command:
- Uses the LNU FTK Campus ACME endpoint.
- Automatically converts your floating IP to the correct FQDN.
- Requests and installs the certificate via the Nginx plugin.
Test and Restart nginx Configuration
After Certbot has modified your nginx configuration, always test that the configuration is valid before proceeding:
You should see:
If the test is successful, restart nginx to apply the changes:
Step 9: Verify HTTPS in Your Browser
After installing the TLS certificate, you should verify that HTTPS is working correctly on your nginx server.
Test HTTPS Access
Open a browser and enter your machine's DNS name using HTTPS:
Replace cuXXXX.camp.lnu.se with your actual DNS name.
Expected Result
You should see:
- The same Welcome to nginx! page as before
- A secure connection indicator (lock icon) in your browser's address bar
- No security warnings or certificate errors
This confirms that:
- The TLS certificate is installed correctly
- HTTPS is properly configured
- Your connection is encrypted and secure
Troubleshooting HTTPS Issues
If you encounter problems:
Certificate errors: Verify the certificate installation with:
Nginx configuration: Check that nginx is using the certificate:
Browser cache: Try a hard refresh (Ctrl+F5) or test in an incognito/private window
HTTP vs HTTPS Behavior
Now that HTTPS is configured:
- HTTP requests (http://cuXXXX.camp.lnu.se) should automatically redirect to HTTPS
- HTTPS requests (https://cuXXXX.camp.lnu.se) should work directly with a secure connection
This automatic redirection is configured by Certbot when it updates your nginx configuration.
Step 10: Secure nginx Configuration
Now that HTTPS is working, it's time to enhance the security of your nginx server by modifying the configuration and removing unnecessary information disclosure.
Edit the nginx Configuration
Open the main nginx configuration file:
Hide Server Version Information
Find the
http
block in the configuration file. Look for the commented line:Uncomment this line by removing the
#
at the beginning:This prevents potential attackers from knowing which specific version of nginx you're running.
Save and Exit
In nano:
- Press
Ctrl + O
to save - Press
Enter
to confirm - Press
Ctrl + X
to exit
- Press
Test the Configuration
Before restarting nginx, always test that your configuration is valid:
You should see:
Restart nginx
Apply the changes by restarting the nginx service:
Verify the Security Enhancement
Test that the version information is now hidden by checking the HTTP headers:
Replace
cuXXXX.camp.lnu.se
with your actual DNS name.Before the change, you would see:
After the change, you should only see:
This simple security enhancement reduces information leakage that could be useful to potential attackers.
Step 11: Create Your Own Static Website
Instead of using the default nginx page, let's create your own custom website with a dedicated directory structure.
Create a New Directory for Your Website
Create a dedicated directory for your hello-world website:
Set Proper Ownership
Change ownership to the ubuntu user so you can edit files without sudo:
Create Your Custom index.html
Create your hello-world homepage:
Add the following content:
Create a New nginx Site Configuration
Create a dedicated configuration file for your domain:
Add the following configuration:
Important: Replace
cuXXXX.camp.lnu.se
with your actual DNS name in both theserver_name
and SSL certificate paths.Configuration Breakdown:
- First server block (HTTP): Redirects all HTTP traffic to HTTPS for security
- Second server block (HTTPS): Handles encrypted connections on port 443
- http2: Enables HTTP/2 protocol for faster page loading and better performance
- SSL certificates: Points to the certificates installed by Certbot
- root /var/www/hello-world: Sets the directory for static files
- location /: Serves static files, returns 404 if not found
- include locations/*.conf: Loads configurations for dynamic applications
HTTP/2 Benefits:
HTTP/2 is automatically enabled in your nginx configuration and provides:
- Multiplexing - Multiple requests over a single connection
- Header compression - Reduced overhead for HTTP headers
- Server push - Proactive resource delivery (if configured)
- Binary protocol - More efficient than HTTP/1.1 text-based protocol
You can verify HTTP/2 is working by checking in your browser's Developer Tools (Network tab) or using online tools like https://tools.keycdn.com/http2-test
Create Directory for Application Configurations
Create a dedicated directory structure for modular nginx configurations. This allows you to manage each application separately:
This directory will store individual
.conf
files for each application you deploy, making it easy to add, remove, or modify applications without touching the main site configuration.Disable the Default Site and Enable Your Hello-World Site
Remove the default nginx site and enable your custom hello-world site:
Test and Restart nginx Configuration
Always test the configuration before applying changes:
If the test is successful, restart nginx:
Visit Your Custom Hello-World Website
Open your browser and navigate to:
Replace
cuXXXX.camp.lnu.se
with your actual DNS name.You should now see your custom hello-world website instead of the default nginx page!
Step 12: Create and Deploy an Express Application
Now let's create a dynamic web application using Node.js with Express and deploy it alongside your static website.
📁 What you'll build:
🌐 URL structure:
https://cuXXXX.camp.lnu.se/
→ Static websitehttps://cuXXXX.camp.lnu.se/hello-world-express/
→ Express application
Option A: Clone from GitLab (Recommended)
If you have access to the course GitLab repository with the Express Hello World project:
Set Up GitLab SSH Access on Your Cumulus Machine (First Time Only)
To clone repositories from GitLab directly on your Cumulus machine, you need to configure SSH access. This creates a separate key pair specifically for your Cumulus server to access GitLab repositories.
⚠️ Important: These commands are run on your Cumulus machine (via SSH), not on your local computer.
Generate a new SSH key pair for GitLab on your Cumulus machine:
When prompted:
- Press Enter to save in the default location (
/home/ubuntu/.ssh/id_gitlab
) - Enter a passphrase (optional but recommended)
Display the public key from your Cumulus machine:
Add the public key to your GitLab account:
Copy the entire output from the command above and add it to your GitLab account:
- Go to GitLab → User Settings → SSH Keys
- Paste the public key content
- Give it a descriptive title (e.g., "Cumulus Machine cuXXXX")
- Click "Add key"
Configure SSH on your Cumulus machine to use the GitLab key:
Add the following configuration:
Test the connection from your Cumulus machine:
You should see: "Welcome to GitLab, @yourusername!"
What you've created:
- A separate SSH key pair on your Cumulus machine for GitLab access
- SSH configuration that uses this key automatically for GitLab
- Secure connection between your Cumulus machine and GitLab repositories
- Press Enter to save in the default location (
Navigate to your home directory
Clone the Express Hello World Project
You'll use a two-step process: clone in home directory, then move to the web directory:
💡 Why you don't clone directly to
/var/www/
:- ❌
sudo git clone
→ SSH uses root's keys (which don't exist) - ❌ Direct clone to
/var/www/
→ Permission denied (directory owned by root) - ✅ Clone to home → move → fix ownership = Clean and simple solution
- ❌
Install Dependencies
Test the Application
You should see:
🚀 Server is running on http://localhost:3000
Test locally:
curl http://localhost:3000
Stop the server with
Ctrl + C
before proceeding to nginx configuration.
Option B: Create from Scratch (Fallback)
If you don't have access to the GitLab repository, create the application manually:
Create Project Directory
Create package.json
Add the following content:
Create Source Directory and Server File
Add the following Express application code:
Install Dependencies
Test the Application
Configure nginx as Reverse Proxy
Regardless of which option you used above, now configure nginx to serve your Express app using the modular configuration approach:
Create Express App Location Configuration
Instead of modifying the main nginx file, create a separate configuration for the Express app:
Add the following configuration:
Test and Restart nginx Configuration
Test the configuration and restart nginx:
No need to modify symlinks since we're using the include directive from Step 11.
Start Your Express Application
Test Your Setup
Now you can access:
- Static website:
https://cuXXXX.camp.lnu.se/
- Express app:
https://cuXXXX.camp.lnu.se/hello-world-express/
- Test error handling:
https://cuXXXX.camp.lnu.se/hello-world-express/test/throw-error
- Test crash (dangerous!):
https://cuXXXX.camp.lnu.se/hello-world-express/test/crash
Important: Replace
cuXXXX.camp.lnu.se
with your actual DNS name.- Static website:
What You've Accomplished:
- Deployed an Express application with ES6 modules
- Configured nginx as a reverse proxy
- Set up both static and dynamic content on the same domain
- Added test routes with intentional errors and crashes
Critical Discovery:
Notice that when you close your terminal or visit /hello-world-express/test/crash
,
your Express application stops working completely! This demonstrates a fundamental
problem with running Node.js applications directly - they don't survive crashes
or disconnections.
This is why we need a process manager in the next step!
Step 13: Install and Configure PM2 Process Manager
As you discovered in the previous step, Node.js applications stop running when you close your terminal or when they crash. PM2 (Process Manager 2) solves this problem by keeping your applications running in the background, automatically restarting them on crashes, and providing process monitoring.
Instead of managing each application separately, we'll use a YAML configuration file to define all our applications in one place.
Install PM2 using npm
Install PM2 globally so it's available system-wide:
This installs PM2 as a global package, making the
pm2
command available from anywhere on your system.Create the Ecosystem Configuration File
Navigate to your web directory and create a PM2 ecosystem file:
Configure Your Applications
Edit the ecosystem configuration file:
Add the following YAML configuration:
Configuration notes:
script: "src/server.js"
- Direct path to the Node.js application filecwd
- Working directory for the applicationexec_mode: "fork"
- Runs a single Node.js process (vs "cluster" for multiple processes)instances: 1
- Number of processes to runenv
- Environment variables for production mode
Start All Applications with PM2 Using the Ecosystem File
Use PM2 to start all applications defined in your ecosystem file:
PM2 will read the configuration and start your Express application.
Verify Applications are Running
Check the status of your PM2-managed applications:
You should see output similar to:
Test Your Express Application
Visit your Express application in a browser:
The application should be working normally.
Test Crash Recovery
Try the crash test route to see PM2's auto-restart feature:
What happens:
- The application crashes (as intended)
- PM2 automatically detects the crash
- PM2 immediately restarts the application
- Your application is available again within seconds
Check PM2 status after the crash:
You should see the restart count has increased, showing that PM2 successfully restarted your application.
Configure PM2 to Start on Server Boot
⚠️ Critical for Production: Without this configuration, your applications will NOT restart automatically when the server reboots, leading to downtime.
For a production server, it's essential that your applications start automatically when the server reboots. PM2 provides a simple way to configure this.
Generate the startup script:
This command will analyze your system and output a custom command that you need to execute. The output will look similar to this:
📋 Important Steps:
- Copy the command that PM2 outputs in YOUR terminal (not the example above)
- Paste and execute that specific command with sudo
- Each server generates a unique command - yours will be different from the example
Example of what to do:
⚠️ Warning: The exact command will be different on your system. Always use the command that PM2 generates for YOUR specific server configuration.
Save your current PM2 configuration:
This saves the current list of running applications so they're restored on boot.
Test the boot persistence:
You can test this by rebooting your server:
After the server comes back online, reconnect via SSH and check:
Your applications should be running automatically without any manual intervention.
Monitor Your Applications
View real-time logs from all applications:
View logs for a specific application:
Monitor processes in real-time:
(Press q
to exit the monitor)
✅ What You've Accomplished
- Installed PM2 process manager
- Created a YAML ecosystem configuration file for managing multiple applications
- Configured centralized logging for your applications
- Set up automatic crash recovery and restart functionality
- Enabled applications to start automatically on server boot
- Learned essential PM2 monitoring and management commands
🗝️ Key Benefits of Using PM2
- Process persistence - Applications survive terminal disconnections
- Automatic restart - Crashed applications are immediately restarted
- Centralized logging - All application logs in one place
- Easy scaling - Can run multiple instances of applications
- Boot persistence - Applications start automatically when server boots
- Process monitoring - Real-time monitoring of CPU, memory, and performance
Your Express application is now running as a production-ready service that can handle crashes, server reboots, and provides comprehensive monitoring capabilities!
What's Next?
Now that you have a fully functional web server with HTTPS, static content, dynamic Express applications, and process management, you can:
- Deploy more applications - Add new location blocks for additional services
- Learn database integration - Connect your Express apps to MongoDB or PostgreSQL
- Implement monitoring - Set up log analysis and performance monitoring
- Scale your applications - Use PM2's cluster mode for better performance
- Add CI/CD - Automate deployments from your GitLab repositories
Your Cumulus machine is now a production-ready web server platform!
Summary: Your Server Stack
You've successfully built a complete web server stack:
Technologies mastered:
- ✅ Linux system administration
- ✅ SSH key management
- ✅ nginx web server configuration
- ✅ SSL/TLS certificate management
- ✅ Node.js and Express development
- ✅ Process management with PM2
- ✅ Modular nginx configuration
Common Issues and Solutions
SSH Connection Problems
- "Permission denied": Check key permissions with
ls -l ~/.ssh/id_cumulus_*
- "Host key verification failed": Run
ssh-keygen -R cuXXXX.camp.lnu.se
- "Connection refused": Verify VPN connection and DNS name
nginx Issues
- 502 Bad Gateway: Check if your Node.js app is running with
pm2 status
- 403 Forbidden: Check file permissions in
/var/www/
- 404 Not Found: Verify file paths and nginx configuration syntax
PM2 Problems
- App not starting: Check logs with
pm2 logs
- Port conflicts: Verify ports in ecosystem.config.yml
- Apps not restarting after reboot: Run
pm2 startup
andpm2 save
SSL Certificate Issues
- Certificate expired: Run
sudo certbot renew
- Certificate errors: Verify with
sudo certbot certificates
- Browser warnings: Clear cache or test in incognito mode