How to Deploy a Ktor Application on a VPS: A Step-by-Step Guide

Firuze Gümüş
7 min readDec 29, 2024

--

Deploying a Ktor application can be tricky if you’re new to server setups, but don’t worry — we’re here to simplify the process. In this guide, you’ll learn how to get your Ktor app up and running on an Ubuntu server with persistent availability and professional polish. Let’s dive right in!

Ktor’s official documentation provides deployment guides for platforms like Google App Engine, Heroku and AWS Elastic BeanStalk, but this guide takes a different approach. We’ll focus on deploying your application on a VPS (Virtual Private Server) from any hosting provider, giving you greater flexibility and control over your environment.

Why Ktor?

Ktor’s lightweight and Kotlin-first approach makes it an excellent choice for building APIs or full-stack applications. But for all its simplicity during development, deploying it efficiently requires a few tricks.

Prerequisites

Here’s what you’ll need:

  • A VPS or cloud-based Ubuntu server (preferably 20.04 or later).
  • OpenJDK installed on your server (version 11 or later).
  • A basic understanding of Linux commands.

Quick Server Setup Checklist

sudo apt update && sudo apt upgrade -y
sudo apt install openjdk-11-jdk -y

Verify Java is installed:

java -version

Output Example:

openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2, mixed mode)

1. Packaging Your Ktor Application

Your Ktor app should be ready for deployment. If the shadowJar task is not available or not generating the expected output, ensure your Gradle setup includes the Shadow plugin. Add this snippet to your build.gradle.kts file:

plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
}

After configuring the plugin, use the Gradle shadowJar task to package your app:

./gradlew shadowJar

This will generate a shadow-jar file in your build/libs directory.

Example Output:

build/libs/my-ktor-app-1.0-all.jar

Copy this JAR file to your server using a tool like scp:

scp build/libs/my-ktor-app-1.0-all.jar user@your-server-ip:/home/user/

2. Installing and Setting Up MySQL(or another db you use)

In many applications, a database is crucial for storing and managing data. MySQL is a popular relational database management system, known for its reliability and ease of use.

Install MySQL

sudo apt update
sudo apt install mysql-server -y

Secure Installation

Run the MySQL secure installation script to configure security options:

sudo mysql_secure_installation

Follow the prompts to:

  • Set a root password.
  • Remove anonymous users.
  • Disallow remote root login.
  • Remove test databases.

Access MySQL

Log in to the MySQL shell:

sudo mysql -u root -p

Create a Database and User

  1. Create a new database:
CREATE DATABASE ktor_app_db;

2. Create a new user and grant permissions:

CREATE USER 'ktor_user'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON ktor_app_db.* TO 'ktor_user'@'%';
FLUSH PRIVILEGES;

Creating Tables

To create a table in the database:

  1. Select the database:
USE ktor_app_db;

2. Create a table:

