Recommended Free Tools
Deploy Flask behind two separate layers: Gunicorn loads your WSGI application on a private loopback address or Unix socket, while Nginx receives public HTTP/HTTPS traffic, terminates TLS, and proxies requests to Gunicorn. This arrangement keeps Flask’s development server off the internet, lets systemd supervise the process, and gives you a controlled place to handle certificates, headers, limits, and access logs.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
What the finished deployment looks like
A browser connects to Nginx on ports 80 or 443. Nginx handles the public connection and forwards the request to Gunicorn, usually at 127.0.0.1:8000 or through a Unix socket such as /run/gunicorn.sock. Gunicorn runs your Flask application with one or more worker processes and returns the response through Nginx.
As an Amazon Associate I earn from qualifying purchases.
Free tools Windows power users keep installed
One-click scans. No signup required.
- Nginx: public reverse proxy, static-file server, TLS termination point, and source of the external access log.
- Gunicorn: production WSGI application server that imports Flask and runs request workers.
- systemd: starts Gunicorn at boot, restarts it after failure, and exposes status and logs through
journalctl. - Flask: the application itself, configured to trust proxy headers only from the proxy path you control.
Gunicorn’s documentation strongly recommends placing it behind a proxy server. Flask’s built-in development server is for development and diagnostics, not for the public edge of a production site.
Before you install anything
Host and account
Use a supported Ubuntu server with administrative access, a DNS name you control, and a dedicated unprivileged account for the application. The examples use flaskapp as the Linux user, /srv/flaskapp as the application directory, and myapp as the Python module. Substitute your real names consistently.
#1 Best Overall
- [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
- [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
- [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
- [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
- [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.
Install Python, the virtual-environment package, and Nginx from Ubuntu’s repositories:
sudo apt update
sudo apt install python3 python3-venv python3-pip nginx
Do not put passwords, signing keys, database URLs, or API tokens in a committed source file. Supply them through a protected environment file or another secret-management system and make sure only the service account can read them.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Application layout
A simple layout is:
/srv/flaskapp/
├── .venv/
├── myapp/
│ ├── __init__.py
│ └── wsgi.py
├── requirements.txt
└── .env
Create the directory and virtual environment, then install the pinned dependencies:
sudo useradd --system --home /srv/flaskapp --shell /usr/sbin/nologin flaskapp
sudo mkdir -p /srv/flaskapp
sudo chown -R flaskapp:flaskapp /srv/flaskapp
sudo -u flaskapp python3 -m venv /srv/flaskapp/.venv
sudo -u flaskapp /srv/flaskapp/.venv/bin/pip install --upgrade pip
sudo -u flaskapp /srv/flaskapp/.venv/bin/pip install -r /srv/flaskapp/requirements.txt
Your import target must expose either an application object or a factory. For example, myapp:wsgi means the module myapp/wsgi.py contains a variable named wsgi; myapp:create_app() tells Gunicorn to call the factory.
Verify Flask with Gunicorn before adding Nginx
Testing Gunicorn directly isolates Python import and application errors from proxy configuration. Run it as the application user and bind it to loopback so it is not reachable from the public network:
sudo -u flaskapp /srv/flaskapp/.venv/bin/gunicorn
--bind 127.0.0.1:8000
myapp:wsgi
In another terminal on the server, request the private endpoint:
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →curl --fail http://127.0.0.1:8000/
Stop the foreground process with Ctrl+C after the check. If Gunicorn reports “failed to find attribute,” correct the module and variable name. If it cannot import a package, install the missing dependency in this virtual environment or fix the working directory and Python package layout. A factory target has the same form:
Rank #2
- 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
- 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
- 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
- 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
- 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.
sudo -u flaskapp /srv/flaskapp/.venv/bin/gunicorn
--bind 127.0.0.1:8000
'myapp:create_app()'
The --workers 4 value often shown in Flask examples is a command example, not a universal sizing rule. Start with a conservative count, observe memory and latency under your own workload, and change it deliberately. Never run this service as root.
Run Gunicorn under systemd
One service using a loopback TCP port
Create /etc/systemd/system/flaskapp.service:
[Unit]
Description=Gunicorn instance for Flask application
After=network.target
[Service]
Type=notify
User=flaskapp
Group=flaskapp
WorkingDirectory=/srv/flaskapp
Environment="PATH=/srv/flaskapp/.venv/bin"
EnvironmentFile=-/srv/flaskapp/.env
ExecStart=/srv/flaskapp/.venv/bin/gunicorn
--workers 3
--bind 127.0.0.1:8000
myapp:wsgi
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
The worker count above is only an example. Choose a value that fits your CPU, memory, request mix, and application behavior rather than copying it as a performance guarantee. If your Gunicorn version or application does not support readiness notification, use the service type recommended by that installation; the important properties are the unprivileged user, explicit working directory, virtual-environment executable, private bind, and restart policy.
Load and start the unit:
sudo systemctl daemon-reload
sudo systemctl enable --now flaskapp.service
sudo systemctl status flaskapp.service
sudo journalctl -u flaskapp.service -e
systemctl status should show an active process. The journal is the first place to look for import exceptions, permission errors, missing environment variables, and worker crashes.
Optional socket activation with a Unix socket
A Unix socket avoids a TCP port and lets systemd create the listening endpoint on demand. It also introduces filesystem ownership and permission decisions. Create /etc/systemd/system/gunicorn.socket:
[Unit]
Description=Gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
SocketUser=flaskapp
SocketGroup=www-data
SocketMode=0660
[Install]
WantedBy=sockets.target
Then create /etc/systemd/system/gunicorn.service:
[Unit]
Description=Gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
Type=notify
User=flaskapp
Group=flaskapp
WorkingDirectory=/srv/flaskapp
Environment="PATH=/srv/flaskapp/.venv/bin"
EnvironmentFile=-/srv/flaskapp/.env
ExecStart=/srv/flaskapp/.venv/bin/gunicorn
--workers 3
--bind unix:/run/gunicorn.sock
myapp:wsgi
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable the socket (and the service if you want it enabled independently):
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn.socket
sudo systemctl status gunicorn.socket
sudo systemctl status gunicorn.service
curl --unix-socket /run/gunicorn.sock http://localhost/
Nginx must be able to open the socket. Adding Nginx to the flaskapp group, setting the socket group to www-data, or using a dedicated group are valid approaches; use one approach consistently and verify it after a reboot. A “permission denied” error in Nginx’s log usually means the socket mode, group membership, or parent-directory permissions are wrong.
Configure Nginx as the reverse proxy
HTTP configuration for a loopback bind
Create a site file such as /etc/nginx/sites-available/flaskapp:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
- [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
- [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
- [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
- [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
- [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
Enable it and remove the default site if it would otherwise answer for the same host:
sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/flaskapp
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
nginx -t must report a successful syntax test before reloading. Keep proxy_pass aligned with the Gunicorn bind. If you selected the Unix socket, use:
proxy_pass http://unix:/run/gunicorn.sock;
Check the site through Nginx, not only through port 8000:
curl --fail -I http://example.com/
curl --fail http://example.com/
If Nginx returns 502 Bad Gateway, check that Gunicorn is running, that the address in proxy_pass matches its bind, and that Nginx has permission to access the Unix socket when applicable.
Why each forwarded header matters
Hostpreserves the domain requested by the browser, which affects host-based routing and URL generation.X-Forwarded-Forcarries the client chain instead of making every request appear to originate at Nginx.X-Forwarded-Prototells Flask whether the original public request was HTTP or HTTPS.X-Real-IPis useful to applications and logs that expect a single address, but it should not replace a carefully configured forwarded-for chain.
These headers are assertions made by a proxy. A client that can connect directly to Gunicorn could forge them, so do not expose the Gunicorn port publicly and do not make Flask trust arbitrary proxy hops.
Make Flask trust only your intended proxy
When Nginx terminates TLS, Flask otherwise sees an HTTP connection from the proxy. URL helpers may therefore generate http:// links, secure-cookie logic may be wrong, and logs may show Nginx’s address. Apply Werkzeug’s ProxyFix middleware with a hop count that matches your topology:
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
# Register this only when requests can arrive through your controlled proxy.
app.wsgi_app = ProxyFix(
app.wsgi_app,
x_for=1,
x_proto=1,
x_host=1,
x_port=1,
x_prefix=1,
)
Use only the fields you actually forward. The value 1 means one trusted proxy hop; increase it only when another controlled proxy is permanently in front of Nginx. If untrusted clients can reach the application directly, remove this trust path or enforce network controls first. Incorrect values let an attacker spoof the client IP, scheme, host, or URL prefix.
Rank #4
- Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
- Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
- All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
- Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
- Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.
Add DNS and HTTPS at Nginx
Create DNS records for the domain that point to the Ubuntu host, then confirm that the name resolves to the intended address before requesting a certificate. Keep the public TLS endpoint at Nginx; Gunicorn can continue using loopback or a Unix socket.
One common Ubuntu workflow is to install a certificate-management client and request a certificate for each name:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
The exact certificate authority, renewal policy, and package availability depend on your Ubuntu release and operating environment. After certificates are installed, an explicit Nginx HTTPS server normally resembles:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Use the certificate paths actually created on your host. Test and reload after every change:
sudo nginx -t
sudo systemctl reload nginx
curl --fail -I https://example.com/
Check certificate renewal with the renewal client’s dry-run facility and monitor its timer or scheduled job. A valid certificate does not by itself make Flask generate secure URLs; the forwarded scheme and the carefully scoped Flask proxy configuration do that.
Secure the network and filesystem
- Allow inbound TCP 80 and 443 at the host firewall and cloud firewall when you need public HTTP/HTTPS. Do not open Gunicorn’s 8000 port to the internet.
- Run Nginx as its packaged unprivileged worker account and Gunicorn as the dedicated application account.
- Keep
.env, private keys, and other secrets unreadable by unrelated users. Do not make the whole application tree writable by Nginx. - Serve static assets directly from Nginx only when their directory and cache policy are intentionally configured; proxy dynamic requests to Flask.
- Set appropriate request-size and timeout limits for your application rather than accepting unlimited uploads by accident.
TCP loopback versus a Unix socket
| Choice | Advantages | Costs and failure modes |
|---|---|---|
| 127.0.0.1:8000 | Simple to understand, easy to test with curl, and independent of Unix group and mode permissions. | The port must remain private; a firewall rule or an accidental bind to 0.0.0.0 can expose it. |
| /run/gunicorn.sock | No listening TCP port for the app and clear filesystem-level access control. | Nginx must have the right group and mode; stale sockets, parent-directory permissions, or service ordering can cause 502 errors. |
Choose TCP when operational simplicity is the priority. Choose a socket when you are comfortable managing ownership and want the application endpoint represented as a filesystem object. Neither option removes the need to keep Gunicorn off the public interface.
Service mode versus socket activation
| Deployment style | Best fit | Operational detail |
|---|---|---|
| Always-on service | Sites that should keep workers ready continuously. | systemctl enable --now flaskapp.service starts Gunicorn at boot and restarts it according to the unit policy. |
| systemd socket activation | Installations that want systemd to own the listening socket and start the service when traffic arrives. | Enable gunicorn.socket, keep the service’s bind and socket unit consistent, and test permissions after reboot. |
Socket activation is not a performance guarantee; it is an operational choice. An always-on service is usually easier to troubleshoot because the process lifecycle is explicit.
Best Value
Validate the complete request path
- Run
sudo systemctl status flaskapp.service(or the socket and service units) and inspectsudo journalctl -u flaskapp.service -e. - Test Gunicorn privately with
curl http://127.0.0.1:8000/, or test the Unix socket withcurl --unix-socket /run/gunicorn.sock http://localhost/. - Run
sudo nginx -tand reload Nginx only after the test succeeds. - Request the real hostname through HTTP and HTTPS. Confirm that the HTTP request redirects as intended and that the HTTPS response is generated by Flask through Nginx.
- Inspect Nginx’s error log and access log alongside the Gunicorn journal when a request fails. The first layer that reports an error identifies where to continue troubleshooting.
Troubleshooting by symptom
Gunicorn exits immediately
Run the exact ExecStart command manually as flaskapp. Import errors usually mean the module path, factory syntax, working directory, or virtual-environment dependencies are wrong. Permission errors usually mean the service user cannot read the application or environment file.
Nginx returns 502
Confirm that Gunicorn is active and listening at the exact address in proxy_pass. For a socket, inspect ls -l /run/gunicorn.sock and verify Nginx’s group access. Review Nginx’s error log for “connection refused,” “no such file,” or “permission denied”; each points to a different bind, lifecycle, or permission problem.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteEvery request appears to come from 127.0.0.1
Ensure Nginx sends X-Forwarded-For and that Flask’s proxy middleware trusts exactly the known proxy hop. Do not solve this by trusting an unlimited number of proxies.
Flask generates HTTP links on an HTTPS page
Forward X-Forwarded-Proto $scheme, enable the corresponding ProxyFix field, and verify that users cannot bypass Nginx to send forged headers directly to Gunicorn.
Changes are not visible
Reload the relevant process after changing code, dependencies, environment values, or configuration. Use sudo systemctl restart flaskapp.service for a full worker restart, and sudo systemctl reload nginx after a valid Nginx configuration change. A reload of Nginx alone does not reload Python code.
When managed hosting is a better fit
Self-managed Ubuntu gives you control over the operating system, process model, networking, proxy rules, and deployment layout, but you own patching, firewall policy, DNS, certificates, monitoring, backups, and incident response. A hosted Python platform can remove much of that server and networking work at the cost of provider-specific configuration, pricing, quotas, and less control.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsFlask’s deployment documentation names PythonAnywhere, Google App Engine, Google Cloud Run, AWS Elastic Beanstalk, and Microsoft Azure as hosted alternatives. Consider one when maintaining an Ubuntu host and public proxy is not a requirement. Stay with the Gunicorn–Nginx pattern when you need predictable OS-level control, custom networking, or a deployment process you can operate independently of a platform.
Operational checklist
- Gunicorn imports the correct Flask object or factory inside the production virtual environment.
- Gunicorn runs as a non-root account and binds only to loopback or a protected Unix socket.
- systemd starts the service at boot, records useful journal output, and restarts failed workers.
- Nginx’s
server_namematches DNS and itsproxy_passmatches Gunicorn’s bind. - Nginx forwards host, client-address, proxy-chain, and scheme headers.
- Flask trusts those headers only for the known proxy hops.
- Port 8000 is not publicly reachable; public access is through Nginx on the intended HTTP/HTTPS ports.
- DNS, certificates, renewal checks, firewall rules, and service status have all been tested through the real hostname.
With these boundaries in place, Nginx remains the public edge, Gunicorn remains the application server, and systemd provides a repeatable process lifecycle without exposing Flask’s development server.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

