[Blog](https://console.f1b10.testing.getox.in/blog) [Guides](https://console.f1b10.testing.getox.in/blog#c-guides) # Deploy Django and Vue.js on a VPS: Nginx, Gunicorn, Celery Deploy a Django and Vue.js app on a VPS: Nginx serves the Vue build, Gunicorn runs Django, Celery and Redis under systemd, with HTTPS from Certbot. Saurav Sharma Jun 4, 2025 14 min read On this page - [Overview](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-overview) - [Prerequisites](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-prerequisites) - [1. VPS Setup](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-1-vps-setup) - [2. System Dependencies](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-2-system-dependencies) - [3. Database: PostgreSQL](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-3-database-postgresql) - [4. Redis for Celery](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-4-redis-for-celery) - [5. Codebase Deployment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-5-codebase-deployment) - [6. Python Virtual Environment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-6-python-virtual-environment) - [7. Frontend Build (Vue.js)](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-7-frontend-build-vuejs) - [8. Django Migrations & Static Files](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-8-django-migrations-amp-static-files) - [9. Application Server: Gunicorn](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-9-application-server-gunicorn) - [10. Background Workers: Celery & Beat](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-10-background-workers-celery-amp-beat) - [11. Reverse Proxy: Nginx](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-11-reverse-proxy-nginx) - [12. SSL/TLS with Let's Encrypt](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-12-ssltls-with-lets-encrypt) - [13. Monitoring & Logging](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-13-monitoring-amp-logging) - [14. Automated Backups](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-14-automated-backups) - [15. Routine Maintenance](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-15-routine-maintenance) - [16. Nginx permissions](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-16-nginx-permissions) - [Few helpful commands to restart services after deployment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-few-helpful-commands-to-restart-services-after-deployment) - [Key takeaways](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#key-takeaways) - [Frequently asked questions](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq) To deploy a Django and Vue.js app on a VPS, build the Vue app into static files and let Nginx serve them, with a `try_files` fallback to `index.html` for Vue Router. Nginx proxies `/api/`, `/auth/` and `/admin/` to Gunicorn running Django under systemd, Celery and Celery Beat run as two more systemd services with Redis as the broker, PostgreSQL holds the data, and Certbot adds HTTPS. This is the exact setup I use for my Focus Timer app, one domain for both halves, so the browser never needs CORS. **In this guide:** - [Securing the VPS](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-1-vps-setup) - [PostgreSQL and Redis](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-3-database-postgresql) - [Building the Vue.js frontend](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-7-frontend-build-vuejs) - [Gunicorn, Celery and Beat under systemd](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-9-application-server-gunicorn) - [Nginx for the Vue build and the Django API](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-11-reverse-proxy-nginx) - [Frequently asked questions](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq) ## Overview This guide provides a secure, production-ready deployment process for the Focus Timer application on a Linux VPS. It follows best practices at each step and includes brief explanations to help beginners understand. Here is what runs on the server when you are done: | Piece | Runs as | Job | | --- | --- | --- | | Nginx | `nginx` service | Serves the Vue `dist/` and Django's static files, proxies API calls, terminates HTTPS | | Django (Gunicorn) | `gunicorn` service | Answers `/api/`, `/auth/` and `/admin/` on 127.0.0.1:8000 | | Celery worker | `celery` service | Runs background tasks | | Celery Beat | `celery-beat` service | Schedules periodic tasks | | Redis | `redis-server` service | Broker and result backend for Celery | | PostgreSQL | `postgresql` service | The database | ## Prerequisites - A fresh Ubuntu VPS on a supported LTS release (22.04 or 24.04), or Debian 12. - Root or sudo access. - A domain name pointing to your VPS. - Basic familiarity with Linux shell. ## 1. VPS Setup ### 1.1 Create Unprivileged User *Why?* Running services as non-root improves security. Shell ```lang-bash # Add a user, no password login, add to sudo group adduser --disabled-password --gecos "" focususer usermod -aG sudo focususer # Set up SSH access for the new user # Copy root's authorized keys to the new user mkdir -p /home/focususer/.ssh cp /root/.ssh/authorized_keys /home/focususer/.ssh/authorized_keys # Set ownership and permissions chown -R focususer:focususer /home/focususer/.ssh chmod 700 /home/focususer/.ssh chmod 600 /home/focususer/.ssh/authorized_keys ``` **Explanation:** - `adduser`: Creates a new Linux user with default settings. - `--disabled-password`: Prevents setting a login password (forces SSH key auth only). - `--gecos ""`: Supplies empty fields for the user's full name and contact info. - `usermod -aG sudo`: Appends (`-a`) the user to the `sudo` group, allowing administrative commands. ### 1.2 Secure SSH Access *Why?* Prevent unauthorized root or password-based logins. Shell ```lang-bash # On your local machine, generate SSH key if needed: ssh-keygen -t ed25519 -C "your_email@example.com" # Copy public key to server: ssh-copy-id focususer@your.domain.com ``` ### On server, edit /etc/ssh/sshd_config: Shell ```lang-bash Port 22 PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no UsePAM yes ``` Then check the settings that are really in effect and reload SSH. Many cloud images put an override in `/etc/ssh/sshd_config.d/` (often `50-cloud-init.conf`) that turns password login back on, and those files win over the main config: Shell ```lang-bash sudo sshd -T | grep -Ei 'passwordauthentication|permitrootlogin' sudo systemctl reload ssh ``` Keep your current session open and test a new login from another terminal before you log out, so a typo can't lock you out. **Explanation:** - `ssh-keygen -t ed25519`: Generates a modern, high-security Ed25519 key pair. - `-C "comment"`: Adds an identifying comment (often your email). - `ssh-copy-id`: Installs your public key on the remote server's `~/.ssh/authorized_keys` file, allowing key-based logins. - `PermitRootLogin no`: Disables SSH login as `root`, forcing administrative access via a less-privileged user plus `sudo`. - `PasswordAuthentication no`: Turns off password-based logins entirely; only key-based auth is allowed. - `KbdInteractiveAuthentication no` (older guides call it `ChallengeResponseAuthentication`, now a deprecated alias): Disables keyboard-interactive (challenge-response) methods, such as one-time passwords or other PAM-driven prompts, preventing any fallback from key-based authentication. - Without this setting, SSH could invoke PAM's challenge modules (e.g. OTP or custom scripts) that might allow weaker or interactive authentication paths. - `UsePAM yes`: Enables Pluggable Authentication Modules (PAM) integration. - Even with password logins disabled, PAM handles account and session management after a successful key login. - PAM modules enforce additional security policies (e.g. account expiration, lockouts, resource limits, logging). - Ensures that system-wide policies (like `pam_faillock` lockouts, which replaced the removed `pam_tally2`) can apply to every SSH session. Fail2Ban is not a PAM module; it reads the logs, as in step 1.3. - `systemctl reload ssh`: Applies the above SSH daemon changes without dropping existing connections. #### 1.2.1. Logging in as focususer *Why?* Operating as a non-root user mitigates the risk of accidental system-wide changes. Shell ```lang-bash # Exit the current root SSH session: exit # From your local machine, SSH back in as the unprivileged user: ssh focususer@your.domain.com ``` **Explanation:** - `exit`: Ends the current SSH session as root and returns you to your local shell. - `ssh focususer@your.domain.com`: Initiates a new SSH session using your key for the `focususer` account. ### 1.3 Firewall & Fail2ban *Why?* Limit open ports and block brute-force attempts. Shell ```lang-bash # Install UFW & Fail2ban sudo apt update && sudo apt install -y ufw fail2ban # Basic UFW rules sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable # Configure Fail2ban (e.g., /etc/fail2ban/jail.local) sudo tee /etc/fail2ban/jail.local < ~/backups/db-$(date +\%F).sql.gz ``` - Secure backup storage (offsite or S3). ## 15. Routine Maintenance - Keep OS & packages updated: Shell ```lang-bash sudo apt update && sudo apt upgrade -y ``` - Review logs, monitor disk and memory. ## 16. Nginx permissions *Why?* Nginx needs access to static files and directories. Shell ```lang-bash # Ensure Nginx can read static files sudo chmod o+x /home/focususer sudo chmod -R o+rX /home/focususer/focus-timer-django-vue/frontend-vue/dist sudo chmod -R o+rX /home/focususer/focus-timer-django-vue/backend/static sudo chmod -R o+rX /home/focususer/focus-timer-django-vue/backend/media sudo chmod -R o+x /home/focususer/focus-timer-django-vue/frontend-vue chmod +x /home/focususer/focus-timer-django-vue/.venv/bin/gunicorn chmod +x /home/focususer/focus-timer-django-vue/.venv/bin/celery chmod u+x deploy.sh ``` ## Few helpful commands to restart services after deployment ### 1. Reload all systemd unit files (after any edits) Shell ```lang-bash sudo systemctl daemon-reload ``` ### 2. Restart your Django app (Gunicorn) Shell ```lang-bash sudo systemctl restart gunicorn sudo systemctl status gunicorn # check exit status immediately journalctl -u gunicorn -f # live logs ``` ### 3. Restart Celery worker & beat Shell ```lang-bash sudo systemctl restart celery celery-beat sudo systemctl status celery # check worker status sudo systemctl status celery-beat journalctl -u celery -f # live worker logs journalctl -u celery-beat -f # live beat logs ``` ### 4. Restart Nginx (reverse proxy & static files) Shell ```lang-bash sudo systemctl restart nginx sudo systemctl status nginx sudo journalctl -u nginx -f ``` ### 5. (Optional) Restart backing services Shell ```lang-bash sudo systemctl restart redis-server postgresql sudo systemctl status redis-server postgresql sudo journalctl -u redis-server -f sudo journalctl -u postgresql -f ``` ### 6. (Optional) I made a script to restart all services at once. Feel free to tweak it as it fits your needs. Shell ```lang-bash #!/usr/bin/env bash # Script to restart all Focus Timer services set -euo pipefail # Parse options SKIP_FRONTEND=false for arg in "$@"; do case $arg in --skip-frontend) SKIP_FRONTEND=true ;; esac done echo "Installing backend requirements..." .venv/bin/uv pip install -r backend/requirements.txt echo "Applying database migrations..." .venv/bin/python backend/manage.py migrate --noinput echo "Collecting static files..." .venv/bin/python backend/manage.py collectstatic --noinput if [ "$SKIP_FRONTEND" = false ]; then echo "Building frontend..." ( cd frontend-vue && npm ci && npm run build ) else echo "Skipping frontend build due to --skip-frontend option" fi echo "Reloading systemd daemon..." sudo systemctl daemon-reload services=( gunicorn celery celery-beat nginx redis-server postgresql ) for service in "${services[@]}"; do echo "Restarting $service..." sudo systemctl restart "$service" done echo "Waiting for services to settle..." sleep 2 echo "Services status:" for service in "${services[@]}"; do echo "===== $service =====" sudo systemctl status "$service" --no-pager done echo "All services restarted." ``` **Save this script as** `deploy.sh` and make it executable: Shell ```lang-bash chmod +x deploy.sh ``` After each push, pull the code and run it from the project root: `git pull && ./deploy.sh`. Restarting Gunicorn this way drops requests for a second or two, which is fine for a side project. ## Key takeaways - Build Vue into `dist/` and let Nginx serve it; Django only answers the API, auth and admin paths. - `try_files $uri $uri/ /index.html` keeps Vue Router's history mode working on refresh. - Serving both halves on one domain means no CORS setup at all. - Gunicorn, the Celery worker and Celery Beat each get a systemd unit, with secrets in one `.env` file. - Lock SSH down to keys, check `sshd -T` for cloud overrides, and add HSTS only after HTTPS works. ## Frequently asked questions ### Should Nginx or Django serve the Vue.js build? Nginx. The Vue build is plain HTML, JavaScript and CSS, and Nginx serves static files faster and with less memory than a Python process. Point the server block's `root` at `dist/`, add the `try_files` fallback to `index.html`, and keep Gunicorn for the paths Django really answers. ### Do I need CORS for Django and Vue on one domain? No. When Nginx serves the Vue app and proxies `/api/` to Django on the same domain, the browser sees one origin, so there is no cross-origin request. You only need `django-cors-headers` when the frontend lives on a different domain or port, as during local development with the Vite dev server. ### Why does refreshing a Vue Router page give a 404? In history mode the path, like `/settings`, exists only inside the Vue app, so the server finds no such file. Add `try_files $uri $uri/ /index.html;` to the Nginx `location /` block. Any path that isn't a real file then returns `index.html`, and Vue Router shows the right page. ### How do I deploy updates after pushing to Git? SSH in, run `git pull` in the project root, then run the `deploy.sh` script above. It installs requirements, applies migrations, collects static files, rebuilds the Vue app and restarts the services. Pass `--skip-frontend` when only the backend changed, to skip the slow `npm` build. ### Can ox deploy a Django and Vue.js app like this? Yes. ox reads a Django app's requirements and runs it with Gunicorn under systemd, with PostgreSQL and Redis when it sees them. A `[static]` block serves the built Vue app next to it and sends API paths like `/api` to Django. You still write no Nginx or unit files yourself. Next step: if you'd rather not maintain all of this by hand, ox runs the same shape of app on your own server. Read the [Django guide](https://console.f1b10.testing.getox.in/docs/guides/django) for the backend, the [static site guide](https://console.f1b10.testing.getox.in/docs/guides/static-site) for serving the Vue build, the [`[static]` settings](https://console.f1b10.testing.getox.in/docs/config#static) for sending `/api` to Django, and [setting environment variables](https://console.f1b10.testing.getox.in/docs/operate/variables) for what goes in your `.env` today. *Updated Oct 8, 2026: fixed the PostgreSQL, virtualenv, Node and Celery steps, updated the SSH settings for current Ubuntu, moved HSTS after HTTPS, and added a FAQ.* First published on [blog.sorv.dev](https://blog.sorv.dev/deployment-guide-for-django-vuejs-project-on-vps). New to running apps on your own server? [How ox self-hosts your apps](https://console.f1b10.testing.getox.in/self-hosting) shows what ox sets up on your server. On this page - [Overview](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-overview) - [Prerequisites](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-prerequisites) - [1. VPS Setup](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-1-vps-setup) - [1.1 Create Unprivileged User](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-11-create-unprivileged-user) - [1.2 Secure SSH Access](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-12-secure-ssh-access) - [On server, edit /etc/ssh/sshd_config:](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-on-server-edit-etcsshsshdconfig) - [1.3 Firewall & Fail2ban](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-13-firewall-amp-fail2ban) - [1.4 Automatic Security Updates](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-14-automatic-security-updates) - [2. System Dependencies](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-2-system-dependencies) - [3. Database: PostgreSQL](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-3-database-postgresql) - [4. Redis for Celery](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-4-redis-for-celery) - [5. Codebase Deployment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-5-codebase-deployment) - [5.1 Clone Repository](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-51-clone-repository) - [5.2 Environment Variables](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-52-environment-variables) - [6. Python Virtual Environment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-6-python-virtual-environment) - [7. Frontend Build (Vue.js)](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-7-frontend-build-vuejs) - [8. Django Migrations & Static Files](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-8-django-migrations-amp-static-files) - [9. Application Server: Gunicorn](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-9-application-server-gunicorn) - [10. Background Workers: Celery & Beat](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-10-background-workers-celery-amp-beat) - [11. Reverse Proxy: Nginx](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-11-reverse-proxy-nginx) - [12. SSL/TLS with Let's Encrypt](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-12-ssltls-with-lets-encrypt) - [13. Monitoring & Logging](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-13-monitoring-amp-logging) - [14. Automated Backups](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-14-automated-backups) - [15. Routine Maintenance](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-15-routine-maintenance) - [16. Nginx permissions](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-16-nginx-permissions) - [Few helpful commands to restart services after deployment](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-few-helpful-commands-to-restart-services-after-deployment) - [1. Reload all systemd unit files (after any edits)](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-1-reload-all-systemd-unit-files-after-any-edits) - [2. Restart your Django app (Gunicorn)](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-2-restart-your-django-app-gunicorn) - [3. Restart Celery worker & beat](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-3-restart-celery-worker-amp-beat) - [4. Restart Nginx (reverse proxy & static files)](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-4-restart-nginx-reverse-proxy-amp-static-files) - [5. (Optional) Restart backing services](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-5-optional-restart-backing-services) - [6. (Optional) I made a script to restart all services at once. Feel free to tweak it as it fits your needs.](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#heading-6-optional-i-made-a-script-to-restart-all-services-at-once-feel-free-to-tweak-it-as-it-fits-your-needs) - [Key takeaways](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#key-takeaways) - [Frequently asked questions](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq) - [Should Nginx or Django serve the Vue.js build?](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq-serve-vue) - [Do I need CORS for Django and Vue on one domain?](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq-cors) - [Why does refreshing a Vue Router page give a 404?](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq-refresh-404) - [How do I deploy updates after pushing to Git?](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq-update) - [Can ox deploy a Django and Vue.js app like this?](https://console.f1b10.testing.getox.in/blog/deployment-guide-for-django-vuejs-project-on-vps#faq-ox) Written by Saurav Sharma Builds ox. Writes about running apps on servers you own, without Docker and without a platform bill. [Older post Fail2Ban for Django: Stop Brute-Force Logins on Your VPS](https://console.f1b10.testing.getox.in/blog/fail2ban-magic-keeping-your-django-castle-safe) [Newer post Case Study: Raising a Vue App's Lighthouse Score to 93](https://console.f1b10.testing.getox.in/blog/case-study-how-i-improved-frontend-page-speed) ## Keep reading - Guides [How to Self-Host Web Apps on Your Own VPS (2026 Guide)](https://console.f1b10.testing.getox.in/blog/self-host-web-apps-on-your-own-vps) What you need to self-host a web app on a VPS: server, domain, HTTPS, database, backups. Four ways to set it up, their trade-offs, and how ox does it. Saurav Sharma Oct 15, 2026 8 min read - Guides [A FastAPI App on Your Own Server with One Config File](https://console.f1b10.testing.getox.in/blog/deploy-fastapi-to-your-own-vps) Put a FastAPI app with uvicorn, Postgres and Alembic on your own Ubuntu server, with HTTPS and no Docker, using one small ox.toml file you can copy. Saurav Sharma Oct 8, 2026 7 min read - Guides [Deploy Django Without Docker: Gunicorn, systemd and Caddy](https://console.f1b10.testing.getox.in/blog/deploy-django-to-a-vps-without-docker) Deploy Django without Docker on your Ubuntu VPS: gunicorn under systemd, Caddy for HTTPS and PostgreSQL. Every step by hand, then the same deploy with ox. Saurav Sharma Oct 8, 2026 9 min read ## Deploy to a server you own ox sets up systemd, Caddy and PostgreSQL on your Ubuntu server and deploys on every push. Free for your first project. [Sign up with GitHub](https://console.f1b10.testing.getox.in/login/github) [Read the docs](https://console.f1b10.testing.getox.in/docs)