Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FetureRequest/Add Talawa-api running on Linux as system daemon processs #2795

Closed
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions example/linux/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Talawa API Installation Guide

This guide provides step-by-step instructions for setting up the Talawa API service on a Linux system using systemd.

## Prerequisites

- **fnm** (Fast Node Manager)
- **Node.js** (version specified in your Talawa API's `package.json`)
- **tsx** (TypeScript execution environment, install globally with `npm install -g tsx`)
- A Linux system with **systemd**
- **Root access** or `sudo` privileges for service installation
- **Dedicated system user** `talawa` for running the service (security best practice)
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
- **MongoDB** installed and running (required for Talawa API)
- **Redis** installed and running (required for Talawa API)
- Proper file permissions on `/path/to/your/talawa-api`
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
- For development:
- Ensure `.env` file sets `NODE_ENV=development`
- Run the service manually to verify functionality
- For production:
- Build the app to generate the `dist` folder
- Ensure `.env` file sets `NODE_ENV=production`
- **Log file setup**:
- Ensure a log file exists at `/var/log/talawa-api.log` with appropriate permissions and ownership
- Verify Node.js version in your system matches the version required by `package.json`
- Install `jq` for parsing JSON data (`sudo apt install jq` or equivalent)

## Steps

### 1. Create a Dedicated System User

- Create a user named `talawa` for running the service:
```bash
sudo adduser --system --no-create-home --group talawa
```
- Verify the user creation:
```bash
id talawa
```
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
### 2. Create the Systemd Service File

- Create the `talawa-api.service` file in the `/etc/systemd/system/` directory with root privileges
- Check following placeholders:
- `ExecStart` (path to your `Talawa-api.sh` script: `/path/to/your/talawa-api/example/linux/systemd/Talawa-api.sh`)
- `WorkingDirectory` (root directory of your Talawa API project: `/path/to/your/talawa-api`)
- `ReadOnlyPaths` (root directory of your Talawa API project: `/path/to/your/talawa-api`)
- `User, Group` (use the `talawa` user and group created earlier)
- Refer to the example in `/path/to/your/talawa-api/example/linux/systemd/talawa-api.service` for guidance
- Copy `talawa-api.service` then paste it inside `/etc/systemd/system/`
- Make sure `talawa-api.service` is owned by root

### 3. Set Up the `Talawa-api.sh` Script

- Edit the script to specify:
- **Project directory** (e.g., `/path/to/your/talawa-api/talawa-api`)
- **Log file path** (e.g., `/var/log/talawa-api.log`)
- Ensure that the development (`src/index.ts`) and production (`dist/index.js`) paths are correctly set
- Make sure `Talawa-api.sh` is executable and owned by user `talawa`. Log file should also be owned by user `talawa`

### 4. Configure the Environment

- Ensure the `.env` file exists in the project directory and contains the appropriate configuration
- Add the following environment variables:
- `NODE_ENV=development` or `NODE_ENV=production`

### 5. Verify Log File and Permissions

- Create the log file if it does not exist:
```bash
sudo touch /var/log/talawa-api.log
sudo chown talawa:talawa /var/log/talawa-api.log
sudo chmod 664 /var/log/talawa-api.log
```
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
- Ensure the log file owner matches the service user (e.g., `talawa`)

### 6. Set Up Log Rotation

- Create a new logrotate configuration file for Talawa API:
```bash
sudo nano /etc/logrotate.d/talawa-api
```

- Add the following configuration:
```plaintext
/var/log/talawa-api.log {
su talawa talawa
weekly
rotate 4
compress
missingok
notifempty
create 664 talawa talawa
postrotate
systemctl restart talawa-api.service > /dev/null 2>&1 || true
endscript
}
```

- Verify logrotate setup:
```bash
sudo logrotate -f /etc/logrotate.d/talawa-api
sudo logrotate -v /etc/logrotate.conf
sudo logrotate -d /etc/logrotate.conf

```
- -f for forced rotation, -v for verbose rotation, -d for debuging mode rotation.
- To confirm log rotation, check the rotated logs:
```bash
ls -la /var/log/talawa-api.log*
```

PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
### 7. Install Dependencies

- Install required Node.js version with `fnm`:
```bash
fnm install <node_version>
fnm use <node_version>
```
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
Replace `<node_version>` with the version specified in `package.json` (`engines.node`)
- Install dependencies:
```bash
npm install
```
- Globally install `tsx` if not already installed:
```bash
npm install -g tsx
```
- Install `jq`:
```bash
sudo apt install jq
```

### 8. Enable and Start the Service

1. Reload the systemd configuration:
```bash
sudo systemctl daemon-reload
```
2. Enable the service:
```bash
sudo systemctl enable talawa-api.service
```
3. Start the service:
```bash
sudo systemctl start talawa-api.service
```

### 9. Verify the Installation

- Check the status of the service:
```bash
sudo systemctl status talawa-api.service
```
- View logs in real-time:
```bash
sudo journalctl -u talawa-api.service -f
```
- Check for errors:
```bash
sudo journalctl -u talawa-api.service -p err
```
- Verify the service configuration:
```bash
sudo systemd-analyze verify talawa-api.service
```
- Verify service dependencies:
```bash
sudo systemctl list-dependencies talawa-api.service
```

## Notes

- Ensure the `Talawa-api.sh` script has executable permissions:
```bash
chmod +x /path/to/Talawa-api.sh
```
- Adjust `LimitNOFILE` and security-related settings in the `talawa-api.service` file as needed for your environment
- For production, ensure the `dist` folder exists by running:
```bash
npm run build
```
- If you encounter any issues, refer to the logs in `/var/log/talawa-api.log` or use `journalctl`
- Don't try to create a global variable to store paths for use in both systemd service and script files. Global variables (like `/path/to/your/talawa-api`) will not work properly as systemd services run in a separate environment. While there are various suggested solutions (using `/etc/environment`, `/etc/default/`, or `Environment` and `EnvironmentFile` directives), these approaches can complicate service execution and are not recommended
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

### Additional Steps for Troubleshooting

1. Verify Node.js and `tsx` installation:
```bash
node -v
tsx -v
```
2. Ensure MongoDB and Redis are running:
```bash
sudo systemctl status mongod
sudo systemctl status redis
```
160 changes: 160 additions & 0 deletions example/linux/systemd/Talawa-api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/bin/bash
# Description: Talawa API startup script
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# Don't use environment variables in this script, as when the script will run by systemd, it will not have access to the environment variables of the user.I have tried setting the environment variables in the systemd service file but it didn't work. So, directly use the absolute paths in the script.)
PROJECT_DIR="/path/to/your/talawa-api"
LOG_FILE="/var/log/talawa-api.log"
DEV_PATH="src/index.ts"
PROD_PATH="dist/index.js"

# Check if the log file exists
if [ ! -f "$LOG_FILE" ]; then
echo "Error: Log file '$LOG_FILE' not found. Exiting."
echo "Please create it first with the correct ownership and permissions, then return."
exit 1
fi

# Get the current user
CURRENT_USER=$(whoami)

# Get the owner of the log file
LOG_FILE_OWNER=$(stat -c '%U' "$LOG_FILE")

# Check if the current user matches the owner of the log file
if [ "$CURRENT_USER" != "$LOG_FILE_OWNER" ]; then
echo "Error: Current user '$CURRENT_USER' does not match the owner of the log file '$LOG_FILE_OWNER'. Exiting."
echo "Change ownership or permissions and try again."
exit 1
fi
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# Check if the user has necessary permissions to read and write to the log file
if [ ! -w "$LOG_FILE" ] || [ ! -r "$LOG_FILE" ]; then
echo "Error: User '$CURRENT_USER' does not have sufficient permissions to read or write to the log file '$LOG_FILE'. Exiting."
echo "Change permissions and try again."
exit 1
fi
echo "-------------------------------***************------------------------------------" | tee -a "$LOG_FILE"
echo "------------------------------>Talawa-API Logs<-----------------------------------" | tee -a "$LOG_FILE"
echo "------------------------------>Current session date: $(date)" | tee -a "$LOG_FILE"
echo "-------------------------------***************------------------------------------" | tee -a "$LOG_FILE"
echo "Log file '$LOG_FILE' is present and writable by user '$CURRENT_USER'. Proceeding..." | tee -a "$LOG_FILE"

# Verify the project directory exists
if [ ! -d "$PROJECT_DIR" ]; then
echo "Error: Project directory '$PROJECT_DIR' not found. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

# Switch to the project directory
cd "$PROJECT_DIR" || { echo "Error: Failed to change to project directory '$PROJECT_DIR'. Exiting." | tee -a "$LOG_FILE"; exit 1; }

echo "Changed to project directory '$PROJECT_DIR'. Proceeding..." | tee -a "$LOG_FILE"

# Check for package.json in the current working directory
if [ ! -f "package.json" ]; then
echo "Error: 'package.json' not found in $(pwd). Exiting." | tee -a "$LOG_FILE"
echo "Please ensure it is present, then return." | tee -a "$LOG_FILE"
exit 1
fi

echo "package.json is present in $(pwd). Proceeding..." | tee -a "$LOG_FILE"

if ! command -v jq >/dev/null 2>&1; then
echo "Error: 'jq' is not installed on this system. Exiting." | tee -a "$LOG_FILE"
echo "It is required to parse the Node.js version from package.json." | tee -a "$LOG_FILE"
echo "Please install 'jq' manually, then rerurn to the script." | tee -a "$LOG_FILE"
exit 1
fi

echo "'jq' is present. Proceeding..." | tee -a "$LOG_FILE"

# Attempt to read the required Node.js version
TARGET_NODE_VERSION=$(jq -r '.engines.node' package.json 2>/dev/null)

# Continue with your script...
if [ -z "$TARGET_NODE_VERSION" ] || [ "$TARGET_NODE_VERSION" == "null" ]; then
echo "Error: Unable to read 'engines.node' from package.json. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

# Remove 'v' prefix if present, e.g. "v20.18.0" -> "20.18.0"
INSTALLED_NODE_VERSION=$(node -v 2>/dev/null | sed 's/^v//')

echo "Installed Node.js version: $INSTALLED_NODE_VERSION" | tee -a "$LOG_FILE"
echo "Target Node.js version: $TARGET_NODE_VERSION" | tee -a "$LOG_FILE"

if [ "$INSTALLED_NODE_VERSION" != "$TARGET_NODE_VERSION" ]; then
echo "Error: Node.js version mismatch. Found $INSTALLED_NODE_VERSION, need $TARGET_NODE_VERSION". Exiting." | tee -a "$LOG_FILE"
echo "First install the required Node.js version from package.json in system then proceed further. It should match system Node.js version and Talawa-api Node.js version "$TARGET_NODE_VERSION" | tee -a "$LOG_FILE"
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
exit 1
fi

echo "Node.js version matched. Proceeding..." | tee -a "$LOG_FILE"

# Check if tsx is installed
if ! command -v tsx >/dev/null 2>&1; then
echo "Error: 'tsx' is not installed on this system. Exiting." | tee -a "$LOG_FILE"
echo "Please install 'tsx' manually, then rerun the script." | tee -a "$LOG_FILE"
exit 1
fi

# Define the path to the tsx executable dynamically
TSX_PATH=$(which tsx)
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# Check if the TSX_PATH is valid
if [ ! -x "$TSX_PATH" ]; then
echo "Error: Path for 'tsx' is not found or not executable. Verify it is properly installed. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

echo "'tsx' is installed and executable at '$TSX_PATH'. Proceeding..." | tee -a "$LOG_FILE"

# Validate paths for development and production
if [ ! -f "$DEV_PATH" ]; then
echo "Error: Development path '$DEV_PATH' not found. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

if [ ! -f "$PROD_PATH" ]; then
echo "Error: Production path '$PROD_PATH' not found. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

echo "Development and production paths are valid. Proceeding..." | tee -a "$LOG_FILE"

# Check if .env file is present
if [ ! -f ".env" ]; then
echo "Error: '.env' file not found. Exiting." | tee -a "$LOG_FILE"
exit 1
fi
echo ".env file found in '$(pwd)' directory. Proceeding..." | tee -a "$LOG_FILE"

# Load environment variables from .env file securely
NODE_ENV=$(grep '^NODE_ENV=' .env | cut -d '=' -f2)
if [ -n "$NODE_ENV" ]; then
export NODE_ENV
else
echo "Error: NODE_ENV not found in .env file" | tee -a "$LOG_FILE"
exit 1
fi

# Check if NODE_ENV is set
if [ -z "$NODE_ENV" ]; then
echo "Error: Property 'NODE_ENV' is not present in the .env file. Exiting." | tee -a "$LOG_FILE"
exit 1
fi

echo "Environment variable 'NODE_ENV' is set to '$NODE_ENV'. Proceeding..." | tee -a "$LOG_FILE"
{
# Check the value of NODE_ENV and execute the corresponding command
if [ "$NODE_ENV" == "development" ]; then
echo "Starting Talawa API in development mode..." | tee -a "$LOG_FILE"
exec "$TSX_PATH" "$DEV_PATH"
elif [ "$NODE_ENV" == "production" ]; then
echo "Starting Talawa API in production mode..." | tee -a "$LOG_FILE"
exec "$TSX_PATH" "$PROD_PATH"
else
echo "NODE_ENV is not set to a valid value. Please set it to 'development' or 'production'. Exiting." | tee -a "$LOG_FILE"
exit 1
fi
} 2>&1 | tee -a "$LOG_FILE"
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading