Self-Hosting Your ATS: The Complete Guide
A self-hosted applicant tracking system runs on infrastructure you control — your own server, a rented VPS, or a managed cloud platform. You own every byte of candidate data, pay no per-seat fees, and choose exactly where your recruitment database lives. This guide covers the full lifecycle: architecture, deployment, security, backups, ongoing operations, real costs, and GDPR compliance.
Most self-hosting guides for ATS software stop at "install it on a server." That is roughly 10% of what you need to know. The other 90% — securing candidate data, automating backups, applying updates without downtime, and keeping infrastructure costs predictable — is what separates a weekend experiment from a production hiring system. This is the guide that covers all of it.
What Self-Hosting Means for Your Applicant Tracking System
Self-hosting an ATS means deploying the application on infrastructure you manage rather than accessing it through a vendor's cloud platform. The software, the database holding your candidate records, and the file storage containing resumes all run on machines you control.
The practical difference is ownership. With a cloud ATS like Greenhouse, Lever, or Workable, your candidate data lives on the vendor's servers. Cancel your subscription and exporting that data is often incomplete — custom fields, pipeline stages, and interview scorecards rarely survive migration intact. With a self-hosted ATS, the database is yours. A standard pg_dump command exports everything. No vendor can hold your talent pool hostage.
Self-hosting does not mean running a server rack in your office closet. Modern self-hosted applications run inside Docker containers on a $5/month cloud server, a managed platform like Railway, or even a laptop for evaluation. The infrastructure overhead has dropped dramatically in the last five years.
If you are unfamiliar with how applicant tracking systems work, start there. This guide assumes you understand what an ATS does and focuses on the self-hosting dimension.
Why Self-Host Your ATS (and When Not To)
Self-hosting is not the right choice for every organization. Here is an honest breakdown.
When self-hosting makes sense
You need data sovereignty. Candidate resumes, contact information, and interview feedback are sensitive personal data. For companies subject to GDPR, CCPA, or industry-specific regulations (healthcare, finance, government), self-hosting can reduce vendor-related compliance overhead significantly. The ATS vendor is no longer hosting your candidate data, which simplifies your processor landscape — though you may still rely on infrastructure processors such as your cloud host, email provider, or CDN.
You refuse to pay a per-seat tax. Cloud ATS platforms charge $15–$165 per recruiter per month. A 10-person hiring team on a mid-tier platform pays $12,000+ per year. Self-hosted ATS software has zero per-seat fees — your entire team accesses the system without increasing costs. For a detailed cost comparison, see our total cost of ownership analysis.
You want full control over your hiring workflow. Self-hosted means you control the source code. Need a custom pipeline stage, a proprietary scoring algorithm, or an integration with an internal HRIS? Fork the repo and build it. No enterprise tier required.
You care about AI transparency. Under the EU AI Act, many AI systems used in recruitment, employment, and worker management are treated as high-risk and require transparency, documentation, and human oversight. Self-hosted open-source ATS platforms make scoring logic inspectable by design — the source code is public. Reqcore's roadmap includes transparent AI candidate ranking with a visible Matching Logic summary, so recruiters will see exactly why a score was assigned and can verify or override the result. Black-box algorithms in commercial platforms cannot offer this level of auditability.
When cloud makes more sense
- Your team has zero technical capacity and no plans to develop it
- You need to be hiring within 24 hours with no setup time
- Your organization is under 5 people and cost savings are negligible
- You require vendor-managed support SLAs for compliance reasons
For a deeper comparison of the two approaches, read our self-hosted vs cloud ATS breakdown.
What You Need: Infrastructure Requirements
A self-hosted ATS is less resource-hungry than most people assume. Here are the actual requirements for running a production instance:
| Requirement | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 2 GB | 4 GB |
| Disk | 10 GB | 20 GB+ (scales with resume uploads) |
| OS | Any Linux, macOS, Windows (WSL2) | Ubuntu 22.04 LTS or Debian 12 |
| Software | Docker Engine + Docker Compose | Same |
| Network | Internet for initial setup | Static IP + domain for production |
These requirements handle a hiring team of 10–50 people processing hundreds of applications per month. The database and file storage are the only components that grow with usage, and PostgreSQL handles tens of thousands of candidate records comfortably within these specs.
Recommended hosting providers
| Provider | Plan | Monthly Cost | Best For |
|---|---|---|---|
| Hetzner | CX22/CX23 (2 vCPU, 4 GB) | ~€4–5/month | Best value. EU data centers (GDPR). Check current pricing. |
| DigitalOcean | Basic Droplet (1 vCPU, 2 GB) | $12/month | Beginner-friendly interface. |
| Vultr | Cloud Compute (1 vCPU, 2 GB) | ~$12/month | Global data centers. Verify current pricing. |
| Railway | Hobby | $5 minimum monthly usage | One-click deploy. Charges can exceed $5 with higher resource use. |
Three Deployment Paths Compared
Not all self-hosting is equal. There are three distinct approaches, each with different trade-offs:
| Factor | VPS (Manual) | Managed Platform (Railway) | Local Machine |
|---|---|---|---|
| Setup time | 1–2 hours | Under 10 minutes | 5 minutes |
| Monthly cost | €4–$15 | $5 minimum usage | $0 (your hardware) |
| Technical skill | Basic Linux + Docker | Click a button | Install Docker |
| Custom domain + HTTPS | You configure it | Automatic | Not applicable |
| Production-ready? | Yes (with hardening) | Yes | No (evaluation only) |
| Uptime | You manage it | Platform manages it | Depends on your laptop |
| Best for | Full control, EU hosting | Fast production deploy | Testing and evaluation |
Reqcore supports all three. The same docker compose up -d command works whether you are on a Hetzner VPS in Helsinki, Railway's managed platform, or your MacBook.
Step-by-Step: Deploying a Self-Hosted ATS with Docker
This walkthrough uses Reqcore as the reference implementation. The pattern applies to any Docker-based ATS.
The architecture
A self-hosted ATS typically runs three components inside Docker containers:
┌─────────────────────────────────────────────────┐
│ Your Server │
│ │
│ ┌────────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ ATS App │ │PostgreSQL│ │ MinIO │ │
│ │ (Nuxt 4) │ │ 16 │ │ (S3 Storage) │ │
│ │ :3000 │ │ :5432 │ │ :9000/:9001 │ │
│ └─────┬──────┘ └────┬─────┘ └──────┬──────┘ │
│ │ │ │ │
│ └──────────────┴───────────────┘ │
│ Docker Network (internal) │
│ │
│ Only port 3000 is exposed externally │
└─────────────────────────────────────────────────┘
Reqcore's Docker Compose runs three services: PostgreSQL 16 for all application data (candidates, jobs, pipeline stages), MinIO for S3-compatible document storage (resumes, cover letters), and the Nuxt 4 application itself. The database and file storage ports are bound to localhost only — they never touch the public internet.
This three-container architecture gives you clear separation of concerns: the application is stateless and can be rebuilt at any time, while your data lives in persistent Docker volumes that survive container restarts and rebuilds. For a broader comparison of self-hosted ATS options that use similar architectures, see our guide to the best open source applicant tracking systems.
The deployment
1. Install Docker on your server. On Ubuntu/Debian:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
2. Clone the repository:
git clone https://github.com/reqcore-inc/reqcore.git
cd reqcore
3. Generate secure credentials. Reqcore includes a setup script that creates cryptographically random passwords for all services:
./setup.sh
This generates a .env file with database passwords, authentication secrets, and storage credentials. Never commit or share this file.
4. Start everything:
docker compose up -d
The first startup takes 2–5 minutes. Docker pulls the PostgreSQL and MinIO images, builds the application using a multi-stage Dockerfile (Alpine-based, non-root user), and runs database migrations automatically.
5. Open your browser at http://your-server-ip:3000, create your account, and set up your organization.
The application itself starts in minutes once Docker and the server are ready. First-time production setup takes longer when you include server provisioning, DNS, TLS, and firewall configuration — budget 1–2 hours for a VPS, or under 10 minutes on a managed platform like Railway.
Adding HTTPS and a custom domain
For production, place a reverse proxy in front of the application. Caddy is the simplest option — it obtains and renews Let's Encrypt certificates automatically:
# Caddyfile
ats.yourcompany.com {
reverse_proxy localhost:3000
}
Point your DNS A record to your server's IP, start Caddy, and HTTPS is handled. Nginx + Certbot is the alternative for teams already using Nginx.
Securing Your Self-Hosted ATS
Candidate data is sensitive personal information. Security is not optional. Here is what a properly secured self-hosted ATS looks like.
What should ship by default
Reqcore ships with these security defaults out of the box, requiring zero configuration:
| Security Control | Implementation |
|---|---|
| Localhost-bound services | PostgreSQL, MinIO, and admin tools are never exposed to the internet |
| CSRF protection | Automatic via Better Auth |
| Encrypted tokens | AES-256-GCM for OAuth tokens |
| Rate limiting | Applied to authentication and sensitive endpoints |
| Security headers | X-Frame-Options: DENY, X-Content-Type-Options: nosniff, strict Referrer-Policy |
| Upload validation | MIME type verification, file size limits, filename sanitization |
| Server-proxied downloads | Uploaded files pass through the application — direct storage access is blocked |
| Deny-by-default access control | Every API endpoint checks org membership and role permissions |
If the ATS software you are evaluating does not provide these defaults, that is a red flag. Security should be built in, not bolted on.
What you should add
Firewall. Restrict inbound traffic to SSH (port 22), HTTP (80), and HTTPS (443):
sudo ufw allow 22/tcp && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
sudo ufw enable
Automatic security updates. On Ubuntu/Debian:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Strong credentials. Use the generated passwords from the setup script. Do not replace them with memorable alternatives.
Keep Docker updated. Docker vulnerabilities affect all containers on the host:
sudo apt update && sudo apt upgrade docker-ce docker-ce-cli containerd.io
Backups, Updates, and Day-2 Operations
Deployment is day 1. Day 2 is where most self-hosting guides stop — and where most self-hosting setups fail. Here is what ongoing operations actually look like.
Backups
Your self-hosted ATS holds candidate data that cannot be recreated. Backups are non-negotiable.
Database backup (covers all candidates, jobs, pipeline data):
docker compose exec db pg_dump -U reqcore reqcore > backup-$(date +%Y%m%d).sql
Automated daily backups via crontab:
# Daily at 2 AM, retain 30 days
0 2 * * * cd /path/to/reqcore && docker compose exec -T db pg_dump -U reqcore reqcore > /backups/reqcore-$(date +\%Y\%m\%d).sql && find /backups -name "reqcore-*.sql" -mtime +30 -delete
Document backup (resumes, cover letters stored in MinIO):
docker cp reqcore_minio:/data ./minio-backup-$(date +%Y%m%d)
Test your restore process before you need it. A backup you have never tested is not a backup.
Updates
Reqcore includes a built-in update system in the web UI — no command line required for routine updates:
- Go to Settings → Updates
- Click "Create backup first" (recommended)
- Click "Update to vX.Y.Z"
- Wait ~2 minutes, refresh the page
For teams that prefer the CLI:
git pull origin main
docker compose up --build -d
Database migrations run automatically. Your data is preserved in Docker volumes across rebuilds.
Monitoring
For production instances, set up basic uptime monitoring using a free service like UptimeRobot (free tier: 50 monitors). Point it at your ATS URL and get alerted when the instance goes down.
Check service health anytime with:
docker compose ps
All three containers (app, db, minio) include built-in health checks that Docker monitors continuously.
How much time does maintenance take?
Based on running Reqcore in production: 1–2 hours per month. That covers pulling updates, verifying backups, and occasional log review. This is not a full-time job. It is a recurring task comparable to updating any other self-hosted application.
The Real Cost of Self-Hosting Your ATS
Self-hosting saves money, but dishonest cost comparisons that ignore maintenance are misleading. Here are real numbers:
| Cost Item | Self-Hosted (VPS) | Self-Hosted (Railway) | Cloud ATS (10 seats) |
|---|---|---|---|
| Software | $0 (open-source) | $0 (open-source) | $12,000–$19,800/yr |
| Infrastructure | €4–$15/mo ($48–$180/yr) | $5+/mo ($60+/yr) | Included |
| Domain + DNS | ~$12/yr | ~$12/yr | Included |
| HTTPS (Let's Encrypt) | $0 | $0 (automatic) | Included |
| Maintenance time | 1–2 hrs/mo | <1 hr/mo | 0 hrs |
| 3-year total | $180–$576 + time | $216 + time | $36,000–$59,400 |
The infrastructure cost of self-hosting Reqcore is $5–$15 per month regardless of team size. A 10-person hiring team on a mid-tier cloud ATS pays $1,000–$1,650 per month — and that bill grows with every recruiter added.
The honest trade-off: self-hosting costs time instead of money. Budget 1–2 hours per month for a VPS deployment, or under 1 hour per month on a managed platform. For most organizations, that trade-off saves $10,000+ per year.
Data Ownership and Compliance
Self-hosting your ATS gives you something that no SaaS agreement can fully guarantee: actual data ownership.
What you own
When you self-host, every piece of recruitment data lives in infrastructure you control:
- Candidate records — Names, emails, phone numbers, application history → PostgreSQL database
- Documents — Resumes, cover letters, portfolios → MinIO (S3-compatible storage)
- Pipeline data — Stages, scores, interview feedback, hiring decisions → PostgreSQL database
- Audit logs — Who accessed what, when → PostgreSQL database
Reqcore stores all candidate data in a standard PostgreSQL database with no proprietary encoding. Running pg_dump exports your complete recruitment database in a format that works with any PostgreSQL-compatible tool. There is no vendor lock-in at the data layer.
GDPR compliance advantages
Self-hosting can simplify GDPR compliance in three concrete ways:
- Data residency. Choose a hosting provider in your jurisdiction. A Hetzner server in Helsinki means candidate data stays in the EU, on infrastructure you control. This can reduce cross-border transfer complexity under Schrems II — though you still need to verify that all supporting services (email, monitoring, CDN) also stay within scope.
- Right to deletion. When a candidate requests data deletion under GDPR Article 17, you have direct control over deletion workflows in your own database. Self-hosting gives you direct control over operational deletion, though GDPR erasure still needs to be managed carefully across live systems, logs, and backups — regulators expect erasure to extend to backups as they are cycled out.
- Fewer processors in your chain. With a cloud ATS, the vendor is a data processor under GDPR, requiring a Data Processing Agreement, security audits, and trust. Self-hosting removes the ATS vendor as host, but it does not necessarily remove all processors from your stack — your infrastructure provider, email service, and other supporting tools may still qualify as processors under EDPB guidance.
Data portability
The difference between self-hosted and cloud ATS becomes starkest when you need to leave. Cloud ATS exports are typically incomplete — custom fields, pipeline configurations, and scoring data rarely survive. Reqcore uses PostgreSQL and S3, which are industry standards. Your data is portable from day one, with no export limitations.
Frequently Asked Questions
How much does it cost to self-host an ATS?
The software is free (open-source). Infrastructure costs range from $5 to $15 per month for a server that handles teams of 10–50 people. Add ~$12 per year for a domain name. Total first-year cost is $72–$192, compared to $12,000+ for a cloud ATS with 10 seats.
Is a self-hosted ATS secure enough for candidate data?
A properly configured self-hosted ATS is more secure than most cloud alternatives for one reason: reduced attack surface. Reqcore binds all internal services (database, file storage) to localhost by default, encrypts tokens with AES-256-GCM, and enforces deny-by-default access control on every endpoint. Your data never travels to a third-party server.
Do I need a dedicated DevOps engineer?
No. Modern self-hosted applications run inside Docker containers. If you can copy five commands into a terminal, you can deploy a self-hosted ATS. Updates and backups are handled through a web UI. Budget 1–2 hours per month for maintenance.
Can I migrate from a cloud ATS to self-hosted?
Yes. Export your candidate data from the cloud ATS (typically as CSV or JSON), then import it into your self-hosted PostgreSQL database using standard database tools. The complexity depends on how proprietary your current vendor's data format is — which is exactly the vendor lock-in problem that self-hosting prevents for the future.
What happens if something breaks?
Your data is stored in Docker volumes that persist across container failures. If the application crashes, docker compose up -d restarts it. If an update fails, roll back with git checkout v1.0.0 && docker compose up --build -d. Pre-update backups (available via the UI) provide an additional safety net.
The Bottom Line
Self-hosting your applicant tracking system is no longer an advanced engineering project. A Docker Compose setup runs a production-grade ATS on a $5/month server with minimal active setup time. The trade-off is honest: you invest 1–2 hours per month in maintenance, and in return you own your candidate data permanently, pay no per-seat fees, and maintain full control over your hiring infrastructure.
The organizations that benefit most are those with data sovereignty requirements, growing teams that refuse to pay an expanding SaaS bill, and anyone who wants to inspect the code behind AI-driven candidate scoring. Check our product roadmap to see what is coming next. For those teams, self-hosting is not the difficult option — it is the rational one.
Reqcore is an open-source (AGPL-3.0) applicant tracking system with no per-seat pricing and full data ownership. Deploy with Docker — try the live demo or read the self-hosting documentation.
About Joachim Kolle
Joachim Kolle
Founder of Reqcore
Joachim Kolle is the founder of Reqcore. He works hands-on with open source software, programming, ATS software, and recruiting workflows.
He writes and reviews content about self-hosted ATS, data ownership, and practical hiring operations.
About the authorLinkedIn profileReady to own your hiring?
Reqcore is the open-source ATS you can self-host. Transparent AI, no per-seat fees, full data ownership.
Keep reading
Best ATS with Transparent AI Scoring
Compare ATS tools with transparent AI scoring, explainable rankings, audit trails, and human oversight before choosing your hiring system.
Best ATS for Recruiting Agencies: Open Source Options
Compare the best open source ATS options for recruiting agencies, including agency workflows, client portals, CRM needs, and data ownership trade-offs.
Best ATS for Small Businesses Under 50 Employees
Compare the best ATS options for small businesses under 50 employees, including open source, low-cost, HR-suite, and scaling choices.