Skip to content

Instantly share code, notes, and snippets.

@evgenyneu
Last active April 29, 2025 10:48
Show Gist options
  • Save evgenyneu/5c5c37ca68886bf1bea38026f60603b6 to your computer and use it in GitHub Desktop.
Save evgenyneu/5c5c37ca68886bf1bea38026f60603b6 to your computer and use it in GitHub Desktop.
Install Cursor AI code editor on Ubuntu 24.04 LTS

Install Cursor AI editor on Ubuntu 24.04

  1. Use the Download button on www.cursor.com web site. It will download the NAME.AppImage file.

  2. Copy the .AppImage file to your Applications directory

cd ~/Downloads
mkdir -p ~/Applications
mv NAME.AppImage ~/Applications/cursor.AppImage
  1. Install libfuse2
sudo apt update
sudo apt install libfuse2
  1. Make it an executable
chmod +x ~/Applications/cursor.AppImage
  1. Run
~/Applications/cursor.AppImage --no-sandbox
  1. Add cursor shortcut

Add to .bashrc or .zshrc

alias cursor='~/Applications/your-app.AppImage --no-sandbox'
@quando2299
Copy link

i update the script for zsh executions but onlyc hange the bin/zsh and the extension for .sh and execute, that allows update and handle update with the last version

additional something simple as put and alias for execute when you wnat

# Custom functions and script aliases
alias update-cursor="$HOME/scripts/update-cursor"
#!/bin/zsh
#
# Cursor AI IDE Installer/Updater
# This script installs or updates Cursor AI IDE on Linux systems
#

# -----------------------------------------------------------------------------
# Configuration
# -----------------------------------------------------------------------------
APPIMAGE_PATH="/opt/cursor/cursor.AppImage"
ICON_PATH="/opt/cursor/cursor.png"
DESKTOP_ENTRY_PATH="/usr/share/applications/cursor.desktop"
ICON_URL="https://us1.discourse-cdn.com/flex020/uploads/cursor1/original/2X/a/a4f78589d63edd61a2843306f8e11bad9590f0ca.png"
API_URL="https://www.cursor.com/api/download?platform=linux-x64&releaseTrack=stable"

# Cursor shell function to be added to config files
read -r -d '' CURSOR_FUNCTION << 'EOL'
# Cursor AI IDE launcher function
function cursor() {
    local args=""
    if [ $# -eq 0 ]; then
        args=$(pwd)
    else
        for arg in "$@"; do
            args="$args $arg"
        done
    fi
    local executable=$(find /opt/cursor/cursor.AppImage -type f)
    (nohup $executable --no-sandbox "$args" >/dev/null 2>&1 &)
}
EOL

# -----------------------------------------------------------------------------
# Helper Functions
# -----------------------------------------------------------------------------

# Ensure required dependencies are installed
ensure_dependencies() {
    if ! command -v curl &> /dev/null; then
        echo "curl is not installed. Installing..."
        sudo apt-get update
        sudo apt-get install -y curl
    fi
}

# Check if Cursor is currently running
check_cursor_running() {
    if pgrep -f "cursor.AppImage" > /dev/null; then
        return 0  # Cursor is running
    else
        return 1  # Cursor is not running
    fi
}

# Fetch the latest version information from the Cursor API
fetch_latest_version() {
    local api_response
    api_response=$(curl -s "$API_URL")
    CURSOR_URL=$(echo "$api_response" | grep -o '"downloadUrl":"[^"]*"' | cut -d'"' -f4)
    LATEST_VERSION=$(echo "$api_response" | grep -o '"version":"[^"]*"' | cut -d'"' -f4)

    if [[ -z "$CURSOR_URL" || -z "$LATEST_VERSION" ]]; then
        echo "Error: Failed to fetch version information from API"
        return 1
    fi

    return 0
}

# Get the currently installed version of Cursor
get_current_version() {
    if [[ -f "$APPIMAGE_PATH" ]]; then
        CURRENT_VERSION=$("$APPIMAGE_PATH" --version 2>/dev/null | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" | head -1)
        if [[ -z "$CURRENT_VERSION" ]]; then
            CURRENT_VERSION="unknown"
        fi
    else
        CURRENT_VERSION="not installed"
    fi
}

# Create desktop entry file for application menu integration
create_desktop_entry() {
    echo "Creating desktop entry for Cursor..."
    sudo bash -c "cat > $DESKTOP_ENTRY_PATH" <<EOL
[Desktop Entry]
Name=Cursor AI IDE
Exec=$APPIMAGE_PATH --no-sandbox
Icon=$ICON_PATH
Type=Application
StartupWMClass=Cursor
Categories=Development;
EOL
}

# Download and install the Cursor AppImage
download_and_install() {
    local version="$1"

    # Check if Cursor is running
    if check_cursor_running; then
        echo "Error: Cursor is currently running."
        echo "Please close all instances of Cursor AI IDE and try again."
        return 1
    fi

    # Create installation directory
    sudo mkdir -p "$(dirname "$APPIMAGE_PATH")"

    # Download and set up AppImage
    echo "Downloading Cursor AppImage..."
    sudo curl -L "$CURSOR_URL" -o "$APPIMAGE_PATH"
    sudo chmod +x "$APPIMAGE_PATH"

    # Download and set up icon
    echo "Downloading Cursor icon..."
    sudo curl -L "$ICON_URL" -o "$ICON_PATH"

    # Create desktop entry
    create_desktop_entry

    echo "Cursor AI IDE version $version installation complete."
}

# Determine and get the appropriate shell config file
get_shell_config_file() {
    # Check which shell the user is running
    local shell_path=$(echo "$SHELL")
    local config_file=""

    case "$shell_path" in
        */zsh)
            if [[ -f "$HOME/.zshrc" ]]; then
                config_file="$HOME/.zshrc"
            else
                # Create .zshrc if it doesn't exist
                touch "$HOME/.zshrc"
                config_file="$HOME/.zshrc"
            fi
            ;;
        */bash)
            if [[ -f "$HOME/.bashrc" ]]; then
                config_file="$HOME/.bashrc"
            else
                touch "$HOME/.bashrc"
                config_file="$HOME/.bashrc"
            fi
            ;;
        *)
            # Default to .bashrc for unknown shells
            if [[ -f "$HOME/.bashrc" ]]; then
                config_file="$HOME/.bashrc"
            else
                touch "$HOME/.bashrc"
                config_file="$HOME/.bashrc"
            fi
            ;;
    esac

    echo "$config_file"
}

# Add the cursor function to shell configuration if it doesn't exist
setup_shell_function() {
    local config_file=$(get_shell_config_file)

    echo "Checking for existing cursor function in $config_file..."

    # Check if function already exists in the config file
    if grep -q "function cursor()" "$config_file"; then
        echo "Cursor function already exists in $config_file. No changes needed."
        return 0
    fi

    echo "Adding cursor function to $config_file..."
    echo -e "\n$CURSOR_FUNCTION" >> "$config_file"
    echo "Cursor function added to $config_file."
    echo "Please restart your terminal or run 'source $config_file' to use the cursor command."

    return 0
}

# -----------------------------------------------------------------------------
# Main Functions
# -----------------------------------------------------------------------------

# Fresh installation of Cursor
install_cursor() {
    echo "Installing Cursor AI IDE..."
    ensure_dependencies

    if ! fetch_latest_version; then
        echo "Installation failed. Could not get latest version information."
        return 1
    fi

    echo "Installing Cursor version $LATEST_VERSION"
    download_and_install "$LATEST_VERSION"

    # Setup shell function
    setup_shell_function

    echo "You can find Cursor AI IDE in your application menu or run it by typing 'cursor' in your terminal."
}

# Update an existing Cursor installation
update_cursor() {
    echo "Checking for Cursor updates..."
    ensure_dependencies

    if ! fetch_latest_version; then
        echo "Update check failed. Could not get latest version information."
        return 1
    fi

    get_current_version

    if [[ "$CURRENT_VERSION" == "not installed" ]]; then
        echo "Cursor is not currently installed. Installing now..."
        install_cursor
        return
    fi

    if [[ "$CURRENT_VERSION" == "$LATEST_VERSION" ]]; then
        echo "Cursor is already up to date (version $CURRENT_VERSION)."

        # Make sure shell function is set up even if no update is needed
        setup_shell_function
        return
    fi

    echo "Current version: $CURRENT_VERSION"
    echo "Latest version: $LATEST_VERSION"
    echo "Updating Cursor..."

    # Check if Cursor is running
    if check_cursor_running; then
        echo "Error: Cannot update while Cursor is running."
        echo "Please close all instances of Cursor AI IDE and try again."
        return 1
    fi

    # Download and install the new version
    sudo curl -L "$CURSOR_URL" -o "$APPIMAGE_PATH"
    sudo chmod +x "$APPIMAGE_PATH"

    # Setup shell function
    setup_shell_function

    echo "Cursor has been updated to version $LATEST_VERSION"
}

# Main function to handle installation or update
manage_cursor() {
    if [[ -f "$APPIMAGE_PATH" ]]; then
        echo "Cursor AI IDE is already installed."
        update_cursor
    else
        install_cursor
    fi
}

# -----------------------------------------------------------------------------
# Execute
# -----------------------------------------------------------------------------
manage_cursor

work well, thank you so much !

@LaurentDumont
Copy link

I recommend to rename the original AppImage as well.

  • The original download has the version number in the file name.
  • An appimage, when executed, will try to update itself.
  • If you are not careful, you will have the original version in the name, but the binaries will be new and shiny.

Source : https://docs.appimage.org/packaging-guide/optional/updates.html

ZSync2 based methods will furthermore always keep the old file as a backup. 
If the overwrite flag is true, the current file will be moved to my.AppImage.zs-old. 
If it is false, the old file will remain untouched.
➜  Downloads ls -alh | grep Cursor
-rwxrwxr-x  1 coldadmin coldadmin  178M Mar 31 05:30 Cursor-0.47.9-x86_64.AppImage
-rwxrwxr-x  1 coldadmin coldadmin  166M Mar 30 11:33 Cursor-0.47.9-x86_64.AppImage.zs-old
Version: 0.48.6
VSCode Version: 1.96.2
Commit: 1649e229afdef8fd1d18ea173f063563f1e722e0
Date: 2025-03-31T05:05:28.011Z
Electron: 34.3.4
Chromium: 132.0.6834.210
Node.js: 20.18.3
V8: 13.2.152.41-electron.0
OS: Linux x64 5.15.0-135-generic

@italocjs
Copy link

italocjs commented Apr 8, 2025

Installing fuse2 breaks ubuntu 24.04. upon restart ui stops working.

@melroy89
Copy link

melroy89 commented Apr 9, 2025

Cursor app also doesn't seems to start fully in a separate thread and detached from the terminal when starting from the terminal. More over, I also notice sometimes issues with like using grep in the built-in terminal within Cursor.

So I dunno what the hack those Cursor people thinking, but they should just build a deb file and distribute those for the people who just want to have a deb. I know its possible since Windsurf does it correctly.

I would like to have Cursor features with the build & releasing of Windsurf using deb files.

@evagabond
Copy link

Is it working for Ubuntu 22.04?

Yes!

@blakete
Copy link

blakete commented Apr 16, 2025

Thanks! This worked smoothly for me on Ubuntu 22.04.5

@NoviaDroid
Copy link

NoviaDroid commented Apr 20, 2025

the online cursor icon to download should be replaced as : https://www.cursor.com/apple-touch-icon.png

@Hassan-Mehmood
Copy link

The link in the script is not working for some reason. Anyone else facing the same issue?
NOT WORKING: https://downloader.cursor.sh/linux/appImage/x64

@melroy89
Copy link

Cursor now really really need to just publish a Debian repo sooner than later.

@Sayeh-1337
Copy link

Sayeh-1337 commented Apr 22, 2025

Simply do that

./Cursor-xxxxxx.AppImage --appimage-extract cursor

# Navigate to the source directory
cd cursor/usr

# Copy the contents to the system /usr directory
sudo cp -r bin/* /usr/bin/
sudo cp -r lib/* /usr/lib/
sudo cp -r share/* /usr/share/

# Set the correct ownership and permissions for the Chrome sandbox
sudo chown root:root /usr/share/cursor/chrome-sandbox
sudo chmod 4755 /usr/share/cursor/chrome-sandbox

@melroy89
Copy link

melroy89 commented Apr 22, 2025

Just saying.. In my case --appimage-extract doesn't accept the parameter for a directory (cursor in this case). Without cursor extracting works as expected into squashfs-root dir. Thanks!

Improved script from above snippet (for Linux): https://gitlab.melroy.org/-/snippets/621

That being said, it's still NOT ideal.. since normally the executable (eg. vscode or windsurf) goes to background when executing it. My code snippet fixing this again, by using a custom launcher script just like vscode. Basically doing:

ELECTRON="/usr/local/share/cursor/cursor"
CLI="/usr/local/share/cursor/resources/app/out/cli.js"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"

Cursor fix your deb files!

So now the only down-side is that an icon is missing Cursor fixed that issue apparently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment