sodcalculator

10 Tech How-To

Deploy Python Bottle Apps on a VPS

Guide 10-40895 · Updated · Step by step

Deploying a Bottle app on a virtual private server (VPS) makes it available over the internet without running the development server on your own computer. You’ll install Python and the app’s dependencies, run Bottle behind a production WSGI server, and put Nginx in front to handle web traffic. You’ll need a Linux VPS, SSH access, and a domain name if you want to use one.

What You’ll Need

  • A VPS running a supported Linux distribution, such as Ubuntu or Debian, with an account that can use sudo.
  • SSH access to the server and your app’s source code, either in a Git repository or copied from your computer.
  • A domain name, optional for testing but needed for a convenient public hostname and HTTPS certificate.
  • Basic familiarity with the terminal and your app’s startup requirements, including any environment variables.

Step-by-Step

  1. Connect and update the server. From your computer, connect with ssh username@SERVER_IP, substituting your account and server address. Update packages with sudo apt update and sudo apt upgrade. Commands below use the Debian/Ubuntu package manager; other distributions use different package commands. Create a non-root user with sudo privileges if you only have a root login, and use that account for routine work.
  2. Install Python tools and Nginx. Run sudo apt install python3 python3-venv python3-pip nginx git. Confirm Python is available with python3 --version. If your app uses a database, install or configure its client libraries and service separately according to the app’s requirements.
  3. Put the application on the server. Choose a directory for the app, for example /var/www/bottle-app. You can clone a repository into a user-owned directory, or copy files using a secure transfer method. Avoid placing secrets such as API keys in a public repository. Check that the app’s entry-point file and dependency file, commonly requirements.txt, are present.
  4. Create an isolated environment and install dependencies. From the app directory, run python3 -m venv .venv, then . .venv/bin/activate. Install the declared packages with python -m pip install --upgrade pip and pip install -r requirements.txt. Add Bottle and a production WSGI server such as Waitress to the requirements if the project does not already list them. Do not rely on packages installed globally for another application.
  5. Make the app expose a WSGI application. Bottle apps can be run through a WSGI server without using Bottle’s built-in development server. For example, if app.py defines app = Bottle(), Waitress can load it as app:app. Test the import from the project directory using .venv/bin/python -c "from app import app; print(app)". Adjust the module and variable names to match your project. Fix import errors before configuring the service.
  6. Test locally on the VPS. Start Waitress temporarily with .venv/bin/waitress-serve --host=127.0.0.1 --port=8000 app:app. In a second SSH session, run curl -i http://127.0.0.1:8000/. Confirm that the expected route responds. Stop the temporary process with Ctrl+C. Binding to the loopback address keeps this test server inaccessible directly from the public network.
  7. Run the app with systemd. Create a service file using sudo nano /etc/systemd/system/bottle-app.service. A basic configuration is:
    [Unit]
    Description=Bottle web application
    After=network.target

    [Service]
    User=YOUR_USER
    WorkingDirectory=/var/www/bottle-app
    EnvironmentFile=-/etc/bottle-app.env
    ExecStart=/var/www/bottle-app/.venv/bin/waitress-serve --host=127.0.0.1 --port=8000 app:app
    Restart=on-failure

    [Install]
    WantedBy=multi-user.target

    Replace YOUR_USER, the directory, and the WSGI target as needed. Create the optional environment file with restricted permissions if the app needs secrets; do not put secret values in a world-readable file. Then run sudo systemctl daemon-reload, sudo systemctl enable --now bottle-app, and sudo systemctl status bottle-app.

  8. Configure Nginx as a reverse proxy. Create an Nginx site configuration that listens on port 80 and forwards requests to Waitress. Inside the server block, include server_name example.com www.example.com; and a location block with proxy_pass http://127.0.0.1:8000;, proxy_set_header Host $host;, proxy_set_header X-Real-IP $remote_addr;, and proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;. Replace the example hostname. Enable the site using the distribution’s Nginx configuration layout, check it with sudo nginx -t, then apply it with sudo systemctl reload nginx. Keep the app port private; do not open port 8000 to the internet.
  9. Point your domain and enable HTTPS. Set the domain’s DNS records to the VPS address and wait for them to resolve. Allow inbound web traffic in the VPS firewall and any provider firewall. Once the hostname reaches Nginx, install Certbot using the current instructions for your distribution and Nginx, then request a certificate for the hostname. Verify HTTPS and certificate renewal rather than assuming DNS or certificate setup succeeded.
  10. Check the deployment and plan updates. Visit the site over HTTPS and test important routes, forms, and static files. Review sudo journalctl -u bottle-app -n 100 --no-pager and the Nginx error log if something fails. For each update, deploy the changed code, install any dependency changes in the virtual environment, and restart with sudo systemctl restart bottle-app. Keep a known-good revision so you can roll back.

Common Mistakes

  • Using Bottle’s development server in production: it is intended for development, not as the public-facing deployment service. Use a production WSGI server behind Nginx.
  • Binding the app to a public interface: keep the WSGI server on 127.0.0.1 when Nginx is on the same VPS. Exposing its port can bypass the proxy and its settings.
  • Using the wrong working directory or WSGI target: systemd must run where imports work, and module:variable must identify the actual Bottle application.
  • Putting secrets in code or weakly protected files: restrict access to environment files and never commit credentials to source control.
  • Forgetting to reload after configuration changes: test Nginx configuration before reloading, and reload systemd after editing a service file.

Tips

  • Keep the app, virtual environment, and service account permissions consistent; the service user must be able to read code and write only to directories the app actually needs.
  • Use environment variables for deployment-specific settings, and make the app log useful errors to standard output or standard error so systemd can capture them.
  • For larger deployments, add monitoring, backups for persistent data, and a repeatable deployment process. A VPS restart should not erase important user uploads or database contents.
  • Set Bottle’s proxy handling appropriately when the app needs accurate scheme or client-address information behind Nginx; trust forwarded headers only from your proxy.

Troubleshooting

If the site returns a gateway error, check sudo systemctl status bottle-app and the service journal first. A crashed process, wrong WSGI target, missing package, or port mismatch commonly prevents Nginx from reaching the app. Run the local curl test again and ensure Nginx’s upstream address and port match the Waitress command.

If the app works locally but not through the domain, check that DNS points to the correct server, Nginx recognizes the hostname, and ports 80 and 443 are allowed by both the operating-system and provider firewalls. Use sudo nginx -t to identify syntax errors. If HTTPS issuance fails, confirm DNS has propagated and that the hostname can reach the server over HTTP before retrying.

For import or permission errors, inspect the service’s WorkingDirectory, virtual-environment paths, and file ownership. Test the import using the same Python environment used by systemd. For a blank or incorrect page, inspect the application logs and test the exact route directly with curl.

Frequently Asked Questions

Can I deploy Bottle without Nginx?
Yes, a WSGI server can serve the app, but Nginx is commonly used as a reverse proxy for public HTTP traffic, TLS termination, and static files.

Do I need a domain name?
No. You can test using the VPS IP address, but a domain is more convenient and is normally needed for a standard HTTPS certificate setup.

Why use Waitress instead of Bottle’s built-in server?
Bottle’s built-in server is intended for development. Waitress is a separate WSGI server suitable for running the application as a managed service.

How do I make code changes live?
Deploy the updated files, install changed dependencies in the virtual environment, then restart the systemd service. Confirm the service is active and test the affected routes.

Where can I find error messages?
Use sudo journalctl -u bottle-app for application service output and check Nginx’s error log for proxy or configuration problems.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →