I have been checking plenty of websites, and many questions/answer here in ServerFault about this issue. However, I don't seem to be getting into the root of the configuration error.

I have 4 domains in my nginx server:

  • example.com
  • www.example.com
  • api.example.com
  • blog.example.com

They are all up and running, both in ports 80 and 443. This is the template nginx.conf I used for all of them, changing only the server_name, root, error_log and access_log directives. There are some other changes, but in principle shouldn't affect. Like different fastcgi_param.

This is the template for example.com and www.example.com:

server {
listen 80;

server_name example.com www.example.com;
root /var/www/example.com/public_html/web;

if ($http_host = example.com) {
    return 301 https://www.example.com$request_uri;
}

location / {
    # try to serve file directly, fallback to front controller
    try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
    fastcgi_pass   unix:/var/run/php/php7.0-fpm.sock;

    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param HTTPS off;
    fastcgi_param   DATABASE_NAME           some_database;
    fastcgi_param   DATABASE_USER           some_user;
    fastcgi_param   DATABASE_PASSWORD       some_pwd;
}

#return 404 for all php files as we do have a front controller
location ~ \.php$ {
    return 404;
}

error_log /var/log/nginx/www.example.com_error.log;
access_log /var/log/nginx/www.example.com_access.log;

# Redirect non-https traffic to https
if ($scheme != "https") {
    return 301 https://$host$request_uri;
} # managed by Certbot


listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

And this is the exact error I get when I restart the server:

root@vps_server:/etc/nginx# journalctl -xe
Mar 09 09:17:16 vps_server systemd[1]: Starting A high performance web server and a reverse proxy server...
-- Subject: Unit nginx.service has begun start-up
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
-- 
-- Unit nginx.service has begun starting up.
Mar 09 09:17:16 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Mar 09 09:17:16 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Mar 09 09:17:16 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Mar 09 09:17:16 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Mar 09 09:17:17 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Mar 09 09:17:17 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Mar 09 09:17:17 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Mar 09 09:17:17 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Mar 09 09:17:18 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Mar 09 09:17:18 vps_server nginx[30764]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Mar 09 09:17:18 vps_server nginx[30764]: nginx: [emerg] still could not bind()
Mar 09 09:17:18 vps_server systemd[1]: nginx.service: Control process exited, code=exited status=1
Mar 09 09:17:18 vps_server systemd[1]: Failed to start A high performance web server and a reverse proxy server.
-- Subject: Unit nginx.service has failed
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
-- 
-- Unit nginx.service has failed.
-- 
-- The result is failed.
Mar 09 09:17:18 vps_server systemd[1]: nginx.service: Unit entered failed state.
Mar 09 09:17:18 vps_server systemd[1]: nginx.service: Failed with result 'exit-code'.

When I try to renew the certificates using sudo certbot renew --dry-run I obtain a similar error, although not exactly the same one.

If I kill the nginx threads, then I'm able to restart the server. But the next time I try to restart it, it throws the same error. And the worst thing is that I cannot manage to renew my SSL certificates (although that could be due to a different reason and I wouldn't like to put in here, since this could be the reason).

EDIT

I have set up a local machine using Vagrant with the exact same configuration, except that I commented the SSL certificates data. I can restart the server without issues. So perhaps it does have something to do with Certbot/SSL configuration.

To help with the debugging of this issue, here is the output of netstat -tulpn (only nginx is using ports 80 and 443, which is the expected output as I understand):

/var/log/nginx# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      16700/mysqld        
tcp        0      0 0.0.0.0:5355            0.0.0.0:*               LISTEN      1578/systemd-resolv 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      30608/nginx: master 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1675/sshd           
tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN      10001/master        
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      30608/nginx: master 
tcp6       0      0 :::5355                 :::*                    LISTEN      1578/systemd-resolv 
tcp6       0      0 :::22                   :::*                    LISTEN      1675/sshd           
tcp6       0      0 :::25                   :::*                    LISTEN      10001/master        
udp        0      0 127.0.0.53:53           0.0.0.0:*                           1578/systemd-resolv 
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1343/dhclient       
udp        0      0 0.0.0.0:5355            0.0.0.0:*                           1578/systemd-resolv 
udp6       0      0 :::5355                 :::*                                1578/systemd-resolv
up vote 1 down vote accepted
+50

