If you just want to serve one image, don't stand up a bare Apache box on port 80 and call it done. Even for a single file, plain HTTP means anyone on the network path can read the request, tamper with the response, and see exactly what you're loading. The fix is either free HTTPS in front of your file, or skipping the server entirely and dropping the image on object storage or a static host.
This comes up on r/webhosting more than you'd think: "Is it safe to expose an Apache HTTP server just to host literally one image?" The honest answer is that exposing a raw web server is the wrong shape of solution for the job. You'd be maintaining a whole daemon, an open port, and a patch schedule to deliver something a static host hands out for free.
Below is what actually matters, and the cheaper, safer routes most people should take instead.
Why plain HTTP is risky even for one file
Plain HTTP is risky because there's no encryption and no integrity check, so anything between your visitor and your server can read or rewrite the traffic. That "anything" includes coffee-shop Wi-Fi, a shady ISP, a compromised router, or a middlebox injecting ads.
For a single image the confidentiality loss might feel trivial, but the tampering risk isn't. An attacker who can modify the response can swap your image for something else, or worse, inject a redirect or malicious payload if the URL is ever loaded in a context that trusts it. Browsers now flag HTTP pages as "Not Secure," and if you try to embed an HTTP image on an HTTPS page, it gets blocked as mixed content. So a bare HTTP image often won't even display where you want it.
There's also the maintenance tax nobody mentions. A public Apache instance is a service you now own: security updates, log rotation, a firewall, watching for scanners hammering the port. That's a lot of surface area to babysit for one PNG.
The fastest safe route: skip the server
The simplest secure way to serve one image is to not run a server at all — put the file on a static host or object storage that gives you HTTPS out of the box.
These options serve your file over TLS, handle caching, and survive traffic spikes without you touching a config file:
- Object storage with a public URL — services like Backblaze B2, Cloudflare R2, or an S3-compatible bucket. Upload the file, mark it public, share the HTTPS link.
- A static site host — Cloudflare Pages, Netlify, or GitHub Pages. Commit the image, get a TLS-secured URL in minutes.
- A folder on hosting you already pay for — if you run any site with TPC Hosting, drop the image in your web root. HTTPS is already there, and there's nothing new to expose.
Object storage is worth a closer look because the URL patterns are predictable. On Backblaze B2 a public file lands at https://f003.backblazeb2.com/file/your-bucket/logo.png (the f003 maps to whichever cluster your bucket lives on). On Cloudflare R2, you don't get a raw endpoint by default — you attach a custom domain and end up with https://cdn.example.com/logo.png, which is cleaner and lets Cloudflare's cache sit in front for free.
Two settings matter when you upload. Set the Content-Type explicitly (image/png, image/webp) so the browser renders instead of downloads, and set a long cache header — Cache-Control: public, max-age=604800, immutable — since the file rarely changes. With the AWS CLI against an S3-compatible bucket that's one command: aws s3 cp logo.png s3://your-bucket/ --content-type image/png --cache-control "public, max-age=604800, immutable" --endpoint-url https://....
One thing to watch: a public bucket is public. Anyone can hotlink it, and on metered plans (B2 bills egress past the free daily allowance) a popular image can cost you real money. If that worries you, front the bucket with Cloudflare and add a hotlink-protection rule that checks the Referer header, or set a monthly cap so a surprise spike can't run up a bill overnight.
The shared-hosting point is the one people overlook. If you already have a site, you don't need a second machine for one asset. Your existing site already terminates TLS, already gets patched, and already has support behind it. Reusing it is free and safer than spinning up a raw box.
If you must run your own server, add free HTTPS
If you genuinely need your own server, put a real TLS certificate on it with Let's Encrypt and never serve the raw file over port 80 unencrypted. The tooling is free and the setup is a few commands.
On a fresh Debian or Ubuntu box with Nginx, this gets you a valid certificate and auto-renewal:
- Point a domain (or subdomain) at your server's IP with an A record.
- Install Nginx and Certbot: sudo apt install nginx certbot python3-certbot-nginx
- Serve the file from a minimal config, then run: sudo certbot --nginx -d img.example.com
- Certbot edits your config, installs the cert, and sets up renewal. Confirm with: sudo certbot renew --dry-run
The trick most guides skip is scoping the server tightly. You don't want a directory host — you want a location that answers exactly one path, allows only GET, and returns 405 for anything else. A minimal block does that in a few lines:
- location = /logo.png {
- limit_except GET { deny all; }
- add_header Cache-Control "public, max-age=604800";
- root /var/www/img;
- }
The = /logo.png is an exact match, so no other path resolves. limit_except GET refuses POST, PUT, and the rest. Add server_tokens off; in your http block so responses stop advertising your Nginx version, and set return 301 https://$host$request_uri; on the port-80 server so nobody lands on the plaintext version.
Hardening a single-file server: the short checklist
If you're exposing any server to the internet, harden it before you share the link, not after the first scan hits your logs. A single-image server is small, which makes the checklist short and there's no excuse to skip it.
- HTTPS only — redirect all HTTP to HTTPS, and add an HSTS header once you're confident: Strict-Transport-Security: max-age=31536000.
- Close every port you don't need — with UFW: sudo ufw allow 443, sudo ufw allow 80, sudo ufw allow 22, then sudo ufw enable. Nothing else.
- Lock down SSH — key-only login, disable password auth, and consider a non-standard port to cut scanner noise.
- Auto-update — enable unattended security upgrades so you're not the reason a known CVE stays open.
- Strip the version header — server_tokens off; in Nginx, or ServerTokens Prod and ServerSignature Off in Apache, so you're not advertising exactly what to attack.
Notice how much of this exists purely because you chose to run a server. That's the trade-off: full control, but you're now the sysadmin. For one image, most people don't want that job.
Which option should you actually pick?
Pick based on how much control you need versus how much maintenance you're willing to own — for a single static image, less is almost always more.
| Option | HTTPS | Maintenance | Best for |
|---|---|---|---|
| Object storage / static host | Free, built in | None | One-off assets, hotlinked images |
| Existing shared hosting folder | Already there | None extra | Anyone who already hosts a site |
| Your own VPS with Certbot | Free, you set it up | Ongoing (you're the admin) | Custom logic, private access rules |
| Bare Apache on HTTP | None | All the downsides, no upside | Nobody |
If the image needs to sit behind auth, get resized on the fly, or live next to an API, a server makes sense — do it properly with TLS. If it's just a file people load, use a static host or a folder on hosting you already have.
This is one place where our setup helps without any fuss: sites on TPC Hosting are EU-hosted and GDPR-friendly, and if you'd rather not fight with certificates and firewalls, real engineers are on support around the clock.
The takeaway
Serving one image is a solved problem, and the solution is rarely "expose a raw server." Reach for a static host or object storage first; keep it on hosting you already run if you have it; and only stand up your own box when the job truly needs one — and when it does, HTTPS and a firewall are the baseline, not extras.
The instinct to ask "is this safe?" is the right one. The better question is "do I even need to run a server for this?" Usually, you don't.
FAQ
Is it safe to host a single image on a plain HTTP server?
No — plain HTTP has no encryption or integrity check, so the traffic can be read or tampered with along the way. Even for one file, browsers flag it as "Not Secure" and block it as mixed content on HTTPS pages, so you should always serve over HTTPS.
Do I need to run a server at all to host one image?
No, and for a single static image you usually shouldn't. Object storage like Cloudflare R2 or Backblaze B2, a static host like Netlify or GitHub Pages, or a folder on hosting you already pay for will all serve the file over HTTPS with zero maintenance.
How do I add free HTTPS to my own server?
Use Let's Encrypt with Certbot, which issues a free certificate and sets up auto-renewal in a few commands. On Ubuntu with Nginx you install certbot, run "certbot --nginx -d yourdomain", then confirm renewal works with "certbot renew --dry-run".
What ports should be open on a single-image server?
Only 443 for HTTPS, 80 to redirect to HTTPS, and 22 for SSH — nothing else. Close everything else with a firewall like UFW, and lock SSH to key-only login to cut down on scanner traffic.
How do I stop people hotlinking my image from object storage?
Front the public bucket with Cloudflare and add a hotlink-protection rule that checks the Referer header, or set a monthly egress cap so a traffic spike can't run up a surprise bill. On metered plans like Backblaze B2 this matters, since you pay for egress past the free daily allowance.

