Skip to main content
    Back to all articles

    Self-Hosting Your Applications: A Complete Guide

    16 min read
    By BAHAJ ABDERRAZAK
    Featured image for "Self-Hosting Your Applications: A Complete Guide"

    Self-hosting your applications offers unparalleled control, flexibility, and often, cost-effectiveness compared to managed services. This comprehensive guide will walk you through the essential steps to set up and manage your own web applications on a Virtual Private Server (VPS), leveraging Docker Compose for easy deployment and Nginx as a powerful reverse proxy.

    \n

    ---

    \n

    Why Self-Host?

    \n
      \n
    • Full Control: You dictate the environment, software versions, and security configurations.
    • \n
    • Cost Savings: Often cheaper than comparable managed services, especially for multiple applications.
    • \n
    • Learning Experience: Deepen your understanding of server management, networking, and DevOps.
    • \n
    • Data Privacy: Keep your data on servers you control.
    • \n
    \n

    ---

    \n

    Step 1: Choosing a VPS Provider

    \n

    Select a reliable VPS provider that fits your budget and performance needs. Popular options include:

    \n
      \n
    • DigitalOcean
    • \n
    • Linode
    • \n
    • Vultr
    • \n
    • Hetzner Cloud
    • \n
    • OVHcloud
    • \n
    \n

    Start with a basic plan (e.g., 1 CPU, 1-2 GB RAM) and scale up as needed. Choose an Ubuntu Server LTS (Long Term Support) version for stability.

    \n

    ---

    \n

    Step 2: Initial Server Setup and Security

    \n

    After provisioning your VPS, immediately secure it.

    \n

    1. SSH Access and Root Login

    \n
      \n
    • Disable Root Login: Create a new user with sudo privileges and disable direct root SSH access.
    • \n
              sudo adduser yourusername\n        sudo usermod -aG sudo yourusername\n        sudo nano /etc/ssh/sshd_config\n        # Change PermitRootLogin to no\n        # Change PasswordAuthentication to no (if using SSH keys)\n        sudo systemctl restart sshd
      \n
    • SSH Key Authentication: Always use SSH keys for login; it''s more secure than passwords.
    • \n
              # On your local machine:\n        ssh-keygen -t rsa -b 4096\n        ssh-copy-id yourusername@your_vps_ip
      \n
    \n

    2. Firewall (UFW)

    \n

    Configure UFW (Uncomplicated Firewall) to allow only necessary traffic.

    \n
          sudo ufw allow OpenSSH\n      sudo ufw allow 'Nginx Full' # We'll install Nginx later\n      sudo ufw enable\n      sudo ufw status verbose
    \n

    3. Update System

    \n

    Keep your system up-to-date.

    \n
          sudo apt update && sudo apt upgrade -y
    \n

    ---

    \n

    Step 3: Installing Docker and Docker Compose

    \n

    Docker will containerize your applications, and Docker Compose will manage multi-container applications.

    \n
          # Install Docker\n      sudo apt install docker.io -y\n      sudo systemctl start docker\n      sudo systemctl enable docker\n      sudo usermod -aG docker yourusername # Add your user to the docker group\n      newgrp docker # Apply group changes\n\n      # Install Docker Compose\n      sudo apt install docker-compose -y\n      # Verify installation\n      docker --version\n      docker-compose --version
    \n

    ---

    \n

    Step 4: Deploying Your Application with Docker Compose

    \n

    Create a directory for your application (e.g., /var/www/my-app) and place your docker-compose.yml file there.

    \n

    Example docker-compose.yml for a simple web app (e.g., a Node.js API with a database)

    \n
          version: '3.8'\n\n      services:\n        web:\n          build: . # Build Dockerfile in current directory, or use image: your-image/name\n          container_name: myapp_web\n          restart: always\n          environment:\n            NODE_ENV: production\n            DATABASE_URL: postgres://user:password@db:5432/mydb\n          ports:\n            - "3000:3000" # Expose internal app port, Nginx will proxy to this\n          networks:\n            - myapp_network\n\n        db:\n          image: postgres:13\n          container_name: myapp_db\n          restart: always\n          environment:\n            POSTGRES_USER: user\n            POSTGRES_PASSWORD: password\n            POSTGRES_DB: mydb\n          volumes:\n            - db_data:/var/lib/postgresql/data\n          networks:\n            - myapp_network\n\n      volumes:\n        db_data:\n\n      networks:\n        myapp_network:\n          driver: bridge
    \n

    Navigate to your application directory and start the services:

    \n
          cd /var/www/my-app\n      docker-compose up -d
    \n

    Your application should now be running internally on the specified port (e.g., port 3000 for the web service).

    \n

    ---

    \n

    Step 5: Setting up Nginx as a Reverse Proxy

    \n

    Nginx will handle incoming HTTP/HTTPS requests and forward them to your Docker containers.

    \n

    1. Install Nginx

    \n
          sudo apt install nginx -y\n      sudo systemctl start nginx\n      sudo systemctl enable nginx
    \n

    2. Configure Nginx for Your Application

    \n

    Create a new Nginx server block configuration file:

    \n
          sudo nano /etc/nginx/sites-available/my-app.conf
    \n

    Add the following content (replace your-domain.com and 3000 with your details):

    \n
          server {\n          listen 80;\n          listen [::]:80;\n          server_name your-domain.com www.your-domain.com;\n\n          location / {\n              proxy_pass http://localhost:3000; # Or http://172.17.0.1:3000 for Docker's default bridge\n              proxy_set_header Host $host;\n              proxy_set_header X-Real-IP $remote_addr;\n              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n              proxy_set_header X-Forwarded-Proto $scheme;\n          }\n      }
    \n

    Enable the Nginx site and test the configuration:

    \n
          sudo ln -s /etc/nginx/sites-available/my-app.conf /etc/nginx/sites-enabled/\n      sudo nginx -t\n      sudo systemctl restart nginx
    \n

    Ensure your domain''s DNS A record points to your VPS IP address. You should now be able to access your application via HTTP.

    \n

    ---

    \n

    Step 6: Securing with SSL (HTTPS) using Certbot

    \n

    HTTPS is essential for security. Certbot automates obtaining and renewing free SSL certificates from Let''s Encrypt.

    \n
          sudo snap install core; sudo snap refresh core\n      sudo snap install --classic certbot\n      sudo ln -s /snap/bin/certbot /usr/bin/certbot\n\n      sudo certbot --nginx -d your-domain.com -d www.your-domain.com
    \n

    Certbot will automatically modify your Nginx configuration, set up redirects from HTTP to HTTPS, and configure automatic renewals.

    \n

    ---

    \n

    Step 7: Monitoring and Logging

    \n
      \n
    • Basic Monitoring: Use htop for process monitoring, df -h for disk space, free -h for memory.
    • \n
    • Docker Logs: docker-compose logs -f for real-time application logs.
    • \n
    • Nginx Access/Error Logs: /var/log/nginx/access.log and /var/log/nginx/error.log.
    • \n
    • Tools: For more advanced monitoring, consider self-hosting tools like Grafana with Prometheus, or using simple uptime monitoring services.
    • \n
    \n

    ---

    \n

    Step 8: Backups

    \n

    Regular backups are critical.

    \n
      \n
    • Database Backups: Use pg_dump (PostgreSQL) or mysqldump (MySQL) to create scheduled database dumps.
    • \n
              # Example for PostgreSQL\n        sudo docker exec myapp_db pg_dump -U user mydb > /path/to/backups/mydb_$(date +%F).sql
      \n
    • Application Code Backups: Use rsync or simply ensure your code is always in a Git repository.
    • \n
    • VPS Snapshots: Many VPS providers offer snapshot features for full server backups.
    • \n
    • Offsite Storage: Store backups on a different server or cloud storage (e.g., S3, Backblaze B2).
    • \n
    \n

    ---

    \n

    Step 9: Maintenance and Updates

    \n
      \n
    • Regular Updates: Periodically run sudo apt update && sudo apt upgrade -y to keep your OS updated.
    • \n
    • Docker Image Updates: Keep your base Docker images updated.
    • \n
    • Application Updates: Pull the latest code and restart your Docker containers.
    • \n
              cd /var/www/my-app\n        git pull origin main # Or your deployment method\n        docker-compose down && docker-compose up -d
      \n
    \n

    ---

    \n

    Conclusion

    \n

    Self-hosting your applications on a VPS using Docker and Nginx provides a powerful, flexible, and cost-effective hosting solution. While it requires more hands-on management, the learning and control gained are invaluable. By following these steps, you''ll be well-equipped to deploy, secure, and maintain your web applications efficiently.