Posted on August 10, 2025
Category: Technology
Tags: Oracle Cloud, Ubuntu, SSH, Flask, web server security, user management
Views: 526
I recently explored setting up a secure compute instance in Oracle Cloud Infrastructure (OCI) using Ubuntu, focusing on user management and securing a Flask web service. With Grok 3's guidance, I got clear answers to my questions about the default ubuntu user, creating additional SSH-enabled users, and the risks of running a web server as ubuntu. Here's a conversational summary of what I learned, including how to run a Flask web service as the www-data user using a TCP port.
I started by asking, "When creating a computing instance in Oracle's Cloud infrastructure, is it usual to create a user who defaults to Ubuntu and has sudo privileges without a password when connecting to the server via SSH?" Grok 3 explained that this is standard for Ubuntu-based OCI instances. When you launch an Ubuntu instance, it creates a default ubuntu user configured for SSH access with a key pair you provide during setup. This user has passwordless sudo privileges, defined in /etc/sudoers with %ubuntu ALL=(ALL) NOPASSWD: ALL. SSH access uses keys, with password authentication disabled by default (PasswordAuthentication no in /etc/ssh/sshd_config). This setup is common across cloud providers like AWS and Azure, prioritizing security through SSH keys over passwords.
Next, I asked, "Can you let me know how to create an additional SSH-enabled user?" Grok 3 provided a detailed guide to create a new user, say newuser, with SSH key-based access and optional sudo privileges. Here's the process:
Log in as the ubuntu user via SSH:
ssh -i <your_private_key> ubuntu@<instance_public_ip>
This gets you into the instance to start configuring the new user.
Create the new user:
sudo adduser --disabled-password --gecos "" newuser
The --disabled-password flag ensures no password is set, and --gecos "" skips user info prompts.
Grant sudo privileges (if needed) by adding the user to the sudo group:
sudo usermod -aG sudo newuser
This allows the new user to run administrative commands.
For passwordless sudo, edit /etc/sudoers with sudo visudo and add:
newuser ALL=(ALL) NOPASSWD: ALL
This mirrors the default ubuntu user’s sudo setup.
Set up SSH key-based authentication:
Generate an SSH key pair on your local computer:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/newuser_key
This creates newuser_key (private key) and newuser_key.pub (public key). Press Enter to accept defaults or specify a passphrase for extra security.
- Copy the public key to the instance (e.g., using scp):
scp -i <your_private_key> ~/.ssh/newuser_key.pub ubuntu@<instance_public_ip>:/tmp
This transfers the public key to a temporary location on the instance.
- On the instance, set up the SSH directory and authorized_keys:
sudo mkdir -p /home/newuser/.ssh
sudo cp /tmp/newuser_key.pub /home/newuser/.ssh/authorized_keys
sudo rm /tmp/newuser_key.pub
These commands create the SSH directory, add the public key, and clean up. - Set correct permissions:
sudo chown -R newuser:newuser /home/newuser/.ssh
sudo chmod 700 /home/newuser/.ssh
sudo chmod 600 /home/newuser/.ssh/authorized_keys
Proper permissions ensure secure SSH access.
Test SSH access with the new user’s private key:
ssh -i ~/.ssh/newuser_key newuser@<instance_public_ip>
This verifies that the new user can log in securely.
Grok 3 also suggested locking the ubuntu user after setting up the new user for better security, which I found to be a solid recommendation.
ubuntu UserI then asked, "Does running a web server with the default user 'ubuntu' pose a significant security risk?" Grok 3 outlined the risks:
- The ubuntu user is a well-known default, making it a target for attackers.
- Its passwordless sudo privileges mean a compromised web server could lead to full system control.
- SSH access via the ubuntu user’s key pair increases the attack surface if keys are mismanaged.
The risk depends on the setup—public-facing servers with vulnerabilities are more exposed—but using ubuntu violates the principle of least privilege. Grok 3 recommended running the web server as a non-privileged user like www-data, especially for a Flask web service.
www-data User with a TCP PortTo address the security concerns, I explored how to run a Flask web service managed by the www-data user, using a TCP port (e.g., 127.0.0.1:8000) for communication between Gunicorn and Nginx. Grok 3 provided the following steps:
Create a non-privileged user:
www-data (often pre-installed on Ubuntu):sudo adduser --system --group --no-create-home www-data
This user is designed for running web services without a home directory or login shell.
Set up the Flask application:
Create a directory for the Flask app:
sudo mkdir -p /var/www/flask_app
sudo chown www-data:www-data /var/www/flask_app
sudo chmod 750 /var/www/flask_app
This sets up a secure directory for the application.
- Place your Flask app (e.g., app.py) in /var/www/flask_app:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
This is a basic Flask app for testing.
Install and configure Gunicorn:
Install Gunicorn and Flask:
sudo apt update
sudo apt install python3-pip
sudo -u www-dat bash
cd /var/www/flask_app
python3 -m venv
source venv/bin/activate
pip3 install Flask gunicorn
Gunicorn will serve the Flask app.
- Run Gunicorn as www-data, binding to a TCP port:
/var/www/flask_app/venv/bin/gunicorn --bind 127.0.0.1:8000 -w 4 app:app -D --chdir /var/www/flask_app
The TCP port ensures local communication between Gunicorn and Nginx.
Configure Nginx as a reverse proxy:
Install Nginx:
sudo apt install nginx
Nginx will handle incoming HTTP requests.
- Configure Nginx to run as www-data by editing /etc/nginx/nginx.conf:
user www-data;
This ensures Nginx runs with minimal privileges.
- Create a site configuration in /etc/nginx/sites-available/flask_app:
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
This proxies requests to the Gunicorn port. - Enable the site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
This activates the configuration and restarts Nginx.
Set up Systemd for Gunicorn:
Create a systemd service file at /etc/systemd/system/flask_app.service:
[Unit]
Description=Gunicorn instance for Flask app
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flask_app
Environment="PATH=/var/www/flask_app/venv/bin"
UMask=027
ExecStart=/var/www/flask_app/venv/bin/gunicorn --bind 127.0.0.1:8000 -w 4 app:app
Restart=always
[Install]
WantedBy=multi-user.target
This ensures Gunicorn runs persistently. - Enable and start the service:
sudo systemctl enable flask_app
sudo systemctl start flask_app
This integrates Gunicorn with system startup.
Secure file permissions:
Ensure the Flask app directory is owned by www-data:
sudo chown -R www-data:www-data /var/www/flask_app
sudo chmod -R 750 /var/www/flask_app
This restricts access to the www-data user and group.
Harden the setup:
Configure a firewall (e.g., ufw) to allow only HTTP/HTTPS traffic:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
This limits network exposure. - Lock down SSH by ensuring key-based authentication and restricting access to specific IPs if possible.
SSH hardening reduces the risk of unauthorized access.
This conversation clarified how to manage users and secure a Flask web service in OCI Ubuntu instances. The default ubuntu user is convenient but risky for web services due to its sudo privileges and SSH access. Creating a dedicated www-data user for Flask (via Gunicorn and Nginx) with a TCP port and setting proper permissions ensures a secure setup. Additional measures like firewall rules and SSH hardening make the system robust for production use.
Disclaimer: This blog post was created with assistance from Grok 3, an AI developed by xAI, under my direct supervision and guidance to ensure accuracy and alignment with my vision for the content.