What is your nginx.conf look like? I assume you have not changed the config, maybe just added the gzip and a new include folder to have separate location for the websites. For each of your doman / sub-domain have a separate config file. Like:

  • example.com & www.example.com
  • api.example.com
  • blog.example.com

This is because I assume these are separate websites under the same domain. If they are on the same website and they are just a so-called sub-page, then you would be better at creating just sub-pages with the location options.

To re-organise your nginx config I would create a com.example.conf file with 3 separate server sections. First is to redirect the non-www users to the www website:

server {
    listen       80;
    server_name  example.com;
    return       301 https://www.example.com$request_uri;
}

server {
    listen       443 ssl;
    server_name  example.com;
    return       301 https://www.example.com$request_uri;
}

The third section would contain the main site:

server {
    listen 443 ssl;

    server_name example.com www.example.com;

    root /var/www/example.com/public_html/web;

    index    index.php;

    error_log /var/log/nginx/www.example.com_error.log;
    access_log /var/log/nginx/www.example.com_access.log;

    location / {
        # try to serve file directly, fallback to front controller
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass   unix:/var/run/php/php7.0-fpm.sock;

        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
        fastcgi_param   DATABASE_NAME           some;
        fastcgi_param   DATABASE_USER           some_user;
        fastcgi_param   DATABASE_PASSWORD       some_pwd;
    }

    location ~ \.php$ {
        return 404;
    }
}

(I have to say, your fastcgi part in your index.php location looks weird to me, but I'll leave that to you)

Then create separate config files as com.example.api.conf and com.example.blog.conf. Add the first two sections from the previous config similarly as before, then you can just add yourself each sub-domain a different config for the locations.

For example I have this for my laravel websites:

rewrite ^/index\.php?(.*)$ /$1 permanent;

location / {
        try_files $uri @rewrite;
}

location        @rewrite {
        rewrite ^(.*)$ /index.php/$1 last;
}
location ~ ^/index.php(/|$) {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 299;
}

Hope this helps you, if not, comment your questions.

  • Thanks for answering @Bert, I really appreciated. I have just posted what seemed to be the solution. My nginx.conf looks as what you just described. There is the gzip improvement, and the include of sites_enabled/* so I can load the subdomains config files. About the server sections, what's really the benefit of having them that way? I don't expect the nginx.conf to change that much. – Carlos Alberto Martínez Gadea Mar 12 at 10:59
  • And by the way, yes, each subdomain (except the www/non-www, which are the same) are different websites, with even different programming languages behind. – Carlos Alberto Martínez Gadea Mar 12 at 11:08
  • The main thing you benefit is a more smooth nginx work (less workload is required / config / page) and better visibility if a 3rd person watches your config. Also use a separate config for the main site because nginx.conf is supposed to be used by everything. If anything happens and you have to add a new subdomain, this nginx config will be used. So make it as plain as you can. – Bert Mar 12 at 11:25
  • I should have explained myself really badly both in the question and in my previous comment. I am using different conf files for each subdomain. Except www.mydomain.me and mydomain.me, which I don't think I should split them. About the the clarity, it definitely adds more clarity. Have just changed it right now :) – Carlos Alberto Martínez Gadea Mar 12 at 11:37
  • 1
    Well, yes. Assuming you want only HTTPS on only www.mydomain.me, you'll need 1 server block for 80: mydomain.me and www.mydomain.me, another server block for 443 and mydomain.me, (these needs to be redirected with 301) and a third server block for 443 and www.mydomain.me. – Bert Mar 12 at 13:13

I have finally solved the issue. It seemed that IPV6 is enabled in the server, and it required the nginx config to be slightly different.

Instead of using this:

listen 80;
listen 443 ssl;

I had to use the following:

listen [::]:80;
listen [::]:443 ssl;

In this website I got a more accurate and detailed explanation: https://chrisjean.com/fix-nginx-emerg-bind-to-80-failed-98-address-already-in-use/

The curious thing is that my error was:

nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)

instead of the described (in the URL I provided):

nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

However this fixed the issue and I was able to restart the nginx server without any troubles.

The vagrant server that I had set up didn't have IPV6 enabled, so that might have something to do with the fact it didn't behave the same way.

  • Normally IPv6 is not used by NginX, unless you have it enabled. Or at least I haven't seen any sign of proof that my websites are served on IPv6 addresses as well. I'm glad you have solved it, but think about removing the if from the nginx config. nginx.com/resources/wiki/start/topics/depth/ifisevil/#examples – Bert Mar 12 at 11:13

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.