mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
Merge pull request #60 from ArnasDon/fix/hostinger-managed-nodejs
fix(hostinger): recommend Managed Node.js Hosting, not VPS
This commit is contained in:
commit
9fc3eb772b
@ -13,7 +13,7 @@ docs walk you from a freshly forked repo to a production deploy.
|
|||||||
phone number, wire the webhook.
|
phone number, wire the webhook.
|
||||||
4. **[Environment variables](./environment-variables.md)** — the full reference.
|
4. **[Environment variables](./environment-variables.md)** — the full reference.
|
||||||
5. **[Deploy on Hostinger](./deployment-hostinger.md)** — recommended hosting
|
5. **[Deploy on Hostinger](./deployment-hostinger.md)** — recommended hosting
|
||||||
walkthrough (Node.js VPS).
|
walkthrough (Managed Node.js Hosting).
|
||||||
6. **[Automations cron](./automations-and-cron.md)** — schedule the pending
|
6. **[Automations cron](./automations-and-cron.md)** — schedule the pending
|
||||||
executions drain so waits and delays fire.
|
executions drain so waits and delays fire.
|
||||||
7. **[Troubleshooting](./troubleshooting.md)** — the usual suspects.
|
7. **[Troubleshooting](./troubleshooting.md)** — the usual suspects.
|
||||||
@ -26,8 +26,8 @@ docs walk you from a freshly forked repo to a production deploy.
|
|||||||
WhatsApp Business app.
|
WhatsApp Business app.
|
||||||
- A WhatsApp phone number that is **not** already tied to the regular
|
- A WhatsApp phone number that is **not** already tied to the regular
|
||||||
WhatsApp or WhatsApp Business mobile apps.
|
WhatsApp or WhatsApp Business mobile apps.
|
||||||
- A [Hostinger](https://www.hostinger.com/vps-hosting) VPS plan (or any Node
|
- A [Hostinger Managed Node.js Hosting](https://www.hostinger.com/web-apps-hosting)
|
||||||
host that supports long-running Node.js 20+ processes).
|
plan (or any Node host that runs long-running Node.js 20+ processes).
|
||||||
|
|
||||||
## Stack at a glance
|
## Stack at a glance
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ docs walk you from a freshly forked repo to a production deploy.
|
|||||||
- **Database + auth + storage** — Supabase (Postgres + RLS).
|
- **Database + auth + storage** — Supabase (Postgres + RLS).
|
||||||
- **WhatsApp transport** — Meta Cloud API (official WhatsApp Business API).
|
- **WhatsApp transport** — Meta Cloud API (official WhatsApp Business API).
|
||||||
- **Encryption** — AES-256-CBC for per-user access tokens.
|
- **Encryption** — AES-256-CBC for per-user access tokens.
|
||||||
- **Scheduler** — external cron that pings `GET /api/automations/cron`.
|
- **Scheduler** — cron (or any pinger) that hits `GET /api/automations/cron`.
|
||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
|
|
||||||
|
|||||||
@ -34,25 +34,17 @@ Copy the result into `AUTOMATION_CRON_SECRET` in your deployment env.
|
|||||||
|
|
||||||
## 2. Schedule the pinger
|
## 2. Schedule the pinger
|
||||||
|
|
||||||
### Option A — cron on the same VPS (Hostinger)
|
### Option A — hPanel cron (Hostinger Managed Node.js)
|
||||||
|
|
||||||
```bash
|
hPanel → **Advanced → Cron Jobs** → add a new job set to every minute
|
||||||
crontab -e
|
(`* * * * *`). Command:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s -H "x-cron-secret: <AUTOMATION_CRON_SECRET>" https://crm.example.com/api/automations/cron > /dev/null
|
||||||
```
|
```
|
||||||
|
|
||||||
```cron
|
Paste the literal secret — hPanel cron jobs don't inherit the Node app's
|
||||||
* * * * * curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null
|
environment variables.
|
||||||
```
|
|
||||||
|
|
||||||
Export the secret into the cron environment. The simplest way is to add
|
|
||||||
it to the user's shell profile and wrap the command:
|
|
||||||
|
|
||||||
```cron
|
|
||||||
* * * * * bash -lc 'curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null'
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, for a more disciplined setup, use a `systemd` timer with
|
|
||||||
`EnvironmentFile=/etc/wacrm.env`.
|
|
||||||
|
|
||||||
### Option B — external pinger
|
### Option B — external pinger
|
||||||
|
|
||||||
|
|||||||
@ -1,158 +1,153 @@
|
|||||||
# Deploy on Hostinger
|
# Deploy on Hostinger
|
||||||
|
|
||||||
Hostinger's **VPS Hosting** plans are the recommended way to run WaCRM in
|
Hostinger's **[Managed Node.js Hosting](https://www.hostinger.com/web-apps-hosting)**
|
||||||
production: you get a dedicated Node.js process, predictable pricing, and
|
is the recommended way to run WaCRM in production: Hostinger patches the
|
||||||
Hostinger's `hPanel` handles SSL and firewalls for you.
|
OS and the Node runtime, handles SSL, and gives you a Git-based deploy
|
||||||
|
flow from hPanel. You deploy from your fork without ever opening an SSH
|
||||||
|
session if you don't want to.
|
||||||
|
|
||||||
This walkthrough uses a VPS running Ubuntu 24.04.
|
This walkthrough assumes you have already completed
|
||||||
|
[getting-started](./getting-started.md), [supabase-setup](./supabase-setup.md),
|
||||||
|
and [whatsapp-setup](./whatsapp-setup.md) — i.e., your fork builds locally
|
||||||
|
and you have your Supabase + Meta credentials ready.
|
||||||
|
|
||||||
## 1. Provision the VPS
|
## 1. Buy a Managed Node.js plan
|
||||||
|
|
||||||
1. Sign up at <https://www.hostinger.com/vps-hosting> and pick a plan. The
|
1. Sign up at <https://www.hostinger.com/web-apps-hosting> and choose a
|
||||||
**KVM 2** tier (2 vCPU / 8 GB RAM) is a comfortable starting point.
|
Node.js plan that gives you enough memory for `npm run build` (2 GB+
|
||||||
2. During the setup wizard:
|
recommended).
|
||||||
- **OS template** → Ubuntu 24.04 (plain, not the managed Node template —
|
2. During the onboarding wizard, pick the **Node.js** stack and the region
|
||||||
we install what we need manually).
|
closest to your users.
|
||||||
- **Location** → region closest to your users.
|
3. Finish setup until you land in **hPanel**.
|
||||||
- **SSH key** → upload your public key (`~/.ssh/id_ed25519.pub` or
|
|
||||||
similar) so you can SSH in passwordless.
|
|
||||||
3. Wait for provisioning. In hPanel you will see the IPv4 address and
|
|
||||||
root credentials.
|
|
||||||
|
|
||||||
## 2. SSH in and install dependencies
|
## 2. Create the app in hPanel
|
||||||
|
|
||||||
```bash
|
In hPanel, open the hosting plan and go to **Websites → Create / Manage**
|
||||||
ssh root@<your-ip>
|
and pick the **Node.js** application option, then:
|
||||||
|
|
||||||
# Create a non-root user for the app
|
- **Application name** — `wacrm`.
|
||||||
adduser wacrm
|
- **Application root** — accept the default (e.g., `domains/yourdomain/public_html`).
|
||||||
usermod -aG sudo wacrm
|
- **Application URL** — the domain or subdomain you want to use (e.g.,
|
||||||
rsync --archive --chown=wacrm:wacrm ~/.ssh /home/wacrm
|
`crm.example.com`). You can attach a domain now or later under
|
||||||
|
**Domains**.
|
||||||
|
- **Node.js version** — 20 or newer.
|
||||||
|
- **Application startup file / command** — Next.js uses `npm start` once
|
||||||
|
it is built, so set:
|
||||||
|
- Start command: `npm start`
|
||||||
|
- Alternatively: `node node_modules/next/dist/bin/next start -p $PORT`
|
||||||
|
|
||||||
# Switch user
|
Save the app. hPanel provisions a container and shows you the app's
|
||||||
su - wacrm
|
control page.
|
||||||
|
|
||||||
# Install Node.js 20 LTS
|
## 3. Connect your GitHub fork
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
||||||
sudo apt-get install -y nodejs git
|
|
||||||
|
|
||||||
# Install PM2 for process management
|
In hPanel → **Git**:
|
||||||
sudo npm install --global pm2
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. Clone your fork
|
1. **Create repository** → paste your fork's HTTPS URL
|
||||||
|
(e.g., `https://github.com/<your-username>/wacrm.git`).
|
||||||
|
2. Pick the branch you want to deploy (usually `main`).
|
||||||
|
3. Set the deploy path to the **Application root** from step 2.
|
||||||
|
|
||||||
```bash
|
Alternative: if you prefer ZIP uploads, use **File Manager** instead —
|
||||||
cd ~
|
upload the repo contents into the application root. Git-based deploy is
|
||||||
git clone https://github.com/<your-username>/wacrm.git
|
simpler because redeploying is one click.
|
||||||
cd wacrm
|
|
||||||
npm ci
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. Configure env vars
|
## 4. Install dependencies and build
|
||||||
|
|
||||||
Create `/home/wacrm/wacrm/.env.local` with the values from
|
hPanel's Node.js app page exposes a **Run NPM install** button and a
|
||||||
[environment-variables.md](./environment-variables.md). Make sure
|
terminal. Either works:
|
||||||
`NEXT_PUBLIC_SITE_URL` is set to the exact public URL you will use
|
|
||||||
(e.g., `https://crm.example.com`).
|
|
||||||
|
|
||||||
```bash
|
- **Button flow**:
|
||||||
chmod 600 .env.local
|
1. Click **Run NPM install**. Wait for it to finish.
|
||||||
```
|
2. Click **Run NPM Build** (or execute `npm run build` from the app
|
||||||
|
terminal).
|
||||||
|
- **Terminal flow**:
|
||||||
|
```bash
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
## 5. Build and start with PM2
|
> Next.js expects `NEXT_PUBLIC_*` variables to be present **at build
|
||||||
|
> time**, so set env vars (step 5) **before** running the build.
|
||||||
|
|
||||||
```bash
|
## 5. Configure environment variables
|
||||||
npm run build
|
|
||||||
pm2 start npm --name wacrm -- start
|
|
||||||
pm2 save
|
|
||||||
pm2 startup systemd -u wacrm --hp /home/wacrm
|
|
||||||
# Follow the command PM2 prints — it enables auto-start on reboot.
|
|
||||||
```
|
|
||||||
|
|
||||||
WaCRM is now listening on `127.0.0.1:3000`.
|
In hPanel → **Node.js app → Environment variables**, add every value from
|
||||||
|
[environment-variables.md](./environment-variables.md):
|
||||||
|
|
||||||
## 6. Front with nginx + SSL
|
- `NEXT_PUBLIC_SUPABASE_URL`
|
||||||
|
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||||
|
- `SUPABASE_SERVICE_ROLE_KEY`
|
||||||
|
- `ENCRYPTION_KEY`
|
||||||
|
- `META_APP_SECRET`
|
||||||
|
- `NEXT_PUBLIC_SITE_URL` — set to `https://<your-domain>` (with the
|
||||||
|
scheme, without a trailing slash).
|
||||||
|
- `AUTOMATION_CRON_SECRET` — if you plan to use Wait steps
|
||||||
|
([automations-and-cron.md](./automations-and-cron.md)).
|
||||||
|
|
||||||
Point your domain's `A` record at the VPS IP. Then:
|
Save, then **re-run the build** so the new `NEXT_PUBLIC_*` values get
|
||||||
|
baked into the client bundle.
|
||||||
|
|
||||||
```bash
|
## 6. Start the app
|
||||||
sudo apt-get install -y nginx certbot python3-certbot-nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
Create `/etc/nginx/sites-available/wacrm`:
|
From the app page, click **Restart application** (or run the equivalent
|
||||||
|
from the terminal). hPanel boots `npm start` behind its own reverse proxy
|
||||||
|
on the domain you configured. Hit the URL in a browser — you should land
|
||||||
|
on the WaCRM marketing page.
|
||||||
|
|
||||||
```nginx
|
SSL is provisioned automatically. If you used a subdomain, Hostinger's
|
||||||
server {
|
AutoSSL usually takes a minute or two; until then the site may serve the
|
||||||
server_name crm.example.com;
|
plain-HTTP version.
|
||||||
|
|
||||||
client_max_body_size 25m; # WhatsApp media upload ceiling
|
## 7. Update the Meta webhook
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:3000;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
listen 80;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Enable and issue a cert:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ln -s /etc/nginx/sites-available/wacrm /etc/nginx/sites-enabled/wacrm
|
|
||||||
sudo nginx -t && sudo systemctl reload nginx
|
|
||||||
sudo certbot --nginx -d crm.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Certbot writes the 443 block, enables HTTP→HTTPS redirect, and schedules
|
|
||||||
renewals in `systemd`.
|
|
||||||
|
|
||||||
## 7. Firewall
|
|
||||||
|
|
||||||
hPanel → **Firewall**: allow inbound 22 (SSH), 80, 443. Everything else
|
|
||||||
stays closed.
|
|
||||||
|
|
||||||
## 8. Update the Meta webhook
|
|
||||||
|
|
||||||
Back in **Meta for Developers → WhatsApp → Configuration**, change the
|
Back in **Meta for Developers → WhatsApp → Configuration**, change the
|
||||||
callback URL to `https://crm.example.com/api/whatsapp/webhook` and re-verify.
|
callback URL to `https://<your-domain>/api/whatsapp/webhook` and re-verify.
|
||||||
|
|
||||||
## 9. Schedule the automation cron
|
## 8. Schedule the automations cron
|
||||||
|
|
||||||
Follow [automations-and-cron.md](./automations-and-cron.md) to drain
|
If you use the Wait step in any automation, schedule the cron drain.
|
||||||
pending executions. A simple `cron` entry on the same VPS works:
|
|
||||||
|
|
||||||
```bash
|
- **Inside hPanel** — open **Advanced → Cron Jobs** and add:
|
||||||
crontab -e
|
```
|
||||||
```
|
* * * * * curl -s -H "x-cron-secret: <AUTOMATION_CRON_SECRET>" https://<your-domain>/api/automations/cron > /dev/null
|
||||||
|
```
|
||||||
|
Paste the literal secret here (cron jobs in hPanel don't read app env
|
||||||
|
vars) or store it in a file the cron reads.
|
||||||
|
- **Outside** — any uptime monitor (UptimeRobot, Better Stack, GitHub
|
||||||
|
Actions) can hit the URL once a minute. See
|
||||||
|
[automations-and-cron.md](./automations-and-cron.md) for detail.
|
||||||
|
|
||||||
```cron
|
## 9. Deploying updates
|
||||||
* * * * * curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
Load `AUTOMATION_CRON_SECRET` into the cron environment via
|
Two options:
|
||||||
`/etc/environment` or an `EnvironmentFile=` in a `systemd` unit.
|
|
||||||
|
|
||||||
## 10. Deploying updates
|
- **Click-deploy**: push to your fork, then hit **Pull** in hPanel → Git
|
||||||
|
and **Restart application**.
|
||||||
|
- **Terminal**:
|
||||||
|
```bash
|
||||||
|
cd <application-root>
|
||||||
|
git pull
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
# then restart from the Node.js app page
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
If the database schema changed, apply any new SQL files from
|
||||||
ssh wacrm@<your-ip>
|
`supabase/migrations/` in the Supabase SQL editor first — migrations are
|
||||||
cd ~/wacrm
|
idempotent.
|
||||||
git pull
|
|
||||||
npm ci
|
|
||||||
npm run build
|
|
||||||
pm2 reload wacrm
|
|
||||||
```
|
|
||||||
|
|
||||||
`pm2 reload` performs a zero-downtime restart. If the database schema
|
## When to reach for a VPS instead
|
||||||
changed, apply any new SQL files from `supabase/migrations/` in the
|
|
||||||
Supabase SQL editor first — migrations are idempotent.
|
Managed Node.js covers most WaCRM deploys. Consider
|
||||||
|
[Hostinger VPS](https://www.hostinger.com/vps-hosting) if you need:
|
||||||
|
|
||||||
|
- Long-running background workers beyond what the single Next.js process
|
||||||
|
gives you.
|
||||||
|
- System-level cron behaviour you can't replicate from hPanel.
|
||||||
|
- Custom binaries (e.g., ffmpeg) for media transforms.
|
||||||
|
|
||||||
|
Otherwise, Managed Node.js is the fast path.
|
||||||
|
|
||||||
## Where to go next
|
## Where to go next
|
||||||
|
|
||||||
|
|||||||
@ -48,8 +48,9 @@ AUTOMATION_CRON_SECRET=generate-a-long-random-string
|
|||||||
## Security checklist
|
## Security checklist
|
||||||
|
|
||||||
- Never commit `.env.local`. The repo already ignores it.
|
- Never commit `.env.local`. The repo already ignores it.
|
||||||
- On Hostinger / any VPS, set env vars via the platform's **Environment**
|
- On Hostinger Managed Node.js (and any other host), set env vars via the
|
||||||
panel rather than writing them into a tracked file on disk.
|
platform's **Environment variables** panel rather than writing them
|
||||||
|
into a tracked file on disk.
|
||||||
- Rotate `SUPABASE_SERVICE_ROLE_KEY` if it leaks — Supabase lets you
|
- Rotate `SUPABASE_SERVICE_ROLE_KEY` if it leaks — Supabase lets you
|
||||||
regenerate it under Project Settings → API.
|
regenerate it under Project Settings → API.
|
||||||
- Treat `ENCRYPTION_KEY` like a database master key. Losing it means
|
- Treat `ENCRYPTION_KEY` like a database master key. Losing it means
|
||||||
|
|||||||
@ -96,23 +96,32 @@ up. Either consolidate to one deploy or route the webhook to exactly one.
|
|||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
### `502 Bad Gateway` from nginx
|
### `502 Bad Gateway` or "Application not running" from Hostinger
|
||||||
|
|
||||||
- `pm2 status` — is the `wacrm` process up?
|
- Open the Node.js app page in hPanel and confirm the status is **Started**.
|
||||||
- `pm2 logs wacrm` — is the Node process crashing on boot (usually a
|
- Check the app log viewer for a crash on boot — almost always a missing
|
||||||
missing env var)?
|
env var. Re-save your env vars, re-run the build, and restart.
|
||||||
- `sudo nginx -t` — is the nginx config valid?
|
- Confirm the **Application startup command** is `npm start` (or
|
||||||
|
equivalent) and that a build has actually run (`.next/` exists in the
|
||||||
|
application root).
|
||||||
|
|
||||||
### Meta webhook works until the cert renews
|
### Env var changes don't take effect in the browser
|
||||||
|
|
||||||
Certbot renews in-place and reloads nginx. If you see a certificate error
|
`NEXT_PUBLIC_*` values are baked into the client bundle at build time.
|
||||||
right after renewal, restart nginx (`sudo systemctl restart nginx`) and
|
After changing any of them, re-run `npm run build` (hPanel's **Run NPM
|
||||||
check `/var/log/letsencrypt/letsencrypt.log` for the last renew attempt.
|
Build** button works) and restart the app.
|
||||||
|
|
||||||
|
### Meta webhook suddenly stops after a domain change
|
||||||
|
|
||||||
|
Hostinger provisions a new SSL certificate when you attach a new domain
|
||||||
|
or subdomain. Until it is issued, the webhook URL serves plain HTTP and
|
||||||
|
Meta rejects it. Wait for AutoSSL to complete (minutes), then re-verify
|
||||||
|
the webhook in Meta.
|
||||||
|
|
||||||
## Still stuck?
|
## Still stuck?
|
||||||
|
|
||||||
Open an issue with:
|
Open an issue with:
|
||||||
|
|
||||||
- Environment (local / Hostinger / other).
|
- Environment (local / Hostinger Managed Node.js / other).
|
||||||
- The exact error from server logs (`pm2 logs wacrm` or Next's dev output).
|
- The exact error from the app log viewer in hPanel or Next's dev output.
|
||||||
- What you were trying to do when it happened.
|
- What you were trying to do when it happened.
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export function Footer() {
|
|||||||
},
|
},
|
||||||
{ href: '#self-host', label: 'Self-host' },
|
{ href: '#self-host', label: 'Self-host' },
|
||||||
{
|
{
|
||||||
href: 'https://www.hostinger.com/vps-hosting',
|
href: 'https://www.hostinger.com/web-apps-hosting',
|
||||||
label: 'Deploy on Hostinger',
|
label: 'Deploy on Hostinger',
|
||||||
external: true,
|
external: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Section, SectionHeader } from './section'
|
|||||||
import { GithubIcon } from './github-icon'
|
import { GithubIcon } from './github-icon'
|
||||||
|
|
||||||
const REPO_URL = 'https://github.com/ArnasDon/wacrm'
|
const REPO_URL = 'https://github.com/ArnasDon/wacrm'
|
||||||
const HOSTINGER_URL = 'https://www.hostinger.com/vps-hosting'
|
const HOSTINGER_URL = 'https://www.hostinger.com/web-apps-hosting'
|
||||||
|
|
||||||
export function OpenSource() {
|
export function OpenSource() {
|
||||||
return (
|
return (
|
||||||
@ -11,7 +11,7 @@ export function OpenSource() {
|
|||||||
<SectionHeader
|
<SectionHeader
|
||||||
eyebrow="Open source"
|
eyebrow="Open source"
|
||||||
title="Fork it, brand it, host it"
|
title="Fork it, brand it, host it"
|
||||||
description="WaCRM is a template you can take and make your own. Grab the source on GitHub and self-host — we recommend Hostinger for a one-click Node.js VPS."
|
description="WaCRM is a template you can take and make your own. Grab the source on GitHub and self-host — we recommend Hostinger Managed Node.js Hosting for a zero-ops deploy."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="mx-auto grid max-w-5xl grid-cols-1 gap-5 md:grid-cols-2">
|
<div className="mx-auto grid max-w-5xl grid-cols-1 gap-5 md:grid-cols-2">
|
||||||
@ -53,11 +53,12 @@ export function OpenSource() {
|
|||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mt-1.5 text-sm leading-relaxed text-slate-400">
|
<p className="mt-1.5 text-sm leading-relaxed text-slate-400">
|
||||||
Best fit for this template — spin up a Node.js VPS, point it at
|
Best fit for this template — connect your forked repo to
|
||||||
your forked repo, and WaCRM is live in a few minutes.
|
Managed Node.js Hosting and WaCRM is live in a few minutes. No
|
||||||
|
servers to patch.
|
||||||
</p>
|
</p>
|
||||||
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-emerald-400 transition-colors group-hover:text-emerald-300">
|
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-emerald-400 transition-colors group-hover:text-emerald-300">
|
||||||
Get Hostinger VPS
|
Managed Node.js Hosting
|
||||||
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user