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

Feature Request : Add Talawa-API to run as systemd in Linux (All suggestion are taken from codeRabbit AI after resolving those new clean PR ) #2809

Open
wants to merge 33 commits into
base: develop-postgres
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6ba0a1f
added installation script and modify talawa-api.sh
PurnenduMIshra129th Dec 26, 2024
ead2e33
added installation.md and Created a script file
PurnenduMIshra129th Dec 26, 2024
320aeb3
Merge branch 'develop-postgres' into linux_systemd
PurnenduMIshra129th Dec 26, 2024
e607bf5
resolved conversession
PurnenduMIshra129th Dec 27, 2024
80e448d
resolved conversation
PurnenduMIshra129th Dec 27, 2024
7411bda
solved unresolved comments
PurnenduMIshra129th Dec 27, 2024
51b6ca7
solved all unresolved conversation of CodeRabbit
PurnenduMIshra129th Dec 28, 2024
b3b4dce
again some suggestion resolved
PurnenduMIshra129th Dec 28, 2024
6bdd005
some more unresolved conversation
PurnenduMIshra129th Dec 29, 2024
b9da888
some suggestion
PurnenduMIshra129th Dec 29, 2024
fb166f6
some changes
PurnenduMIshra129th Dec 29, 2024
42af787
some unresolved conversation
PurnenduMIshra129th Dec 29, 2024
f20cdc9
some suggestion
PurnenduMIshra129th Dec 29, 2024
b86aff7
conversation resolved
PurnenduMIshra129th Dec 29, 2024
a11fb1a
added logrotate
PurnenduMIshra129th Dec 30, 2024
117cc5e
some suggestion
PurnenduMIshra129th Dec 30, 2024
828aefd
add some security directives in log
PurnenduMIshra129th Dec 30, 2024
3144255
Merge branch 'develop-postgres' into linux_systemd
PurnenduMIshra129th Dec 30, 2024
a627fa3
added node in prod script
PurnenduMIshra129th Dec 30, 2024
b30e79d
changed path
PurnenduMIshra129th Dec 30, 2024
c5ad21f
new changes
PurnenduMIshra129th Jan 2, 2025
4aca388
added readme in talwa-api.service
PurnenduMIshra129th Jan 2, 2025
dbb1b19
taken suggesion
PurnenduMIshra129th Jan 3, 2025
1e8d6b5
taken suggestion from ai and changed in installation.md
PurnenduMIshra129th Jan 11, 2025
d4b7b98
Merge branch 'main-develop-postgres' into linux_systemd
PurnenduMIshra129th Jan 11, 2025
a7c27ea
get the dev-postgres branch to the minimal base state (#2597)
xoldd Nov 10, 2024
51a9532
Added GitHub Actions python script linter (#2850)
palisadoes Jan 12, 2025
a2a7e1b
Update .gitignore
palisadoes Jan 13, 2025
41b89af
Update push-deploy-website.yml
palisadoes Jan 14, 2025
1f305a6
Update .gitignore
palisadoes Jan 14, 2025
1f17d1e
fix postgres test env file, remove sign up confirm password input (#2…
xoldd Jan 14, 2025
b667654
fix apply drizzle migrations env (#2859)
xoldd Jan 14, 2025
a2de7db
Merge branch 'develop-postgres' of https://github.com/PalisadoesFound…
PurnenduMIshra129th Jan 14, 2025
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
225 changes: 225 additions & 0 deletions example/linux/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# 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`)
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
- **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)
- **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
```
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
- Verify the user creation:

```bash
id talawa
```

### 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:
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

```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
```
- 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
# Prevent symlink attacks
nolinkasym
# Delete old versions of log files
delaycompress
# Don't rotate empty log files
notifempty
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*
```

### 7. Install Dependencies

- Install required Node.js version with `fnm`:

```bash
fnm install <node_version>
fnm use <node_version>
```
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:

PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
```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.
- While systemd supports environment variables through EnvironmentFile and Environment directives, using absolute paths in both the service file and script ensures consistent behavior across different environments and makes debugging easier.

### Additional Steps for Troubleshooting

1. Verify Node.js and `tsx` installation:

```bash
node -v
tsx -v
```
2. Ensure MongoDB and Redis are running:
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

```bash
sudo systemctl status mongod
sudo systemctl status redis
```
161 changes: 161 additions & 0 deletions example/linux/systemd/Talawa-api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/bin/bash
# filepath: /path/to/your/talawa-api/example/linux/systemd/Talawa-api.sh
# Description: Talawa API startup script

# 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"
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# 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
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# 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

# 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
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

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 return 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 v$TARGET_NODE_VERSION" | tee -a "$LOG_FILE"
exit 1
fi
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

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)

# 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"

PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved
# 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
PurnenduMIshra129th marked this conversation as resolved.
Show resolved Hide resolved

# 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
Loading
Loading