Fixing the “NestJS APP‑ONE Connection Refused on VPS” Error: Why Your Database Migrations Fail on Shared Hosting and How to Resolve It Instantly
If you’ve ever tried to launch a NestJS app on a cheap VPS and hit a “Connection refused” wall, you know the feeling: excitement turns into frustration, deadlines creep, and the whole project feels stuck. This article shows you exactly why those migrations keep failing on shared hosting and gives you a step‑by‑step rescue plan that works the first time.
Why This Matters
Most developers buy a cheap VPS, dump their code, run npm run migration:run, and watch the process die with ECONNREFUSED. The socket never reaches the database because the host’s firewall, bind-address settings, or missing .env variables block traffic. The result? Missed migrations, broken schemas, and a non‑functional production app.
mysql -h localhost -u root -p works but your NestJS app can’t connect, it’s a configuration issue, not a MySQL install problem.
Step‑by‑Step Tutorial: Get Your NestJS App‑ONE Running
Verify MySQL Is Listening on the Correct Interface
Open
/etc/mysql/mysql.conf.d/mysqld.cnf(or/etc/my.cnfon CentOS) and ensure thebind-addressis set to0.0.0.0or the VPS’s private IP, not127.0.0.1.# mysqld.cnf [mysqld] bind-address = 0.0.0.0 port = 3306Restart MySQL:
sudo systemctl restart mysqlOpen the Firewall for Port 3306
Most VPS providers enable
ufworfirewalldby default. Allow inbound MySQL traffic:# Ubuntu/Debian sudo ufw allow 3306/tcp # CentOS/RHEL sudo firewall-cmd --add-port=3306/tcp --permanent sudo firewall-cmd --reloadCreate a Dedicated Database User for the App
Never use
rootin production. From the MySQL shell:CREATE USER 'app_one'@'%' IDENTIFIED BY 'StrongP@ssw0rd!'; GRANT ALL PRIVILEGES ON app_one_db.* TO 'app_one'@'%'; FLUSH PRIVILEGES;Update Your NestJS
.envFileMake sure the host points to the VPS’s public IP (or
127.0.0.1if MySQL runs on the same box) and that the credentials match the user you just created.# .env DB_HOST=YOUR_VPS_IP DB_PORT=3306 DB_USER=app_one DB_PASSWORD=StrongP@ssw0rd! DB_NAME=app_one_dbEnable TCP Keep‑Alive in TypeORM Config
Adding
extra: { connectTimeout: 20000 }prevents quick timeouts that look like “connection refused”.// src/app.module.ts TypeOrmModule.forRoot({ type: 'mysql', host: process.env.DB_HOST, port: +process.env.DB_PORT, username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, entities: [__dirname + '/**/*.entity{.ts,.js}'], migrations: [__dirname + '/migrations/*{.ts,.js}'], synchronize: false, extra: { connectTimeout: 20000 }, });Run the Migrations Locally First
Testing locally guarantees the scripts are valid before you hit the VPS.
npm run migration:runDeploy and Execute on the VPS
SSH into your server, pull the latest code, install deps, then run the migration command.
ssh root@YOUR_VPS_IP cd /var/www/app-one git pull origin main npm ci npm run build npm run migration:run
hosts.allow file isn’t blocking external MySQL connections, and verify that no other service is using port 3306.
Real‑World Use Case: A SaaS Startup Saves $150/Month
A small SaaS built on NestJS and TypeORM was using a $5 shared hosting plan. Their migrations kept failing, forcing them to upgrade to an expensive managed DB. After following the steps above, they kept the same VPS, opened port 3306, and ran migrations without a hitch. The result? $150 saved each month and a faster release cycle.
Results / Outcome
- Zero “Connection refused” errors after the first run.
- All pending migrations applied in < 30 seconds.
- Secure, least‑privilege MySQL user ready for production.
- Repeatable deployment process that any teammate can execute.
Bonus Tips
- Use SSL for MySQL on public IPs. Add
ssl: { rejectUnauthorized: false }to the TypeORMextraobject. - Automate migrations with a CI/CD pipeline. A simple GitHub Actions job can run
npm run migration:runafter a successful build. - Monitor port health. Install
netstat -tulpn | grep 3306in a cron job and alert you if the MySQL process stops. - Keep backups. Schedule
mysqldumpweekly and store snapshots on a different region.
Monetization Corner
If you enjoy quick fixes that save time and money, check out our premium “NestJS Production Checklist” PDF for $9.99. It includes hardened Docker files, CI templates, and a 30‑day support window.
Your NestJS app should now connect to MySQL on a shared VPS without screaming “Connection refused”. Follow the steps, test each layer, and you’ll turn a painful error into a repeatable, revenue‑generating workflow.
No comments:
Post a Comment