CREATE TABLE user (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Database Backup and Restoration

If you have an existing database and want to replicate it on your Ubuntu server, follow these steps:

Backup Your Database

  1. Export the Database: On the source machine, use the mysqldump command to create a backup of your database:
mysqldump -u [username] -p [database_name] > backup.sql

Replace [username] with your database username and [database_name] with the name of your database. You'll be prompted to enter the database password.

2. Transfer the Backup File: Use SCP to copy the backup.sql file to your Ubuntu server:

scp backup.sql user@your-server-ip:/path/to/destination

Replace user with your SSH username and your-server-ip with the server's IP address.

Restore the Database on the Server

  1. Login to MySQL: On your Ubuntu server, log in to the MySQL shell:
mysql -u [username] -p

2. Create a New Database: Create a new database to restore the backup:

CREATE DATABASE new_database_name;

3. Import the Backup: Exit the MySQL shell and import the backup into the new database:

mysql -u [username] -p new_database_name < /path/to/destination/backup.sql

4. Verify the Restoration: Log back into MySQL and ensure the data has been restored:

USE new_database_name; SHOW TABLES;

With these steps, your database should now be successfully restored and ready for use with your Ktor application.

3. Running the App with NoHup (Optional)

For a quick test, you can start your Ktor app with nohup to keep it running after you log out. Why nohup, you ask? Let’s say you run your app using java -jar, but then close your terminal or log out. The app would stop running because the session ends. By using nohup, you can ensure your app continues running in the background even after you disconnect from the server, making it an essential tool for uninterrupted service in testing or quick setups:

nohup java -jar my-ktor-app-1.0-all.jar &

Check Logs:

Logs will be written to a nohup.out file by default:

tail -f nohup.out

4. Setting Up Systemd for Persistent Availability(Better for Production)

Using nohup is great for testing quick setups, but for production environments, systemd is a more suitable choice. Why? systemd offers several advantages: it automatically restarts your app if it crashes, provides detailed service logs, and seamlessly integrates with other system services. These features ensure your application is highly available and maintainable in a production setting.

Create a Service File

sudo nano /etc/systemd/system/ktor.service

Add the following content:

[Unit]
Description=Ktor Application
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/
ExecStart=/usr/bin/java -jar /home/ubuntu/my-ktor-app-1.0-all.jar
Restart=always
[Install]
WantedBy=multi-user.target

Enable and Start the Service

sudo systemctl daemon-reload
sudo systemctl start ktor
sudo systemctl enable ktor

Check Service Status

sudo systemctl status ktor

Output Example:

ktor.service - Ktor Application
Loaded: loaded (/etc/systemd/system/ktor.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-12-26 10:00:00 UTC; 1min ago
Main PID: 12345 (java)
Tasks: 15 (limit: 4698)
Memory: 256.3M
CGroup: /system.slice/ktor.service
└─12345 /usr/bin/java -jar /home/ubuntu/my-ktor-app-1.0-all.jar

Stopping or Disabling the Service

To stop the service:

sudo systemctl stop ktor

To disable the service from starting automatically:

sudo systemctl disable ktor

5. Filtering Logs with Journalctl

Logs are crucial for troubleshooting and monitoring your application’s behavior. Using the journalctl command, you can easily filter and view logs for a specific service. This ensures you focus only on the information related to your Ktor application, avoiding unnecessary noise from other processes.

View Logs for a Specific Service

sudo journalctl -u ktor.service

View Logs in Real-Time

sudo journalctl -u ktor.service -f

Filter Logs by Time Range

View logs from the last 10 minutes:

sudo journalctl --since "10 minutes ago"

View logs from a specific date:

sudo journalctl --since "2024-12-25 14:00:00" --until "2024-12-25 16:00:00"

Search for Specific Keywords

To search logs for a specific keyword, use:

sudo journalctl -u ktor.service | grep "ERROR"

6. Deployment Script for Automating Ktor App Updates (Optional)

This script automates the deployment of a Ktor application by packaging it using the Gradle shadowJar task, transferring the resulting JAR file to an Ubuntu server, and restarting the application service.

Requirements

  • The application is set up with Gradle and a shadowJar task.
  • The target server is Ubuntu-based.
  • Systemd is used to manage the application service on the server.
  • SSH access is set up with a key for password-less login.

Deployment Script

Save the following script as deploy.sh and customize the placeholders with your project and server details:

#!/bin/bash

# Configurations to update
SERVER_USER="ubuntu" # Username on the server
SERVER_IP="your-server-ip" # Your server's IP address
REMOTE_APP_PATH="/home/ubuntu" # Directory on the server where the JAR file is located
LOCAL_JAR_PATH="build/libs" # Directory on the local system where the JAR file is located
JAR_NAME="my-ktor-app-1.0-all.jar" # Name of the JAR file
SERVICE_NAME="ktor" # systemctl service name

# 1. Build the ShadowJar
echo "Building shadowJar..."
./gradlew shadowJar

if [ $? -ne 0 ]; then
echo "Gradle build failed. Exiting."
exit 1
fi

# 2. Upload the JAR file to the server using SCP
echo "Uploading JAR to the server..."
scp "$LOCAL_JAR_PATH/$JAR_NAME" "$SERVER_USER@$SERVER_IP:$REMOTE_APP_PATH"

if [ $? -ne 0 ]; then
echo "Failed to upload JAR file. Exiting."
exit 1
fi

# 3. Execute operations on the server
echo "Restarting the Ktor application on the server..."

ssh "$SERVER_USER@$SERVER_IP" << EOF
# Stop the service
echo "Stopping the existing Ktor service..."
sudo systemctl stop $SERVICE_NAME

# Replace the JAR file with the new one
echo "Updating the JAR file..."
mv "$REMOTE_APP_PATH/$JAR_NAME" "$REMOTE_APP_PATH/$JAR_NAME.bak"
mv "$REMOTE_APP_PATH/$JAR_NAME" "$REMOTE_APP_PATH/$JAR_NAME"

# Start the service
echo "Starting the Ktor service..."
sudo systemctl start $SERVICE_NAME

# Check the service status
echo "Service status:"
sudo systemctl status $SERVICE_NAME | head -10
EOF

echo "Deployment completed!"

How It Works

  1. Build the JAR: The script uses the shadowJar Gradle task to create a fat JAR containing all dependencies.
  2. Transfer the JAR: It uses scp to securely copy the built JAR file to the server.
  3. Restart the Service: The script stops the running service, updates the JAR, and starts the service again.

Usage Instructions

Ensure your application is managed by a systemd service as above.

  1. Make the script executable:
chmod +x deploy.sh

2. Run the script:

./deploy.sh

Deploying a Ktor application on a VPS gives you full control over your application’s environment and infrastructure. By following the steps outlined in this guide, you can ensure your application runs smoothly and reliably, serving your users with minimal downtime. While it may seem complex at first, mastering these steps will empower you to manage and deploy applications with confidence. Happy coding!

--

--

Firuze Gümüş
Firuze Gümüş

No responses yet