Your First Cumulus Machine

Your Cumulus machine can serve content to the Internet when you set up web services, but machine access requires VPN connection. **WARNING: This machine must only be used for course activities. Unauthorized use for private projects will result in immediate loss of access and potential disciplinary action.**
The SSH key you have received should be considered a secret. Never share it with third parties or display it publicly.

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.

  1. 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

    Download the private key file (id_cumulus_xxx) to a known location at your computer.

  2. 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:

  3. 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.

  1. 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
  2. Connect using SSH

    Open your terminal (Git Bash on Windows) and run:

    Replace:

    • id_cumulus_xxx with the actual filename of your private key
    • cuXXXX.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.

  3. 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.

  1. 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.

  2. Install Node.js

    Once the repository is added, install Node.js and npm:

    The -y flag automatically confirms the installation.

  3. 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.

  1. Install nginx

    Run the following command to install nginx:

    This installs the nginx package and its dependencies.

  2. Start the nginx Service

    Once installed, start the nginx service:

    This launches the web server.

  3. Enable nginx to Start on Boot

    To make sure nginx starts automatically when the machine boots:

  4. 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.

  1. 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.

  2. 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
  3. 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.

  1. Prerequisites

    • Your server has a floating IP address in the Cumulus campus network.
    • You have sudo privileges.
    • Nginx is installed and running.
  2. 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 named LNU_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.

  3. 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.

  4. 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.
  5. 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.

  1. 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.

  2. 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
  3. 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

  4. HTTP vs HTTPS Behavior

    Now that HTTPS is configured:

    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.

  1. Edit the nginx Configuration

    Open the main nginx configuration file:

  2. 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.

  3. Save and Exit

    In nano:

    • Press Ctrl + O to save
    • Press Enter to confirm
    • Press Ctrl + X to exit
  4. Test the Configuration

    Before restarting nginx, always test that your configuration is valid:

    You should see:

  5. Restart nginx

    Apply the changes by restarting the nginx service:

  6. 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.

  1. Create a New Directory for Your Website

    Create a dedicated directory for your hello-world website:

  2. Set Proper Ownership

    Change ownership to the ubuntu user so you can edit files without sudo:

  3. Create Your Custom index.html

    Create your hello-world homepage:

    Add the following content:

  4. 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 the server_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

  5. 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.

  6. Disable the Default Site and Enable Your Hello-World Site

    Remove the default nginx site and enable your custom hello-world site:

  7. Test and Restart nginx Configuration

    Always test the configuration before applying changes:

    If the test is successful, restart nginx:

  8. 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 website
  • https://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:

  1. 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
  2. Navigate to your home directory

  3. 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
  4. Install Dependencies

  5. 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:

  1. Create Project Directory

  2. Create package.json

    Add the following content:

  3. Create Source Directory and Server File

    Add the following Express application code:

  4. Install Dependencies

  5. 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:

  1. Create Express App Location Configuration

    Instead of modifying the main nginx file, create a separate configuration for the Express app:

    Add the following configuration:

  2. 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.

  3. Start Your Express Application

  4. 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.

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.

  1. 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.

  2. Create the Ecosystem Configuration File

    Navigate to your web directory and create a PM2 ecosystem file:

  3. 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 file
    • cwd - Working directory for the application
    • exec_mode: "fork" - Runs a single Node.js process (vs "cluster" for multiple processes)
    • instances: 1 - Number of processes to run
    • env - Environment variables for production mode
  4. 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.

  5. Verify Applications are Running

    Check the status of your PM2-managed applications:

    You should see output similar to:

  6. Test Your Express Application

    Visit your Express application in a browser:

    The application should be working normally.

  7. 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.

  8. 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:

    1. Copy the command that PM2 outputs in YOUR terminal (not the example above)
    2. Paste and execute that specific command with sudo
    3. 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 and pm2 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